diff --git a/.gitignore b/.gitignore index 40f20e32..1b6985c0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,166 +1,5 @@ -################# -## Eclipse -################# +# Ignore Gradle project-specific cache directory +.gradle -*.pydevproject -.project -.metadata -bin/ -tmp/ -*.tmp -*.bak -*.swp -*~.nib -local.properties -.classpath -.settings/ -.loadpath - -# External tool builders -.externalToolBuilders/ - -# Locally stored "Eclipse launch configurations" -*.launch - -# CDT-specific -.cproject - -# PDT-specific -.buildpath - - -################# -## Visual Studio -################# - -## Ignore Visual Studio temporary files, build results, and -## files generated by popular Visual Studio add-ons. - -# User-specific files -*.suo -*.user -*.sln.docstates - -# Build results -[Dd]ebug/ -[Rr]elease/ -*_i.c -*_p.c -*.ilk -*.meta -*.obj -*.pch -*.pdb -*.pgc -*.pgd -*.rsp -*.sbr -*.tlb -*.tli -*.tlh -*.tmp -*.vspscc -.builds -*.dotCover - -## TODO: If you have NuGet Package Restore enabled, uncomment this -#packages/ - -# Visual C++ cache files -ipch/ -*.aps -*.ncb -*.opensdf -*.sdf - -# Visual Studio profiler -*.psess -*.vsp - -# ReSharper is a .NET coding add-in -_ReSharper* - -# Installshield output folder -[Ee]xpress - -# DocProject is a documentation generator add-in -DocProject/buildhelp/ -DocProject/Help/*.HxT -DocProject/Help/*.HxC -DocProject/Help/*.hhc -DocProject/Help/*.hhk -DocProject/Help/*.hhp -DocProject/Help/Html2 -DocProject/Help/html - -# Click-Once directory -publish - -# Others -[Bb]in -[Oo]bj -sql -TestResults -*.Cache -ClientBin -stylecop.* -~$* -*.dbmdl -Generated_Code #added for RIA/Silverlight projects - -# Backup & report files from converting an old project file to a newer -# Visual Studio version. Backup files are not needed, because we have git ;-) -_UpgradeReport_Files/ -Backup*/ -UpgradeLog*.XML - - - -############ -## Windows -############ - -# Windows image file caches -Thumbs.db - -# Folder config file -Desktop.ini - - -############# -## Python -############# - -*.py[co] - -# Packages -*.egg -*.egg-info -dist +# Ignore Gradle build output directory build -eggs -parts -bin -var -sdist -develop-eggs -.installed.cfg - -# Installer logs -pip-log.txt - -# Unit test / coverage reports -.coverage -.tox - -#Translations -*.mo - -#Mr Developer -.mr.developer.cfg - -# Mac crap -.DS_Store - -# svn -.svn* \ No newline at end of file diff --git a/3rd-party-jars/JoSQL-2.2.jar b/3rd-party-jars/JoSQL-2.2.jar deleted file mode 100644 index 08fcd6f5..00000000 Binary files a/3rd-party-jars/JoSQL-2.2.jar and /dev/null differ diff --git a/3rd-party-jars/gentlyWEB-properties-1.2.jar b/3rd-party-jars/gentlyWEB-properties-1.2.jar deleted file mode 100644 index 931b8d1f..00000000 Binary files a/3rd-party-jars/gentlyWEB-properties-1.2.jar and /dev/null differ diff --git a/3rd-party-jars/gentlyweb-properties-3.jar b/3rd-party-jars/gentlyweb-properties-3.jar new file mode 100644 index 00000000..65b21295 Binary files /dev/null and b/3rd-party-jars/gentlyweb-properties-3.jar differ diff --git a/3rd-party-jars/josql-2.3.jar b/3rd-party-jars/josql-2.3.jar new file mode 100644 index 00000000..416c8714 Binary files /dev/null and b/3rd-party-jars/josql-2.3.jar differ diff --git a/build.gradle b/build.gradle new file mode 100644 index 00000000..811c7454 --- /dev/null +++ b/build.gradle @@ -0,0 +1,265 @@ +/* + * This file was generated by the Gradle 'init' task. + * + * This generated file contains a sample Java project to get you started. + * For more details take a look at the Java Quickstart chapter in the Gradle + * User Manual available at https://docs.gradle.org/5.2.1/userguide/tutorial_java_projects.html + */ + +plugins { + // Apply the java plugin to add support for Java + id 'java' + + // Apply the application plugin to add support for building an application + id 'application' + + //id 'org.openjfx.javafxplugin' version '0.0.9' +} + +version '3.0.1' +//version '3.0.0' + +sourceSets { + main { + } +} +/* +javafx { + version = '12' + modules = [ 'javafx.swing', 'javafx.controls', 'javafx.media', 'javafx.web' ] + configuration = 'compileOnly' +} +*/ +repositories { + // Use jcenter for resolving your dependencies. + // You can declare any Maven/Ivy/file repository here. + //jcenter() + mavenCentral() + + // Needed for the EPUB lib artifact. +/* + maven { + url 'http://maven.openkm.com/' + } +*/ + + maven { + //id 'psiegman-repo' + url 'https://github.com/psiegman/mvn-repo/raw/master/releases' + } + + maven { + url 'https://oss.sonatype.org/content/repositories/snapshots/' + } + +} + +dependencies { + + implementation fileTree('3rd-party-jars') { + //include 'jdom-1.0.jar' + //include 'jgoodies-forms-1.8.0.jar' + //include 'JoSQL-2.2.jar' + include 'josql-2.3.jar' + //include 'gentlyWEB-utils-1.1.jar' + //include 'gentlyWEB-xml-1.1.jar' + //include 'gentlyWEB-properties-1.2.jar' + //include 'gentlyWEB-logging-1.0.jar' + include 'gentlyweb-properties-3.jar' + include 'javadiff.jar' + + // Spellchecker + include 'suggester-1.1.2.jar' + + // TODO Investigate using maven? + include 'jazzy-core.jar' + + include 'suggester-1.1.2.jar' + include 'GWordCram-0.1.jar' + + // TODO Remove when no longer using Swing/AWT + include 'jcalendar-1.4.jar' + + include 'h2mig_pagestore_addon.jar' + + } + + //compile 'org.jsoup:jsoup:1.11.3' + implementation 'org.jsoup:jsoup:1.11.3' + + // Use JUnit test framework + testImplementation 'junit:junit:4.12' + + // XML Parser + implementation 'pull-parser:pull-parser:2.1.10' + + // Docx4J + implementation 'org.docx4j:docx4j-JAXB-ReferenceImpl:11.1.8' + + // Bouncy castle crypto + implementation 'org.bouncycastle:bcprov-jdk15on:1.62' + implementation 'org.bouncycastle:bcpg-jdk15on:1.62' + + // TODO This is probably not needed now since we can scale images via JavaFX. + implementation 'org.imgscalr:imgscalr-lib:4.2' + + // DBCP implementation (Apache) + implementation 'org.apache.commons:commons-dbcp2:2.6.0' + + // Apache Commons IO + implementation 'commons-io:commons-io:2.11.0' + + // H2 DB + implementation 'com.h2database:h2:1.3.175' + + // EPUB lib + implementation 'nl.siegmann.epublib:epublib-core:3.1' + + // POI hwpf (.doc file reading) + //implementation 'org.apache.poi:poi-scratchpad:4.1.0' + + // JFreeChart + implementation 'org.jfree:jfreechart:1.5.0' + + // JFreeChart-FX + implementation 'org.jfree:jfreechart-fx:1.0.1' + + // Smack + implementation 'org.igniterealtime.smack:smack-core:4.4.4' + implementation 'org.igniterealtime.smack:smack-extensions:4.4.4' + implementation 'org.igniterealtime.smack:smack-tcp:4.4.4' + implementation 'org.igniterealtime.smack:smack-im:4.4.4' + implementation 'org.igniterealtime.smack:smack-java8:4.4.4' + + // RichtextFX + implementation 'org.fxmisc.richtext:richtextfx:0.11.0' + //implementation 'org.fxmisc.richtext:richtextfx:0.10.9' + //implementation 'org.fxmisc.richtext:richtextfx:1.0.0-SNAPSHOT' + + // This is temporary for testing changes to a local version of richtextfx. Ignore. + // TEMP ADD RICHTEXTFX JARS AND DEPS +/* + implementation fileTree('d:/reference/java/afester-richtextfx/RichTextFX/richtextfx/build/libs/') { + //include 'richtextfx-1.0.0-SNAPSHOT.jar' + include 'richtextfx-0.10.8-rc1.jar' + include 'flowless-0.6.7.jar' + include 'reactfx-2.0-M5.jar' + include 'undofx-2.1.1.jar' + include 'wellbehavedfx-0.3.3.jar' + } +*/ + // Flying Saucer (can be removed when no longer using Swing) + implementation 'org.xhtmlrenderer:flying-saucer-core:9.1.18' + + // JGoodies (remove when no longer using Swing) + implementation 'com.jgoodies:jgoodies-looks:2.7.0' + implementation 'com.jgoodies:jgoodies-forms:1.9.0' + + // AnimateFX (test) + //implementation 'io.github.typhon0:AnimateFX:1.2.1' + + // SVG support + //implementation 'de.codecentric.centerdevice:javafxsvg:1.3.0' + + // PDF support + //implementation 'org.apache.pdfbox:pdfbox:2.0.20' + + // DOM4J + implementation 'org.dom4j:dom4j:2.1.3' + +} + +compileJava { + + options.incremental = true + + options.compilerArgs = + [ + '--add-modules', + 'java.base,javafx.swing,javafx.controls,javafx.media,javafx.web,java.instrument,jdk.attach', + '--add-exports', + 'javafx.graphics/com.sun.javafx.iio=ALL-UNNAMED', + '--add-exports', + 'javafx.graphics/com.sun.javafx.iio.common=ALL-UNNAMED', + '--add-exports', + 'javafx.web/com.sun.javafx.webkit=ALL-UNNAMED', + '--add-exports', + 'javafx.web/com.sun.webkit=ALL-UNNAMED', + '--module-path', + // This is a property that should be defined (usually) in gradle.prpoerties, i.e. module_path=/usr/share/lib/javafx-sdk-12/lib + module_path, + '-Xmaxerrs', + '1000' + ] +} + +jar { + doFirst { + file("${sourceSets.main.output.resourcesDir}/data/version.txt").text = "$version" + } +} + +javadoc { + doFirst { + options.addStringOption ('-module-path', module_path) + options.addStringOption ('-add-modules', 'javafx.controls,javafx.swing,javafx.media,javafx.web,java.instrument,jdk.attach') + } +} + +application { + applicationDefaultJvmArgs = + [ + '-Djava.locale.providers=COMPAT', + '--module-path', + // This is a property that should be defined (usually) in gradle.prpoerties, i.e. module_path=/usr/share/lib/javafx-sdk-12/lib + module_path, + '--add-modules=javafx.controls,javafx.swing,javafx.media,javafx.web,java.instrument,jdk.attach', + '--add-exports', + 'javafx.graphics/com.sun.javafx.iio=ALL-UNNAMED', + '--add-exports', + 'javafx.graphics/com.sun.javafx.iio.common=ALL-UNNAMED', + '--add-exports', + 'javafx.graphics/com.sun.javafx.scene.text=ALL-UNNAMED', + '--add-exports', + 'javafx.graphics/com.sun.javafx.geom=ALL-UNNAMED', + '--add-opens', + 'javafx.graphics/javafx.scene.text=ALL-UNNAMED', + '--add-opens', + 'javafx.graphics/com.sun.javafx.text=ALL-UNNAMED', + '--add-exports', + 'javafx.graphics/com.sun.javafx.geom=ALL-UNNAMED', + '--add-exports', + 'javafx.graphics/com.sun.javafx.scene.text=ALL-UNNAMED', + '--add-exports', + 'javafx.graphics/com.sun.javafx.tk=ALL-UNNAMED', + '--add-exports', + 'javafx.web/com.sun.javafx.webkit=ALL-UNNAMED', + '--add-exports', + 'javafx.web/com.sun.webkit=ALL-UNNAMED' + ] + + // Define the main class for the application + mainClassName 'com.quollwriter.Startup' + +} + +run { + dependsOn jar +} + +task copyToLib(type: Copy) { + delete "$buildDir/libs" + into "$buildDir/libs" + from configurations.runtimeClasspath +} + +configurations.all { + resolutionStrategy { + //failOnVersionConflict() + // This is to try and fix some of the dependency conflicts between siegmann and dom4j. + force 'commons-codec:commons-codec:1.15', + 'commons-io:commons-io:2.11.0', + 'org.slf4j:slf4j-api:1.8.0-beta4', + 'pull-parser:pull-parser:2.1.10' + } +} diff --git a/build.xml b/build.xml deleted file mode 100644 index 44359b6a..00000000 --- a/build.xml +++ /dev/null @@ -1,581 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ${currVersion} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
-
-
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
-
-
- -
- - - - - - - - - - - -
- - - - -
-
-
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - -
-
-
- -
- - - - - - - - - - -
- - - -
-
-
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - -
-
-
- -
- -
diff --git a/data/project-info-schema-version.txt b/data/project-info-schema-version.txt deleted file mode 100644 index e440e5c8..00000000 --- a/data/project-info-schema-version.txt +++ /dev/null @@ -1 +0,0 @@ -3 \ No newline at end of file diff --git a/data/prompts/5148672f441b.txt b/data/prompts/5148672f441b.txt deleted file mode 100644 index ae081571..00000000 --- a/data/prompts/5148672f441b.txt +++ /dev/null @@ -1 +0,0 @@ -Louisa M. AlcottA Garland for Girlshttp://www.gutenberg.org/dirs/etext04/grlnd11.txtMuch is not expected of a girl of eighteen, I know; but oh! there were heaps of kind little things I MIGHT have done if I hadn't thought only of myself. \ No newline at end of file diff --git a/data/prompts/e4671c821dcc.txt b/data/prompts/e4671c821dcc.txt deleted file mode 100644 index b969abe9..00000000 --- a/data/prompts/e4671c821dcc.txt +++ /dev/null @@ -1 +0,0 @@ -L. Frank BaumDorothy and the Wizard of Ozhttp://www.gutenberg.org/files/420/420-h/420-h.htmThe buggy seemed almost new, for it had a shiny top and side curtains. Getting around in front, so that she could look inside, the girl saw a boy curled up on the seat, fast asleep. \ No newline at end of file diff --git a/data/version.txt b/data/version.txt deleted file mode 100644 index d5724cd4..00000000 --- a/data/version.txt +++ /dev/null @@ -1 +0,0 @@ -2.6.2 \ No newline at end of file diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 00000000..9634be09 --- /dev/null +++ b/settings.gradle @@ -0,0 +1,10 @@ +/* + * This file was generated by the Gradle 'init' task. + * + * The settings file is used to specify which projects to include in your build. + * + * Detailed information about configuring a multi-project build in Gradle can be found + * in the user manual at https://docs.gradle.org/5.2.1/userguide/multi_project_builds.html + */ + +rootProject.name = 'QuollWriter' diff --git a/src/com/quollwriter/ByteArrayDataSource.java b/src/com/quollwriter/ByteArrayDataSource.java deleted file mode 100644 index 57d4a643..00000000 --- a/src/com/quollwriter/ByteArrayDataSource.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.quollwriter; - -import java.io.*; - -import javax.activation.*; - -public class ByteArrayDataSource implements DataSource -{ - - private byte[] bytes = null; - - public ByteArrayDataSource (byte[] bytes) - { - - this.bytes = bytes; - - } - - public InputStream getInputStream () - throws IOException - { - - return new ByteArrayInputStream (this.bytes); - - } - - public OutputStream getOutputStream () - throws IOException - { - - throw new UnsupportedOperationException ("Write is not supported."); - - } - - public String getName () - { - - return null; - - } - - public String getContentType () - { - - return "application/octet-stream"; - - } - -} \ No newline at end of file diff --git a/src/com/quollwriter/DictionaryProvider.java b/src/com/quollwriter/DictionaryProvider.java deleted file mode 100644 index f8a88f7e..00000000 --- a/src/com/quollwriter/DictionaryProvider.java +++ /dev/null @@ -1,556 +0,0 @@ -package com.quollwriter; - -import java.io.*; - -import java.util.*; - -import com.quollwriter.ui.events.*; - -import com.quollwriter.ui.components.*; -import com.quollwriter.text.*; - -import com.softcorporation.suggester.util.Constants; -import com.softcorporation.suggester.util.SpellCheckConfiguration; -import com.softcorporation.suggester.Suggestion; -import com.softcorporation.suggester.dictionary.BasicDictionary; -import com.softcorporation.suggester.BasicSuggester; - -public class DictionaryProvider -{ - - private List listeners = new ArrayList (); - //private List dicts = new ArrayList (); - private QWSpellDictionaryHashMap projDict = null; - private SpellChecker checker = null; - private com.swabunga.spell.event.SpellChecker projectSpellChecker = null; - - private static File userDictFile = null; - private static QWSpellDictionaryHashMap userDict = null; - private static com.swabunga.spell.event.SpellChecker userSpellChecker = null; - private String language = null; - - public DictionaryProvider (String lang, - List projWords) - throws Exception - { - - this.language = lang; - - File dictFile = Environment.getDictionaryFile (lang); - - if (!dictFile.exists ()) - { - - throw new GeneralException ("Unable to find dictionary file: " + - dictFile); - - } - - BasicDictionary dict = new BasicDictionary ("file://" + dictFile.getPath ()); - - SpellCheckConfiguration config = new SpellCheckConfiguration ("/com/softcorporation/suggester/spellCheck.config"); - - final BasicSuggester suggester = new BasicSuggester (config); - suggester.attach (dict); - - final DictionaryProvider _this = this; - - this.checker = new SpellChecker () - { - - public synchronized boolean isCorrect (Word word) - { - - if (word.isPunctuation ()) - { - - return true; - - } - - String w = word.getText (); - - // See if the word is a number. - try - { - - Double.parseDouble (w); - - return true; - - } catch (Exception e) { - - // Not a number. - - } - - if (this.isIgnored (word)) - { - - return true; - - } - - try - { - - if (_this.projectSpellChecker.isCorrect (w)) - { - - return true; - - } - - if (DictionaryProvider.userSpellChecker.isCorrect (w)) - { - - return true; - - } - - if (suggester.hasExactWord (w)) - { - - return true; - - } - - int result = suggester.hasWord (w); - if (result == Constants.RESULT_ID_MATCH || - result == Constants.RESULT_ID_MATCH_EXACT) - { - return true; - } - - }catch (Exception e) { - - Environment.logError ("Unable to check word: " + - word, - e); - - } - - return false; - - } - - public synchronized boolean isIgnored (Word word) - { - - return false; - - } - - public synchronized List getSuggestions (Word word) - { - - List ret = new ArrayList (); - - if (word == null) - { - - return null; - - } - - if (this.isCorrect (word)) - { - - return null; - - } - - String wt = word.getText (); - - List suggestions = null; - - List jsuggestions = _this.projectSpellChecker.getSuggestions (wt, - 1); - - if (jsuggestions != null) - { - - for (int i = 0; i < jsuggestions.size (); i++) - { - - ret.add (((com.swabunga.spell.engine.Word) jsuggestions.get (i)).getWord ()); - - } - - } - - jsuggestions = DictionaryProvider.userSpellChecker.getSuggestions (wt, - 1); - - if (jsuggestions != null) - { - - for (int i = 0; i < jsuggestions.size (); i++) - { - - ret.add (((com.swabunga.spell.engine.Word) jsuggestions.get (i)).getWord ()); - - } - - } - - try - { - - suggestions = suggester.getSuggestions (wt, 20); - - } catch (Exception e) { - - e.printStackTrace (); - - } - - if (suggestions != null) - { - - for (int i = 0; i < suggestions.size (); i++) - { - - Suggestion s = (Suggestion) suggestions.get (i); - - ret.add (s.word); - - } - - } - - if (Character.isUpperCase (wt.charAt (0))) - { - - for (int i = 0; i < ret.size (); i++) - { - - String w = ret.get (i); - - ret.set (i, - Character.toUpperCase (w.charAt (0)) + w.substring (1)); - - } - - } - - return ret; - - } - - }; - - this.projectSpellChecker = new com.swabunga.spell.event.SpellChecker (); - - if (projWords != null) - { - - StringBuilder b = new StringBuilder (); - - for (String i : projWords) - { - - b.append (i); - b.append ('\n'); - - } - - this.projDict = new QWSpellDictionaryHashMap (new StringReader (b.toString ())); - - this.projectSpellChecker.addDictionary (this.projDict); - - //this.dicts.add (this.projDict); - - } - - if (DictionaryProvider.userDict == null) - { - - File userDictFile = Environment.getUserDictionaryFile (); - - if (!userDictFile.exists ()) - { - - userDictFile.createNewFile (); - - } - - DictionaryProvider.userDict = new QWSpellDictionaryHashMap (userDictFile); - - DictionaryProvider.userDictFile = userDictFile; - - DictionaryProvider.userSpellChecker = new com.swabunga.spell.event.SpellChecker (); - - DictionaryProvider.userSpellChecker.setUserDictionary (DictionaryProvider.userDict); - - } - - } - - public String getLanguage () - { - - return this.language; - - } - - public static boolean isLanguageInstalled (String lang) - { - - File f = Environment.getDictionaryFile (lang); - - if ((f != null) - && - (f.exists ()) - ) - { - - return true; - - } - - return false; - - } - - /** - * Checks to see if the directory is an indexed dictionary directory which means: - * - It contains a db directory - * - It contains a words directory - * - It contains a contents file - * - * @param dir The directory to check. - * @return If the checks pass. - */ - private boolean isIndexedDictionaryDirectory (File dir) - { - - if (!dir.exists ()) - { - - return false; - - } - - File dbDir = new File (dir, "db"); - - if ((!dbDir.exists ()) - || - (dbDir.isFile ()) - ) - { - - return false; - - } - - File wordsDir = new File (dir, "words"); - - if ((!wordsDir.exists ()) - || - (wordsDir.isFile ()) - ) - { - - return false; - - } - - return true; - - } - - public void addDictionaryChangedListener (DictionaryChangedListener l) - { - - if (this.listeners.contains (l)) - { - - return; - - } - - this.listeners.add (l); - - } - - public void removeDictionaryChangedListener (DictionaryChangedListener l) - { - - this.listeners.remove (l); - - } - - protected void fireDictionaryEvent (DictionaryChangedEvent ev) - { - - for (int i = 0; i < this.listeners.size (); i++) - { - - DictionaryChangedListener dcl = (DictionaryChangedListener) this.listeners.get (i); - - dcl.dictionaryChanged (ev); - - } - - } - - public SpellChecker getSpellChecker () - { - - return this.checker; - - } - - public static void addUserWord (String word) - { - - if (!DictionaryProvider.userDict.isCorrect (word)) - { - - DictionaryProvider.userDict.addWord (word); -/* - this.fireDictionaryEvent (new DictionaryChangedEvent (this, - DictionaryChangedEvent.WORD_ADDED, - word)); -*/ - } - - } - - public static void removeUserWord (String word) - { - - if (DictionaryProvider.userDict != null) - { - - DictionaryProvider.userDict.removeWord (word); - - try - { - - DictionaryProvider.userDict.saveDictionaryToFile (DictionaryProvider.userDictFile); - - } catch (Exception e) - { - - Environment.logError ("Unable to save user dictionary file", - e); - - } - - /* - this.fireDictionaryEvent (new DictionaryChangedEvent (this, - DictionaryChangedEvent.WORD_REMOVED, - word)); -*/ - } - - } - - public void removeWord (String word, - String type) - { - - if (type.equals ("project")) - { - - if (this.projDict != null) - { - - this.projDict.removeWord (word); - - this.fireDictionaryEvent (new DictionaryChangedEvent (this, - DictionaryChangedEvent.WORD_REMOVED, - word)); - - } - - } - - if (type.equals ("user")) - { - - if (DictionaryProvider.userDict != null) - { - - DictionaryProvider.userDict.removeWord (word); - - try - { - - DictionaryProvider.userDict.saveDictionaryToFile (DictionaryProvider.userDictFile); - - } catch (Exception e) - { - - Environment.logError ("Unable to save user dictionary file", - e); - - } - - this.fireDictionaryEvent (new DictionaryChangedEvent (this, - DictionaryChangedEvent.WORD_REMOVED, - word)); - - } - - } - - } - - public void addWord (String word, - String type) - { - - if (type.equals ("project")) - { - - if (this.projDict == null) - { - - try - { - - this.projDict = new QWSpellDictionaryHashMap (new StringReader ("")); - - } catch (Exception e) - { - - Environment.logError ("Unable to create project dictionary for word: " + - word, - e); - - return; - - } - - } - - this.projDict.addWord (word); - - this.fireDictionaryEvent (new DictionaryChangedEvent (this, - DictionaryChangedEvent.WORD_ADDED, - word)); - - } - - if (type.equals ("user")) - { - - if (!DictionaryProvider.userDict.isCorrect (word)) - { - - DictionaryProvider.userDict.addWord (word); - - this.fireDictionaryEvent (new DictionaryChangedEvent (this, - DictionaryChangedEvent.WORD_ADDED, - word)); - - } - - } - - } - -} diff --git a/src/com/quollwriter/Environment.java b/src/com/quollwriter/Environment.java deleted file mode 100644 index 2396748e..00000000 --- a/src/com/quollwriter/Environment.java +++ /dev/null @@ -1,8211 +0,0 @@ -package com.quollwriter; - -import java.awt.Color; -import java.awt.Component; -import java.awt.Dimension; -import java.awt.Image; -import java.awt.Insets; -import java.awt.Font; -import java.awt.KeyboardFocusManager; -import java.awt.image.*; -import java.awt.event.*; - -import java.nio.channels.*; - -import java.beans.*; - -import java.io.*; -import java.nio.charset.*; - -import java.net.*; - -import java.security.*; - -import java.text.*; - -import java.util.*; -import java.util.jar.*; -import java.util.logging.*; -import java.util.prefs.*; -import java.util.concurrent.*; - -import javax.swing.*; -import javax.swing.border.*; -import javax.swing.plaf.*; - -import javax.imageio.*; - -import javax.sound.sampled.*; - -import com.gentlyweb.logging.Logger; - -import com.gentlyweb.properties.*; - -import com.gentlyweb.utils.*; - -import com.gentlyweb.xml.*; - -import com.jgoodies.looks.*; -import com.jgoodies.looks.windows.*; - -import com.quollwriter.data.*; -import com.quollwriter.editors.*; -import com.quollwriter.data.editors.*; -import com.quollwriter.data.comparators.*; - -import com.quollwriter.text.*; - -import com.quollwriter.events.*; - -import com.quollwriter.importer.*; - -import com.quollwriter.synonyms.*; - -import com.quollwriter.text.rules.*; - -import com.quollwriter.db.*; - -import com.quollwriter.ui.*; -import com.quollwriter.ui.components.ActionAdapter; -import com.quollwriter.ui.components.GradientPanel; -import com.quollwriter.ui.components.Header; -import com.quollwriter.ui.components.IconProvider; -import com.quollwriter.ui.components.Runner; - -import com.quollwriter.achievements.*; -import com.quollwriter.achievements.rules.*; - -import com.quollwriter.editors.ui.*; - -import static com.quollwriter.LanguageStrings.*; - -import org.jdom.*; - -public class Environment -{ - - public static String GZIP_EXTENSION = ".gz"; - - private static Landing landingViewer = null; - private static Map openProjects = new HashMap<> (); - private static Set openViewers = new HashSet<> (); - - public static Map defaultObjectProperties = new HashMap (); - - //public static com.gentlyweb.properties.Properties userProperties = new com.gentlyweb.properties.Properties (); - public static PrintStream out = null; - - private static Logger generalLog = null; - private static Logger errorLog = null; - private static Logger sqlLog = null; - - // Get rid of this value once bug reporting is via the web. - public static boolean seenReportBugMessage = false; - - private static Version appVersion = null; - //private static String appVersion = null; - //private static boolean betaVersion = false; - private static int schemaVersion = 0; - private static int projectInfoSchemaVersion = 0; - - private static SimpleDateFormat dateFormatter = null; - private static SimpleDateFormat timeFormatter = null; - - private static boolean debugMode = false; - private static boolean doneVersionCheck = false; - public static boolean isWindows = false; - public static boolean isMac = false; - public static boolean isLinux = false; - private static boolean isFirstUse = false; - - private static List installJarFilesToDelete = new ArrayList (); - - private static Map userPropertyHandlers = new HashMap (); - - private static DecimalFormat numFormat = new DecimalFormat ("###,###"); - private static DecimalFormat floatNumFormat = new DecimalFormat ("###,###.#"); - - private static Map backgroundImages = new HashMap (); - - private static AchievementsManager achievementsManager = null; - - private static Map objectTypeNamesSingular = new HashMap (); - private static Map objectTypeNamesPlural = new HashMap (); - - private static Map synonymProviders = new WeakHashMap (); - //private static DictionaryProvider defaultDictProv = null; - - private static List startupProgressListeners = new ArrayList (); - private static int startupProgress = 0; - - private static FileLock lock = null; - - private static ProjectInfoObjectManager projectInfoManager = null; - - private static Map projectInfoChangedListeners = null; - - private static Map userProjectEventListeners = null; - - // Just used in the maps above as a placeholder for the listeners. - private static final Object listenerFillObj = new Object (); - - private static boolean playSoundOnKeyStroke = false; - private static Clip keyStrokeSound = null; - - private static UserSession userSession = null; - private static TargetsData targets = null; - - private static ScheduledThreadPoolExecutor generalTimer = null; - - private static ProjectTextProperties projectTextProps = null; - private static FullScreenTextProperties fullScreenTextProps = null; - - private static List doOnShutdown = new ArrayList (); - - private static Set userConfigObjTypes = new HashSet (); - - private static PropertyChangedListener userConfigurableObjectTypeNameListener = null; - - private static Set tags = null; - - private static LanguageStrings uiLanguageStrings = null; - private static LanguageStrings defaultUILanguageStrings = null; - - static - { - - // We use a synchronized weak hash map here so that we don't have to worry about all the - // references since they will be transient compared to the potential length of the service - // running. - - // Where possible listeners should de-register as normal but this just ensure that objects - // that don't have a controlled pre-defined lifecycle (as opposed say to AbstractSideBar) - // won't leak. - Environment.projectInfoChangedListeners = Collections.synchronizedMap (new WeakHashMap ()); - - Environment.userProjectEventListeners = Collections.synchronizedMap (new WeakHashMap ()); - - try - { - - // Put a wrapper around System.out to ensure that non ascii characters show up correctly when debugging. - Environment.out = new java.io.PrintStream (System.out, true, "utf-8"); - - } catch (Exception e) { - - Environment.out = System.out; - - } - - } - - public class XMLConstants - { - - public static final String projects = "projects"; - public static final String type = "type"; - public static final String name = "name"; - public static final String object = "object"; - public static final String singular = "singular"; - public static final String plural = "plural"; - public static final String file = "file"; - public static final String files = "files"; - public static final String stats = "stats"; - public static final String stat = "stat"; - public static final String id = "id"; - - } - - public static void fireProjectInfoChangedEvent (final ProjectInfo proj, - final String changeType) - { - - UIUtils.doActionLater (new ActionListener () - { - - public void actionPerformed (ActionEvent aev) - { - - ProjectInfoChangedEvent ev = new ProjectInfoChangedEvent (proj, - changeType); - - Set ls = null; - - // Get a copy of the current valid listeners. - synchronized (Environment.projectInfoChangedListeners) - { - - ls = new LinkedHashSet (Environment.projectInfoChangedListeners.keySet ()); - - } - - for (ProjectInfoChangedListener l : ls) - { - - l.projectInfoChanged (ev); - - } - - } - - }); - - } - - public static void unregisterViewer (AbstractViewer v, - ActionListener afterUnregister) - { - - Environment.openViewers.remove (v); - - if (v == Environment.landingViewer) - { - - Environment.landingViewer = null; - - } - - if (afterUnregister != null) - { - - UIUtils.doLater (afterUnregister); - - return; - - } - - if (Environment.openViewers.size () == 0) - { - - Environment.closeDown (); - - } - - } - - public static void registerViewer (AbstractViewer v) - { - - Environment.openViewers.add (v); - - } - - public static void removeProjectInfoChangedListener (ProjectInfoChangedListener l) - { - - Environment.projectInfoChangedListeners.remove (l); - - } - - public static void addProjectInfoChangedListener (ProjectInfoChangedListener l) - { - - Environment.projectInfoChangedListeners.put (l, - Environment.listenerFillObj); - - } - - public static void addStartupProgressListener (PropertyChangedListener l) - { - - Environment.startupProgressListeners.add (l); - - } - - private static void fireStartupProgressEvent () - { - - PropertyChangedEvent ev = new PropertyChangedEvent (new Object (), - "progress", - 0, - Environment.startupProgress); - - for (PropertyChangedListener l : Environment.startupProgressListeners) - { - - l.propertyChanged (ev); - - } - - } - - public static void incrStartupProgress () - { - - if (Environment.isStartupComplete ()) - { - - return; - - } - - Environment.startupProgress += 9; - - Environment.fireStartupProgressEvent (); - - } - - public static void startupComplete () - { - - if (Environment.isStartupComplete ()) - { - - return; - - } - - Environment.startupProgress = 100; - - Environment.fireStartupProgressEvent (); - - } - - public static boolean isStartupComplete () - { - - return Environment.startupProgress == 100; - - } - - public static boolean isDistractionFreeModeEnabled () - { - - for (AbstractProjectViewer pv : Environment.openProjects.values ()) - { - - if (pv.isDistractionFreeModeEnabled ()) - { - - return true; - - } - - } - - return false; - - } - - public static AbstractViewer getFocusedViewer () - { - - if (Environment.landingViewer != null) - { - - if (Environment.landingViewer.isFocused ()) - { - - return Environment.landingViewer; - - } - - } - - if (Environment.openViewers.size () == 0) - { - - return null; - - } - - for (AbstractViewer viewer : Environment.openViewers) - { - - if (viewer.isFocused ()) - { - - return viewer; - - } - - } - - // Return the first viewer that is showing. - for (AbstractViewer viewer : Environment.openViewers) - { - - if (viewer.isShowing ()) - { - - return viewer; - - } - - } - - // What the derp... Return the first. - return Environment.openViewers.iterator ().next (); - - } - - public static String getUrlFileAsString (URL url) - throws Exception - { - - URLConnection c = url.openConnection (); - - InputStream bin = c.getInputStream (); - - return Utils.getStreamAsString (bin, - StandardCharsets.UTF_8); - - } - - public static AbstractProjectViewer getProjectViewer (ProjectInfo p) - { - - return Environment.openProjects.get (p); - - } - - public static AbstractProjectViewer getProjectViewer (Project p) - { - - return Environment.openProjects.get (Environment.getProjectInfo (p)); - - } - - public static void removeSideBarFromAllProjectViewers (String id) - { - - for (AbstractProjectViewer pv : Environment.openProjects.values ()) - { - - pv.removeSideBar (pv.getSideBar (id)); - - } - - } - - public static Book createTestBook () - throws Exception - { - - Element root = JDOMUtils.getStringAsElement (Environment.getResourceFileAsString (Constants.TEST_BOOK_FILE)); - - String name = JDOMUtils.getAttributeValue (root, - XMLConstants.name); - - Book b = new Book (); - - b.setName (name); - - List chEls = JDOMUtils.getChildElements (root, - Chapter.OBJECT_TYPE, - false); - - for (int i = 0; i < chEls.size (); i++) - { - - Element el = (Element) chEls.get (i); - - name = JDOMUtils.getAttributeValue (el, - XMLConstants.name); - - Chapter ch = new Chapter (); - ch.setName (name); - - String text = JDOMUtils.getChildContent (el); - - ch.setText (new StringWithMarkup (text)); - - b.addChapter (ch); - - } - - return b; - - } - - public static boolean areDifferent (Comparable o, - Comparable n) - { - - if ((o == null) && - (n == null)) - { - - return false; - - } - - if ((o != null) && - (n == null)) - { - - return true; - - } - - if ((o == null) && - (n != null)) - { - - return true; - - } - - return o.compareTo (n) != 0; - - } - - public static void addInstallJarToDelete (File oldFile, - File newFile) - { - - Environment.installJarFilesToDelete.add (oldFile); - - } - - public static Date zeroTimeFieldsForDate (Date d) - { - - GregorianCalendar gc = new GregorianCalendar (); - gc.setTime (d); - - Environment.zeroTimeFields (gc); - - return gc.getTime (); - - } - - public static void zeroTimeFields (GregorianCalendar gc) - { - - // Zero-out the non date fields. - gc.set (Calendar.HOUR_OF_DAY, - 0); - gc.set (Calendar.MINUTE, - 0); - gc.set (Calendar.SECOND, - 0); - gc.set (Calendar.MILLISECOND, - 0); - - } - - public static void updateUserObjectTypeNames (Map singular, - Map plural) - throws Exception - { - - //Map newSingular = new HashMap (); - //newSingular.putAll (Environment.objectTypeNamesSingular); - - //newSingular.putAll (singular); - - //Map newPlural = new HashMap (); - //newPlural.putAll (Environment.objectTypeNamesPlural); - - //newPlural.putAll (plural); - - UserConfigurableObjectType type = Environment.getUserConfigurableObjectType (Chapter.OBJECT_TYPE); - - // TODO: Fix this nonsense... - if (singular.containsKey (Chapter.OBJECT_TYPE)) - { - - type.setObjectTypeName (singular.get (Chapter.OBJECT_TYPE)); - - } - - if (plural.containsKey (Chapter.OBJECT_TYPE)) - { - - type.setObjectTypeNamePlural (plural.get (Chapter.OBJECT_TYPE)); - - } - - Environment.updateUserConfigurableObjectType (type); - - Environment.setUserObjectTypeNames (singular, - plural); - - - } - - public static void setUserObjectTypeNames (Map singular, - Map plural) - throws Exception - { - - Map> t = new HashMap (); - - t.put (LanguageStrings.singular, - singular); - t.put (LanguageStrings.plural, - plural); - - IOUtils.writeStringToFile (Environment.getUserObjectTypeNamesFile (), - JSONEncoder.encode (t), - false); - - Environment.loadUserObjectTypeNames (); - - /* - Element root = new Element ("object-names"); - - Map els = new HashMap (); - - for (String ot : singular.keySet ()) - { - - ot = ot.toLowerCase (); - - String s = singular.get (ot); - - Element el = els.get (ot); - - if (el == null) - { - - el = new Element (XMLConstants.object); - - el.setAttribute (XMLConstants.type, - ot); - - els.put (ot, - el); - - root.addContent (el); - - } - - Element sel = new Element (XMLConstants.singular); - - CDATA cd = new CDATA (s); - - sel.addContent (cd); - - el.addContent (sel); - - } - - for (String ot : plural.keySet ()) - { - - ot = ot.toLowerCase (); - - String p = plural.get (ot); - - Element el = els.get (ot); - - if (el == null) - { - - el = new Element (XMLConstants.object); - - el.setAttribute (XMLConstants.type, - ot); - - els.put (ot, - el); - - root.addContent (el); - - } - - Element pel = new Element (XMLConstants.plural); - - CDATA cd = new CDATA (p); - - pel.addContent (cd); - - el.addContent (pel); - - } - - JDOMUtils.writeElementToFile (root, - Environment.getUserObjectTypeNamesFile (), - true); - - // Now force a reload. - Environment.loadObjectTypeNames (root); -*/ - } - - public static Map getObjectTypeNamePlurals () - { - - return new HashMap (Environment.objectTypeNamesPlural); - - } - - public static Map getObjectTypeNames () - { - - return new HashMap (Environment.objectTypeNamesSingular); - - } - - public static String getObjectTypeName (DataObject t) - { - - if (t == null) - { - - return null; - - } - - if (t instanceof UserConfigurableObject) - { - - UserConfigurableObject ut = (UserConfigurableObject) t; - - return ut.getObjectTypeName (); - - } - - if (t instanceof Note) - { - - Note n = (Note) t; - - if (n.isEditNeeded ()) - { - - return Environment.getObjectTypeName ("editneeded" + t.getObjectType ()); - - } - - } - - return Environment.getObjectTypeName (t.getObjectType ()); - - } - - public static String getObjectTypeName (String t) - { - - if (t == null) - { - - return null; - - } - - t = t.toLowerCase (); - - if (t.equals ("qw")) - { - - return Constants.QUOLL_WRITER_NAME; - - } - - String v = Environment.objectTypeNamesSingular.get (t); - - if (v == null) - { - - v = Environment.getUIString (LanguageStrings.objectnames, - LanguageStrings.singular, - t); - - } - - return v; - - } - - public static int getPercent (float t, - float b) - { - - return (int) ((t / b) * 100); - - } - - public static String getObjectTypeNamePlural (DataObject t) - { - - if (t == null) - { - - return null; - - } - - if (t instanceof UserConfigurableObjectType) - { - - UserConfigurableObjectType ut = (UserConfigurableObjectType) t; - - if (ut.isLegacyObjectType ()) - { - - return Environment.getObjectTypeNamePlural (ut.getUserObjectType ()); - - } - - return ut.getObjectTypeNamePlural (); - - } - - if ((t instanceof UserConfigurableObject) - && - (!(t instanceof LegacyUserConfigurableObject)) - ) - { - - UserConfigurableObject ut = (UserConfigurableObject) t; - - return ut.getObjectTypePluralName (); - - } - - if (t instanceof Note) - { - - Note n = (Note) t; - - if (n.isEditNeeded ()) - { - - return Environment.getObjectTypeNamePlural ("editneeded" + t.getObjectType ()); - - } - - } - - return Environment.getObjectTypeNamePlural (t.getObjectType ()); - - } - - public static String getObjectTypeNamePlural (String t) - { - - if (t == null) - { - - return null; - - } - - t = t.toLowerCase (); - - String v = Environment.objectTypeNamesPlural.get (t); - - if (v == null) - { - - v = Environment.getUIString (LanguageStrings.objectnames, - LanguageStrings.plural, - t); - - } - - return v; - - //return Environment.objectTypeNamesPlural.get (t); - - } -/* - public static String getObjectTypeName (NamedObject n) - { - - if (n == null) - { - - return null; - - } - - return Environment.getObjectTypeName (n.getObjectType ()); - - } - - public static String getObjectTypeNamePlural (NamedObject n) - { - - if (n == null) - { - - return null; - - } - - return Environment.getObjectTypeNamePlural (n.getObjectType ()); - - } -*/ - public static Map getOpenProjects () - { - - return new HashMap (Environment.openProjects); - - } - - public static boolean projectsEqual (Project p1, - Project p2) - { - - if ((p1 == null) || - (p2 == null)) - { - - return false; - - } - - if ((p1.getId () != null) - && - (p2.getId () != null) - ) - { - - return p1.equals (p2); - - } - - if (p1.getName ().equalsIgnoreCase (p2.getName ())) - { - - return true; - - } - - return false; - - } - - public static void deleteProject (Project p, - ActionListener onDelete) - { - - ProjectInfo pi = Environment.getProjectInfo (p.getId (), - p.getType ()); - - if (pi == null) - { - - return; - - } - - Environment.deleteProject (pi, - onDelete); - - } - - public static void deleteProject (final ProjectInfo pr, - final ActionListener onDelete) - { - - AbstractProjectViewer viewer = Environment.openProjects.get (pr); - - ActionListener onClose = new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - // There is probably now (because of h2) a "projectdb.lobs.db" directory. - // Add a can delete file to it. - try - { - - Utils.createQuollWriterDirFile (new File (pr.getProjectDirectory ().getPath () + "/projectdb.lobs.db")); - - } catch (Exception e) - { - - // Ignore for now. - Environment.logError ("Unable to add can delete dir file to: " + - pr.getProjectDirectory ().getPath () + "/projectdb.lobs.db", - e); - - } - - // Delete the backup directory. - Utils.deleteDir (pr.getBackupDirectory ()); - - // Delete the files directory. - Utils.deleteDir (pr.getFilesDirectory ()); - - // Delete the directory. - Utils.deleteDir (pr.getProjectDirectory ()); - - // Remove the project from the list. - try - { - - Environment.projectInfoManager.deleteObject (pr, - false, - null); - - } catch (Exception e) - { - - Environment.logError ("Unable to delete project: " + - pr, - e); - - } - - Environment.fireProjectInfoChangedEvent (pr, - ProjectInfoChangedEvent.DELETED); - - if (onDelete != null) - { - - onDelete.actionPerformed (new ActionEvent (pr, 1, "deleted")); - - } else { - - Environment.showLandingIfNoOpenProjects (); - - } - - } - - - }; - - if (viewer != null) - { - - viewer.close (true, - onClose); - - } else { - - UIUtils.doLater (onClose); - - } - - } - - public static void deleteProject (Project pr) - { - - if (pr == null) - { - - return; - - } - - ProjectInfo p = Environment.getProjectInfo (pr); - - if (p == null) - { - - return; - - } - - Environment.deleteProject (p, - null); - - } - - public static ProjectInfo getProjectInfo (Project p) - { - - ProjectInfo pi = Environment.getProjectInfo (p.getId (), - p.getType ()); - - if (pi != null) - { - - pi.setFilePassword (p.getFilePassword ()); - - } - - return pi; - - } - - public static ProjectInfo getProjectInfo (String id, - String type) - { - - try - { - - for (ProjectInfo p : Environment.getAllProjectInfos ()) - { - - if (p.getId ().equals (id)) - { - - if (type == null) - { - - return p; - - } - - if (type.equals (p.getType ())) - { - - return p; - - } - - } - - } - - } catch (Exception e) { - - Environment.logError ("Unable to get all project infos to check for project: " + - id + - ", type: " + - type, - e); - - } - - return null; - - } - - public static void showLandingIfNoOpenProjects () - { - - // Show the welcome screen if there are no projects open. - if (Environment.getOpenProjects ().size () == 0) - { - - Environment.showLanding (); - - } - - } - - public static File getQuollWriterJarsDir () - { - - String userDir = System.getProperty ("user.dir"); - - if (!userDir.endsWith ("jars")) - { - - userDir += "/jars"; - - } - - File dir = null; - - try - { - - dir = new File (userDir).getCanonicalFile (); - - } catch (Exception e) { - - return null; - - } - - if ((!dir.exists ()) - || - (dir.isFile ()) - ) - { - - return null; - - } - - return dir; - - } - - public static void closeDown () - { - - if (Environment.openViewers.size () > 0) - { - - throw new IllegalStateException ("Cannot closedown when there are open viewers."); - - } - - Environment.generalTimer.shutdown (); - - // Go offline from the editors service (if logged in). - EditorsEnvironment.closeDown (); - - Environment.userSession.end (new Date ()); - - try - { - - Environment.projectInfoManager.addSession (Environment.userSession); - - } catch (Exception e) { - - Environment.logError ("Unable to add session", - e); - - } - - Environment.projectInfoManager.closeConnectionPool (); - - if (Environment.doOnShutdown.size () > 0) - { - - for (Runnable r : Environment.doOnShutdown) - { - - try - { - - r.run (); - - } catch (Exception e) { - - Environment.logError ("Unable to run on shutdown.", - e); - - } - - } - - } - - System.exit (0); - - } - - /** - * Inform the environment about a project closing. - * - * If onClose is provided then it is assumed that the caller - * is doing something after the project has been deregistered with the - * environment, for example opening another project or window. - * - * If onClose is not provided (null) then a check is made to see if - * the projects window should be shown or should shutdown occur because - * there are no projects open. - * - * @param pv The project viewer being closed. - * @param onClose The action to take once the project is deregistered. - * @throws Exception If something goes wrong (the list is long). - */ - public static void projectClosed (AbstractProjectViewer pv, - boolean tryShowLanding) - throws Exception - { - - Project proj = pv.getProject (); - - ProjectInfo p = Environment.getProjectInfo (pv.getProject ().getId (), - pv.getProject ().getType ()); - - if (p != null) - { - - Object r = Environment.openProjects.remove (p); - - } - - Environment.userSession.updateCurrentSessionWordCount (pv.getSessionWordCount ()); - - if ((tryShowLanding) - && - (UserProperties.getAsBoolean (Constants.SHOW_PROJECTS_WINDOW_WHEN_NO_OPEN_PROJECTS_PROPERTY_NAME)) - ) - { - - Environment.showLandingIfNoOpenProjects (); - - } - - } - - public static void addOpenedProject (AbstractProjectViewer pv) - throws Exception - { - - final Project proj = pv.getProject (); - - ProjectInfo p = Environment.getProjectInfo (proj.getId (), - proj.getType ()); - - if (p == null) - { - - // We don't have this project, so add it. - p = new ProjectInfo (proj); - - try - { - - Environment.projectInfoManager.saveObject (p, - null); - - } catch (Exception e) { - - Environment.logError ("Unable to add new project info for project: " + - proj, - e); - - } - - } else { - - p.setProject (proj); - - } - - Environment.openProjects.put (p, - pv); - - } - - public static void updateProjectInfo (ProjectInfo pi) - throws GeneralException - { - - Environment.projectInfoManager.saveObject (pi, - null); - - Environment.fireProjectInfoChangedEvent (pi, - ProjectInfoChangedEvent.CHANGED); - - } - - public static void updateProjectInfos (List pis) - throws GeneralException - { - - Environment.projectInfoManager.saveObjects (pis, - null); - - for (ProjectInfo pi : pis) - { - - Environment.fireProjectInfoChangedEvent (pi, - ProjectInfoChangedEvent.CHANGED); - - } - - } - - public static String replaceObjectNames (String t) - { - - if (t == null) - { - - return t; - - } - - StringBuilder b = new StringBuilder (t); - - int start = b.indexOf ("{"); - - while (start > -1) - { - - int end = b.indexOf ("}", - start); - - if (end > -1) - { - - String ot = b.substring (start + 1, - end); - - String newot = ot.toLowerCase (); - - if (newot.equals ("qw")) - { - - newot = Constants.QUOLL_WRITER_NAME; - - } - -/* - boolean an = newot.startsWith ("an "); - - if (an) - { - - newot = newot.substring (3); - - } - - if (newot.endsWith ("s")) - { - - newot = Environment.getObjectTypeNamePlural (newot.substring (0, - newot.length () - 1)); - - } else - { - - newot = Environment.getObjectTypeName (newot); - - } - - if (newot == null) - { - - newot = ot; - - } else - { - - if (Character.isUpperCase (ot.charAt (0))) - { - - newot = Character.toUpperCase (newot.charAt (0)) + newot.substring (1); - - } else - { - - newot = newot.toLowerCase (); - - } - - } - - if (an) - { - - if (TextUtilities.isVowel (newot.toLowerCase ().charAt (0))) - { - - newot = "an " + newot; - - } else { - - newot = "a " + newot; - - } - - } -*/ - b.replace (start, - end + 1, - newot); - - start += newot.length (); - - } else { - - start++; - - } - - start = b.indexOf ("{", - start); - - } - - return b.toString (); - - } - - public static String canOpenProject (Project p) - { - - java.util.List prefix = new ArrayList (); - prefix.add (LanguageStrings.project); - prefix.add (LanguageStrings.actions); - prefix.add (LanguageStrings.openproject); - prefix.add (LanguageStrings.openerrors); - - if (p == null) - { - - return Environment.getUIString (prefix, - LanguageStrings.projectnotexist); - //"{Project} does not exist."; - - } - - if (!p.getProjectDirectory ().exists ()) - { - - return String.format (Environment.getUIString (prefix, - LanguageStrings.projectdirnotexist), - p.getProjectDirectory ()); - //"Cannot find {project} directory " + p.getProjectDirectory () + "."; - - } - - if (!p.getProjectDirectory ().isDirectory ()) - { - - return String.format (Environment.getUIString (prefix, - LanguageStrings.projectdirisfile), - p.getProjectDirectory ()); - //"Path to {project} " + p.getProjectDirectory () + " is a file, but a directory is expected."; - - } - - if (!Utils.getQuollWriterDirFile (p.getProjectDirectory ()).exists ()) - { - - return String.format (Environment.getUIString (prefix, - LanguageStrings.invalidprojectdir), - p.getProjectDirectory ()); - //"{Project} directory " + p.getProjectDirectory () + " doesn't appear to be a valid Quoll Writer {project}."; - - } - - if ((p.isEditorProject ()) - && - (EditorsEnvironment.getEditorByEmail (p.getForEditor ().getEmail ()) == null) - ) - { - - return String.format (Environment.getUIString (prefix, - LanguageStrings.cantfindeditor), - //"Unable to find {contact}: %s you are editing the {project} for.", - p.getForEditor ().getEmail ()); - - } - - return null; - - } - - public static String canOpenProject (ProjectInfo p) - { - - java.util.List prefix = new ArrayList<> (); - prefix.add (LanguageStrings.project); - prefix.add (LanguageStrings.actions); - prefix.add (LanguageStrings.openproject); - prefix.add (LanguageStrings.openerrors); - - if (p == null) - { - - return Environment.getUIString (prefix, - LanguageStrings.projectnotexist); - //return "{Project} does not exist."; - - } - - if (!p.getProjectDirectory ().exists ()) - { - - return String.format (Environment.getUIString (prefix, - LanguageStrings.projectdirnotexist), - p.getProjectDirectory ()); - //return "Cannot find {project} directory " + p.getProjectDirectory () + "."; - - } - - if (!p.getProjectDirectory ().isDirectory ()) - { - - return String.format (Environment.getUIString (prefix, - LanguageStrings.projectdirisfile), - p.getProjectDirectory ()); - //return "Path to {project} " + p.getProjectDirectory () + " is a file, but a directory is expected."; - - } - - if (!Utils.getQuollWriterDirFile (p.getProjectDirectory ()).exists ()) - { - - return String.format (Environment.getUIString (prefix, - LanguageStrings.invalidprojectdir), - p.getProjectDirectory ()); - //return "{Project} directory " + p.getProjectDirectory () + " doesn't appear to be a valid Quoll Writer {project}."; - - } - - if ((p.isEditorProject ()) - && - (p.getForEditor () != null) - && - (EditorsEnvironment.getEditorByEmail (p.getForEditor ().getEmail ()) == null) - ) - { - - return String.format (Environment.getUIString (prefix, - LanguageStrings.cantfindeditor), - //"Unable to find {contact}: %s you are editing the {project} for.", - p.getForEditor ().getEmail ()); - - } - - return null; - - } - - public static boolean isFirstUse () - { - - return Environment.isFirstUse; - - } - - public static boolean checkCanOpenProject (ProjectInfo p, - boolean showLanding) - { - - String r = Environment.canOpenProject (p); - - if (r != null) - { - - // Do this first to ensure the error shows above it. - if (showLanding) - { - - Environment.showLanding (); - - } - - UIUtils.showErrorMessage (null, - String.format (Environment.getUIString (LanguageStrings.project, - LanguageStrings.actions, - LanguageStrings.openproject, - LanguageStrings.openerrors, - LanguageStrings.general), - p.getName (), - r)); - //"Unable to open {project} " + p.getName () + ", reason:

" + r); - - return false; - - } - - return true; - - } - - public static boolean openLastEditedProject () - throws Exception - { - - List projs = new ArrayList (Environment.getAllProjectInfos ()); - - Collections.sort (projs, - new ProjectInfoSorter ()); - - ProjectInfo p = null; - - if (projs.size () > 0) - { - - p = projs.get (0); - - } - - if (p != null) - { - - // Check to see if the project directory exists. - if (!Environment.checkCanOpenProject (p, - true)) - { - - // We return true here since we don't want further errors to be displayed or the find/open. - return true; - - } - - try - { - - // Get the first. - Environment.openProject (p, - null); - - } catch (Exception e) - { - - Environment.logError ("Unable to open project: " + - p, - e); - - return false; - - } - - return true; - - } - - return false; - - } - - public static ProjectInfo getProjectById (String id, - String projType) - throws Exception - { - - if (id == null) - { - - return null; - - } - - Set projs = Environment.getAllProjectInfos (); - - for (ProjectInfo p : projs) - { - - String pid = p.getId (); - - if (pid == null) - { - - continue; - - } - - if (projType != null) - { - - if (!p.getType ().equals (projType)) - { - - continue; - - } - - } - - if (pid.equals (id)) - { - - return p; - - } - - } - - return null; - - } - - public static ProjectInfo getProjectByDirectory (File dir) - throws Exception - { - - if (dir == null) - { - - return null; - - } - - Set projs = Environment.getAllProjectInfos (); - - for (ProjectInfo p : projs) - { - - if (p.getProjectDirectory ().equals (dir)) - { - - return p; - - } - - } - - return null; - - } - - /** For a given project, get the project version object by its id. - * - * @param p The project. - * @param id The project version id. - * @param filePassword The password for the project file if it is encrypted. - * @return The project version, if it can be found. - * @throws Exception If something goes wrong. - * TODO: Move the filepassword into the project and expect it there instead. - */ - public static ProjectVersion getProjectVersionById (ProjectInfo p, - String id, - String filePassword) - throws Exception - { - - AbstractProjectViewer pv = Environment.getProjectViewer (p); - - ObjectManager om = null; - - if (pv != null) - { - - // Load up the chapters. - om = pv.getObjectManager (); - - } else { - - // Open the project. - om = Environment.getProjectObjectManager (p, - filePassword); - - om.getProject (); - - } - - ProjectVersionDataHandler pdh = (ProjectVersionDataHandler) om.getHandler (ProjectVersion.class); - - return pdh.getById (id); - - } - - /** - * For a given project get the text/data for the versions of the chapters passed in. This assumes that the - * text is not already available in the chapter object, for example when you only know the id and version. - * - * @param p The project. - * @param chaps The chapters to look up. - * @param filePassword The password for the project file if it is encrypted. - * @return The set of versioned chapters. - * @throws If something goes wrong. - * TODO: Move the filepassword into the project and expect it there instead. - */ - public static Set getVersionedChapters (ProjectInfo p, - Collection chaps, - String filePassword) - throws Exception - { - - AbstractProjectViewer pv = Environment.getProjectViewer (p); - - ObjectManager om = null; - - if (pv != null) - { - - // Load up the chapters. - om = pv.getObjectManager (); - - } else { - - // Open the project. - om = Environment.getProjectObjectManager (p, - filePassword); - - om.getProject (); - - } - - ChapterDataHandler cdh = (ChapterDataHandler) om.getHandler (Chapter.class); - - return cdh.getVersionedChapters (chaps); - - } - - /** - * Update the chapters to the versions provided. This creates new chapter objects with new keys but - * keeps the id/version in the chapter. - * - * @param p The project. - * @param projVer The new project version to update to. - * @param chaps The chapters to update. - * @param filePassword The password for the project file if it is encrypted. - * @return The set of versioned chapters. - * @throws If something goes wrong. - * TODO: Move the filepassword into the project and expect it there instead. - */ - public static Set updateToNewVersions (ProjectInfo p, - ProjectVersion projVer, - Collection chaps, - String filePassword) - throws Exception - { - - boolean closePool = false; - - AbstractProjectViewer pv = Environment.getProjectViewer (p); - - ObjectManager om = null; - - if (pv != null) - { - - // Load up the chapters. - om = pv.getObjectManager (); - - } else { - - // Open the project. - om = Environment.getProjectObjectManager (p, - filePassword); - - om.getProject (); - - closePool = true; - - } - - try - { - - ChapterDataHandler cdh = (ChapterDataHandler) om.getHandler (Chapter.class); - - // Check to see if we already have a version with the specified id. - ProjectVersionDataHandler pvdh = (ProjectVersionDataHandler) om.getHandler (ProjectVersion.class); - - if (pvdh.getById (projVer.getId ()) != null) - { - - // Already have this version. - return cdh.getChaptersForVersion (projVer, - om.getProject ().getBook (0), - null, - true); - - } - - return cdh.updateToNewVersions (projVer, - chaps); - - } finally { - - if (closePool) - { - - if (om != null) - { - - om.closeConnectionPool (); - - } - - } - - } - - } - - public static void restoreBackupForProject (ProjectInfo p, - File restoreFile) - throws Exception - { - - // Get the project db file. - - File dbFile = new File (p.getProjectDirectory (), - Constants.PROJECT_DB_FILE_NAME_PREFIX + Constants.H2_DB_FILE_SUFFIX); - - if (!dbFile.exists ()) - { - - throw new GeneralException ("No project database file found at: " + - dbFile + - ", for project: " + - p); - - } - - File oldDBFile = new File (dbFile.getPath () + ".old"); - - // Rename to .old - // TODO: Investigate using java.nio.file.Files.move instead. - if (!dbFile.renameTo (oldDBFile)) - { - - throw new GeneralException ("Unable to rename project database file to: " + - dbFile.getPath () + ".old" + - ", for project: " + - p); - - } - - try - { - - Utils.extractZipFile (restoreFile, - p.getProjectDirectory ()); - - // See if there is a project db file in there now. - if (!dbFile.exists ()) - { - - throw new GeneralException ("Backup file does not contain a valid project db file"); - - } - - oldDBFile.delete (); - - } catch (Exception e) { - - // Try and rename back. - oldDBFile.renameTo (dbFile); - - throw e; - - } - - } - - public static File createBackupForProject (Project p, - boolean noPrune) - throws Exception - { - - return Environment.createBackupForProject (Environment.getProjectInfo (p), - noPrune); - - } - - public static File createBackupForProject (ProjectInfo p, - boolean noPrune) - throws Exception - { - - boolean closePool = false; - - AbstractProjectViewer pv = Environment.getProjectViewer (p); - - ObjectManager om = null; - Project proj = null; - - if (pv != null) - { - - // Load up the chapters. - om = pv.getObjectManager (); - - proj = pv.getProject (); - - } else { - - if ((p.isEncrypted ()) - && - (p.getFilePassword () == null) - ) - { - - throw new IllegalArgumentException ("The file password must be specified for encrypted projects when the project is not already open."); - - } - - // Open the project. - try - { - - om = Environment.getProjectObjectManager (p, - p.getFilePassword ()); - - proj = om.getProject (); - - } catch (Exception e) { - - // Can't open the project. - if (om != null) - { - - om.closeConnectionPool (); - - } - - throw e; - - } - - proj.setBackupDirectory (p.getBackupDirectory ()); - - closePool = true; - - } - - String backupCount = proj.getProperty (Constants.BACKUPS_TO_KEEP_COUNT_PROPERTY_NAME); - - int count = -1; - - if ((backupCount != null) - && - // Legacy, pre 2.6.5 - (!backupCount.equals ("All")) - ) - { - - try - { - - count = Integer.parseInt (backupCount); - - } catch (Exception e) {} - - } - - try - { - - File f = om.createBackup (proj, - (noPrune ? -1 : count)); - - Environment.fireUserProjectEvent (proj, - ProjectEvent.BACKUPS, - ProjectEvent.NEW, - proj); - - return f; - - } finally { - - if (closePool) - { - - if (om != null) - { - - om.closeConnectionPool (); - - } - - } - - } - - } - - /** - * Get an object manager for the specified project and init it. - * - * @param p The project. - * @param filePassword Optional, the password for the project if it is encrypted. - * @returns The object manager for the project. - * @throws An exception if the object manager cannot be inited. - * TODO: Move the filepassword into the project and expect it there instead. - */ - public static ObjectManager getProjectObjectManager (ProjectInfo p, - String filePassword) - throws GeneralException - { - - // Get the username and password. - String username = Environment.getProperty (Constants.DB_USERNAME_PROPERTY_NAME); - String password = Environment.getProperty (Constants.DB_PASSWORD_PROPERTY_NAME); - - if (p.isNoCredentials ()) - { - - username = null; - password = null; - - } - - ObjectManager dBMan = new ObjectManager (); - dBMan.init (new File (p.getProjectDirectory ().getPath (), Constants.PROJECT_DB_FILE_NAME_PREFIX), - username, - password, - filePassword, - Environment.getSchemaVersion ()); - - try - { - - dBMan.getProject (); - - } catch (Exception e) { - - dBMan.closeConnectionPool (); - - throw e; - - } - - return dBMan; - - } - - /** - * Creates a completely new project with the specified name at the saveDir/name location. - * If the project is to be encrypted then a filePassword should be supplied. The schema will be created. - * - * @param saveDir The directory to save the project to. - * @param name The name of the project. - * @param filePassword Optional, provide if the project is to be encrypted. - * @returns The new project object created. - * @throws An exception if the schema cannot be created or if the save location already exists. - */ - public static Project createNewProject (File saveDir, - String name, - String filePassword) - throws Exception - { - - File projDir = new File (saveDir, - Utils.sanitizeForFilename (name)); - - if (projDir.exists ()) - { - - throw new IllegalArgumentException ("A project with name: " + - name + - " already exists at: " + - projDir); - - } - - Project p = new Project (); - p.setName (name); - - // Get the username and password. - String username = Environment.getProperty (Constants.DB_USERNAME_PROPERTY_NAME); - String password = Environment.getProperty (Constants.DB_PASSWORD_PROPERTY_NAME); - - ObjectManager dBMan = new ObjectManager (); - dBMan.init (new File (projDir.getPath (), Constants.PROJECT_DB_FILE_NAME_PREFIX), - username, - password, - filePassword, - 0); - - // Create a file that indicates that the directory can be deleted. - Utils.createQuollWriterDirFile (projDir); - - p.setProjectDirectory (projDir); - p.setEncrypted (filePassword != null); - - Book b = new Book (p, - p.getName ()); - - p.addBook (b); - - dBMan.saveObject (p, - null); - - dBMan.closeConnectionPool (); - - ProjectInfo pi = new ProjectInfo (p); - - Environment.fireProjectInfoChangedEvent (pi, - ProjectInfoChangedEvent.ADDED); - - return p; - - } - - /** - * Creates the specified project (containing the relevant information) at the saveDir/p.getName () location. - * If the project is to be encrypted then a filePassword should be supplied. The schema will be created. - * - * @param saveDir The directory to save the project to. - * @param p The project. - * @param filePassword Optional, provide if the project is to be encrypted. - * @throws An exception if the schema cannot be created or if a project already exists at the save location. - */ - public static ObjectManager createProject (File saveDir, - Project p, - String filePassword) - throws Exception - { - - File projDir = new File (saveDir, - Utils.sanitizeForFilename (p.getName ())); - - if (projDir.exists ()) - { - - throw new IllegalArgumentException ("A project with name: " + - p.getName () + - " already exists at: " + - projDir); - - } - - // Get the username and password. - String username = Environment.getProperty (Constants.DB_USERNAME_PROPERTY_NAME); - String password = Environment.getProperty (Constants.DB_PASSWORD_PROPERTY_NAME); - - ObjectManager dBMan = new ObjectManager (); - dBMan.init (new File (projDir.getPath (), Constants.PROJECT_DB_FILE_NAME_PREFIX), - username, - password, - filePassword, - 0); - - // Create a file that indicates that the directory can be deleted. - Utils.createQuollWriterDirFile (projDir); - - p.setProjectDirectory (projDir); - p.setEncrypted (filePassword != null); - - dBMan.setProject (p); - - dBMan.saveObject (p, - null); - - ProjectInfo pi = new ProjectInfo (p); - - Environment.projectInfoManager.saveObject (pi, - null); - - Environment.fireProjectInfoChangedEvent (pi, - ProjectInfoChangedEvent.ADDED); - - return dBMan; - - } - - public static void openObjectInProject (final ProjectInfo proj, - final DataObject obj) - throws Exception - { - - Environment.openProject (proj, - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - // View the object. - AbstractProjectViewer viewer = Environment.getProjectViewer (proj); - - viewer.viewObject (obj); - - } - - }); - - } - - public static void openObjectInProject (final Project proj, - final DataObject obj) - throws Exception - { - - final DataObject dobj = obj; - - ProjectInfo p = null; - - try - { - - p = Environment.getProjectInfo (proj); - - } catch (Exception e) { - - throw new GeneralException ("Unable to get project info for project id: " + - proj.getId (), - e); - - } - - if (p == null) - { - - throw new GeneralException ("Unable to get project info for project id: " + - proj.getId ()); - - } - - Environment.openObjectInProject (p, - obj); - - } - - public static void openProjectWithId (String projId, - String projType) - throws Exception - { - - Environment.openProject (projId, - projType, - null); - - } - - public static void openProject (Project p) - throws Exception - { - - Environment.openProject (p, - null); - - } - - public static void openProject (Project p, - ActionListener onProjectOpen) - throws Exception - { - - if (p == null) - { - - return; - - } - - Environment.openProject (p.getId (), - p.getType (), - onProjectOpen); - - } - - public static void openProject (final String projId, - final String projType, - final ActionListener onProjectOpen) - throws Exception - { - - ProjectInfo p = Environment.getProjectInfo (projId, - projType); - - if (p != null) - { - - Environment.openProject (p, - onProjectOpen); - - } - - } - - public static void openProject (final ProjectInfo p) - throws Exception - { - - Environment.openProject (p, - null); - - } - - public static void openProject (final ProjectInfo p, - final ActionListener onProjectOpen) - throws Exception - { - - if (p == null) - { - - return; - - } - - if (p.isOpening ()) - { - - return; - - } - - AbstractProjectViewer pv = (AbstractProjectViewer) Environment.openProjects.get (p); - - if (pv != null) - { - - p.setOpening (false); - - pv.setVisible (true); - pv.setState (java.awt.Frame.NORMAL); - pv.toFront (); - - if (onProjectOpen != null) - { - - onProjectOpen.actionPerformed (new ActionEvent ("open", 1, "open")); - - } - - } else - { - - try - { - - pv = Environment.getProjectViewerForType (p); - - } catch (Exception e) - { - - throw new GeneralException ("Unable to open project: " + - p, - e); - - } - - if (pv == null) - { - - throw new GeneralException ("Unable to open project: " + - p); - - } - - final AbstractProjectViewer fpv = pv; - /* - if (onProjectOpen != null) - { - - pv.addProjectEventListener (new ProjectEventListener () - { - - @Override - public void eventOccurred (ProjectEvent ev) - { - - if ((ev.getType ().equals (Project.OBJECT_TYPE)) - && - (ev.getAction ().equals (ProjectEvent.OPEN)) - ) - { - - try - { - - onProjectOpen.actionPerformed (new ActionEvent (fpv, 1, "open")); - - } catch (Exception e) { - - Environment.logError ("Unable to perform action after project open", - e); - - } - - } - - } - - }); - - } - */ - Environment.incrStartupProgress (); - - java.util.List prefix = new ArrayList (); - prefix.add (LanguageStrings.project); - prefix.add (LanguageStrings.actions); - prefix.add (LanguageStrings.openproject); - prefix.add (LanguageStrings.enterpasswordpopup); - - if (p.isEncrypted ()) - { - - Environment.startupComplete (); - - PasswordInputWindow.create (Environment.getUIString (prefix, - LanguageStrings.title), - //"Enter password", - "lock", - String.format (Environment.getUIString (prefix, - LanguageStrings.text), - p.getName ()), - //"{Project}: " + p.getName () + " is encrypted, please enter the password.", - Environment.getUIString (prefix, - LanguageStrings.buttons, - LanguageStrings.open), - //"Open", - new ValueValidator () - { - - public String isValid (String v) - { - - if ((v == null) - || - (v.trim ().equals ("")) - ) - { - - return Environment.getUIString (prefix, - LanguageStrings.errors, - LanguageStrings.novalue); - //"Please enter the password."; - - } - - try - { - - fpv.openProject (p, - v, - onProjectOpen); - /* - Environment.openProjects.put (p, - fpv); - */ - } catch (Exception e) { - - if (ObjectManager.isDatabaseAlreadyInUseException (e)) - { - - return Environment.getUIString (prefix, - LanguageStrings.errors, - LanguageStrings.projectalreadyopen); - //"Sorry, the {project} appears to already be open in Quoll Writer. Please close all other instances of Quoll Writer first before trying to open the {project}."; - - } - - if (ObjectManager.isEncryptionException (e)) - { - - return Environment.getUIString (prefix, - LanguageStrings.errors, - LanguageStrings.invalidpassword); - //return "Password is not valid."; - - } - - Environment.logError ("Cant open project: " + - p, - e); - - UIUtils.showErrorMessage (null, - Environment.getUIString (prefix, - LanguageStrings.errors, - LanguageStrings.general)); - //"Sorry, the {project} can't be opened. Please contact Quoll Writer support for assistance."); - - return null; - - } finally { - - p.setOpening (false); - - } - - return null; - - } - - }, - new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - // All handled by the validator. - - } - - }, - new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - Environment.showLanding (); - - } - - }).resize (); - - return; - - } - - try - { - - pv.openProject (p, - null, - onProjectOpen); - - } catch (Exception e) { - - pv.close (false, - null); - - if (ObjectManager.isDatabaseAlreadyInUseException (e)) - { - - UIUtils.showErrorMessage (null, - Environment.getUIString (prefix, - LanguageStrings.errors, - LanguageStrings.projectalreadyopen)); - //"Sorry, the {project} appears to already be open in Quoll Writer. Please close all other instances of Quoll Writer first before trying to open the {project}."); - - return; - - } - - throw e; - - } finally { - - p.setOpening (false); - - } - - Environment.startupComplete (); - /* - Environment.openProjects.put (p, - pv); -*/ - } - - //return pv; - - } - - public static void addToAchievementsManager (AbstractProjectViewer viewer) - { - - try - { - - Environment.achievementsManager.addProjectViewer (viewer); - - } catch (Exception e) { - - Environment.logError ("Unable to init achievements for viewer: " + - viewer, - e); - - } - - } - - public static void removeFromAchievementsManager (AbstractViewer viewer) - { - - try - { - - Environment.achievementsManager.removeViewer (viewer); - - } catch (Exception e) { - - Environment.logError ("Unable to remove from achievements: " + - viewer, - e); - - } - - } - - public static boolean isDebugModeEnabled () - { - - return Environment.debugMode; - - } - - public static void setDebugModeEnabled (boolean v) - { - - Environment.debugMode = v; - - // TODO: Maybe have an EnvironmentEvent? - - } - - public static void logDebugMessage (String m) - { - - if (Environment.isDebugModeEnabled ()) - { - - Environment.logMessage (m); - - } - - } - - public static void logMessage (String m) - { - - if (Environment.isDebugModeEnabled ()) - { - - //System.out.println (m); - - } - - Environment.generalLog.logInformationMessage (m); - - } - - public static void logError (String m) - { - - if (Environment.errorLog == null) - { - - return; - - } - - Environment.logError (m, - null); - - } - - public static void logSQLStatement (String s, - List params) - { - - if (!Environment.isDebugModeEnabled ()) - { - - return; - - } - - Environment.sqlLog.logInformationMessage ("SQL:=============================\n" + s + "\nPARAMS:\n" + params); - - } - - public static void logError (String m, - Exception ex) - { - - if (Environment.errorLog == null) - { - - return; - - } - - Environment.errorLog.logError (m, - ex, - null); - - if ((!Environment.isDebugModeEnabled ()) - && - (UserProperties.getAsBoolean (Constants.AUTO_SEND_ERRORS_TO_SUPPORT_PROPERTY_NAME)) - ) - { - - Map details = new HashMap (); -/* - try - { - - details.put ("errorLog", - IOUtils.getFile (Environment.getErrorLogFile ())); - details.put ("generalLog", - IOUtils.getFile (Environment.getGeneralLogFile ())); - - } catch (Exception e) { - - // NOt much we can do here! - - } -*/ - details.put ("reason", - m); - - if (ex != null) - { - - details.put ("stackTrace", - Utils.getStackTrace (ex)); - - } - - try - { - - Environment.sendMessageToSupport ("error", - details, - null); - - } catch (Exception e) { - - // Nothing we can do. - - } - - } - - } - - public static com.gentlyweb.properties.Properties getDefaultProperties (String objType) - { - - com.gentlyweb.properties.Properties props = (com.gentlyweb.properties.Properties) Environment.defaultObjectProperties.get (objType); - - if (props == null) - { - - // Create some new blank properties. - props = new com.gentlyweb.properties.Properties (); - - Environment.defaultObjectProperties.put (objType, - props); - - } - - if (props.getId () == null) - { - - props.setId ("default-" + objType); - - } - - if (props.getParentProperties () == null) - { - - props.setParentProperties (UserProperties.getProperties ()); - - } - - return props; - - } - - private static void initProjectId (Project envProj, - Project realProj) - { - - if ((envProj.getId () == null) - && - (realProj.getId () != null) - ) - { - - envProj.setId (realProj.getId ()); - - } - - } - - public static void setUILanguage (String id) - throws Exception - { - - LanguageStrings ls = null; - - ls = Environment.getUILanguageStrings (id); - - if (ls == null) - { - - throw new GeneralException ("No language strings found for id: " + - id); - - } - - Environment.uiLanguageStrings = ls; - - UserProperties.set (Constants.USER_UI_LANGUAGE_PROPERTY_NAME, id); - - Environment.loadUserObjectTypeNames (); - - } - - private static File getUILanguageStringsDir () - { - - File d = new File (Environment.getUserQuollWriterDir (), - Constants.UI_LANGUAGES_DIR_NAME); - - if (!d.exists ()) - { - - d.mkdirs (); - - } - - return d; - - } - - private static File getUserUILanguageStringsDir (Version v) - { - - File d = new File (Environment.getUserQuollWriterDir (), - Constants.USER_UI_LANGUAGES_DIR_NAME + "/" + v.toString ()); - - if (!d.exists ()) - { - - d.mkdirs (); - - } - - return d; - - } - - public static LanguageStrings getUserUILanguageStrings (Version v, - String id) - throws Exception - { - - File f = Environment.getUserUILanguageStringsFile (v, - id); - - if (f.exists ()) - { - - LanguageStrings ls = new LanguageStrings (f); - ls.setUser (true); - - return ls; - - } - - return null; - - } - - private static void deleteUserUILanguageStrings (final LanguageStrings ls) - { - - ActionListener remFile = new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - File f = Environment.getUserUILanguageStringsFile (ls.getQuollWriterVersion (), - ls.getId ()); - - if (f.exists ()) - { - - f.delete (); - - } - - } - - }; - - Set viewers = new HashSet<> (Environment.openViewers); - - for (AbstractViewer v : viewers) - { - - if (v instanceof LanguageStringsEditor) - { - - LanguageStringsEditor lse = (LanguageStringsEditor) v; - - if ((lse.getUserLanguageStrings ().getId ().equals (ls.getId ())) - && - (lse.getUserLanguageStrings ().getQuollWriterVersion ().equals (ls.getQuollWriterVersion ())) - ) - { - - lse.close (false, - remFile); - - return; - - } - - } - - } - - remFile.actionPerformed (new ActionEvent (ls, 0, "do")); - - if (UserProperties.get (Constants.USER_UI_LANGUAGE_PROPERTY_NAME).equals ("user-" + ls.getId ())) - { - - try - { - - // Need to set the language back to English. - Environment.setUILanguage (LanguageStrings.ENGLISH_ID); - - } catch (Exception e) { - - Environment.logError ("Unable to set UI strings.", - e); - - UIUtils.showErrorMessage (null, - "Unable to reset user interface language to " + Constants.ENGLISH); - - return; - - } - - UIUtils.showMessage ((Component) null, - "Restart recommended", - "The user interface language has been reset to " + Constants.ENGLISH + ", a restart is recommended."); - - } - - } - - public static void deleteUserUILanguageStrings (LanguageStrings ls, - boolean allVersions) - throws Exception - { - - if (!ls.isUser ()) - { - - throw new IllegalArgumentException ("Can only delete user language strings."); - - } - - if (allVersions) - { - - Set allLs = Environment.getAllUserLanguageStrings (); - - for (LanguageStrings _ls : allLs) - { - - if (_ls.getId ().equals (ls.getId ())) - { - - Environment.deleteUserUILanguageStrings (_ls); - - } - - } - - } else { - - Environment.deleteUserUILanguageStrings (ls); - - } - - } - - public static LanguageStrings getUserUIEnglishLanguageStrings (Version v) - throws Exception - { - - // If the version is the same as the QW version the user is running then - if (v.equals (Environment.getQuollWriterVersion ())) - { - - LanguageStrings def = Environment.getDefaultUILanguageStrings (); - - Environment.saveUserUILanguageStrings (def); - - return def; - - //return Environment.getUserUIEnglishLanguageStrings (v); - - } - - // See if there is a user strings file. - File f = Environment.getUserUILanguageStringsFile (v, - LanguageStrings.ENGLISH_ID); - - if (f.exists ()) - { - - return new LanguageStrings (f); - - } - - return null; - - } - - public static LanguageStrings getDefaultUILanguageStrings () - { - - return Environment.defaultUILanguageStrings; - - } - - public static LanguageStrings getCurrentUILanguageStrings () - { - - return Environment.uiLanguageStrings; - - } - - public static LanguageStrings getUILanguageStrings (String id) - throws Exception - { - - if (id.startsWith ("user-")) - { - - id = id.substring ("user-".length ()); - - return Environment.getUserUILanguageStrings (Environment.getQuollWriterVersion (), - id); - - } - - if (id.equals (LanguageStrings.ENGLISH_ID)) - { - - return Environment.getDefaultUILanguageStrings (); - - } - - File f = Environment.getUILanguageStringsFile (id); - - if (!f.exists ()) - { - - return null; - - } - - String data = Utils.getFileAsString (f, - StandardCharsets.UTF_8); - - LanguageStrings s = new LanguageStrings (data); - - return s; - - } - - public static Set getAllUserLanguageStrings (Version qwVer) - throws GeneralException - { - - Set ret = new LinkedHashSet<> (); - - for (LanguageStrings ls : Environment.getAllUserLanguageStrings ()) - { - - if (ls.getQuollWriterVersion ().equals (qwVer)) - { - - ret.add (ls); - - } - - } - - return ret; - - } - - public static Set getAllUserLanguageStrings () - throws GeneralException - { - - Set s = new TreeSet<> (); - - File d = new File (Environment.getUserQuollWriterDir (), - Constants.USER_UI_LANGUAGES_DIR_NAME); - - File[] files = d.listFiles (); - - if (files != null) - { - - for (int i = 0; i < files.length; i++) - { - - File fd = files[i]; - - File[] dfiles = fd.listFiles (); - - if (dfiles != null) - { - - for (int j = 0; j < dfiles.length; j++) - { - - LanguageStrings ls = new LanguageStrings (dfiles[j]); - - if (ls.isEnglish ()) - { - - continue; - - } - - s.add (ls); - - } - - } - - } - - } - - return s; - - } - - public static void saveUserUILanguageStrings (LanguageStrings ls) - throws Exception - { - - File f = Environment.getUserUILanguageStringsFile (ls); - - f.getParentFile ().mkdirs (); - - String json = JSONEncoder.encode (ls.getAsJSON ()); - - Writer out = new BufferedWriter (new OutputStreamWriter (new FileOutputStream (f), - "utf-8")); - - char[] chars = json.toCharArray (); - - out.write (chars, 0, chars.length); - out.flush (); - out.close (); - - } - - public static void downloadUILanguageFile (final String id, - final ActionListener onComplete, - final ActionListener onError) - { - - Environment.schedule (new Runnable () - { - - @Override - public void run () - { - - String lastMod = ""; - - LanguageStrings ls = null; - - try - { - - ls = Environment.getUILanguageStrings (id); - - } catch (Exception e) { - - Environment.logError ("Unable to get language strings: " + id, - e); - - onError.actionPerformed (new ActionEvent (getUIString (uilanguage,download,actionerror), 0, "error")); - - return; - - } - - if (ls != null) - { - - Date d = ls.getLastModified (); - - if (d == null) - { - - d = ls.getDateCreated (); - - } - - lastMod = d.getTime () + ""; - - } - - String url = Environment.getProperty (Constants.QUOLL_WRITER_GET_UI_LANGUAGE_STRINGS_URL_PROPERTY_NAME); - - url = StringUtils.replaceString (url, - Constants.VERSION_TAG, - Environment.getQuollWriterVersion ().toString ()); - - url = StringUtils.replaceString (url, - Constants.ID_TAG, - id); - - url = StringUtils.replaceString (url, - Constants.LAST_MOD_TAG, - lastMod); - - try - { - - String data = Environment.getUrlFileAsString (new URL (Environment.getQuollWriterWebsite () + "/" + url)); - - if (data.startsWith (Constants.JSON_RETURN_PREFIX)) - { - - data = data.substring (Constants.JSON_RETURN_PREFIX.length ()); - - } - - if (data.trim ().length () == 0) - { - - Environment.logError ("No language strings data available for: " + id + ", " + Environment.getQuollWriterVersion ()); - - onError.actionPerformed (new ActionEvent (getUIString (uilanguage,download,actionerror), 0, "error")); - - return; - - } - - // Will be a collection. - Collection col = null; - - try - { - - col = (Collection) JSONDecoder.decode (data); - - } catch (Exception e) { - - Environment.logError ("Unable to decode language strings data for id: " + id + ", " + Environment.getQuollWriterVersion (), - e); - - onError.actionPerformed (new ActionEvent (getUIString (uilanguage,download,actionerror), 0, "error")); - - return; - - } - - Iterator iter = col.iterator (); - - int updated = 0; - - while (iter.hasNext ()) - { - - Map m = (Map) iter.next (); - - String id = (String) m.get (":id"); - - if (id == null) - { - - throw new GeneralException ("No id found."); - - } - - updated++; - - File f = Environment.getUILanguageStringsFile (id); - - Writer out = new BufferedWriter (new OutputStreamWriter (new FileOutputStream (f), - StandardCharsets.UTF_8)); - - char[] chars = JSONEncoder.encode (m).toCharArray (); - - out.write (chars, 0, chars.length); - out.flush (); - out.close (); - - } - - onComplete.actionPerformed (new ActionEvent (this, updated, "success")); - - } catch (Exception e) { - - Environment.logError ("Unable to get user interface files for: " + id + ", " + Environment.getQuollWriterVersion (), - e); - - onError.actionPerformed (new ActionEvent (getUIString (uilanguage,download,actionerror), 0, "error")); - - } - - } - - }, - 1 * Constants.SEC_IN_MILLIS, - -1); - - } - - public static Set getAllUILanguageStrings () - { - - return Environment.getAllUILanguageStrings (null); - - } - - public static Set getAllUILanguageStrings (Version ver) - { - - Set ret = new LinkedHashSet<> (); - - File[] files = Environment.getUILanguageStringsDir ().listFiles (); - - if (files == null) - { - - return ret; - - } - - for (int i = 0; i < files.length; i++) - { - - File f = files[i]; - - if (f.isFile ()) - { - - try - { - - LanguageStrings ls = new LanguageStrings (f); - - if (ver != null) - { - - if (!ls.getQuollWriterVersion ().equals (ver)) - { - - continue; - - } - - } - - ret.add (ls); - - } catch (Exception e) { - - Environment.logError ("Unable to create strings from: " + f, - e); - - // Delete the file. - f.delete (); - - } - - } - - } - - return ret; - - } - - public static File getUILanguageStringsFile (String id) - { - - return new File (Environment.getUILanguageStringsDir (), - id); - - } - - public static File getUserUILanguageStringsFile (Version qwVersion, - String id) - { - - if (id.equals (LanguageStrings.ENGLISH_ID)) - { - - id = id.substring (1); - - } - - return new File (Environment.getUserUILanguageStringsDir (qwVersion), - id); - - } - - public static File getUserUILanguageStringsFile (LanguageStrings ls) - { - - return Environment.getUserUILanguageStringsFile (ls.getQuollWriterVersion (), - ls.getId ()); - - } - - private static File getUserDefaultProjectPropertiesFile () - { - - return new File (Environment.getUserQuollWriterDir () + "/" + Constants.DEFAULT_PROJECT_PROPERTIES_FILE_NAME); - - } - - public static AbstractProjectViewer getProjectViewerForType (Project p) - throws Exception - { - - AbstractProjectViewer v = null; - - if (p.getType ().equals (Project.NORMAL_PROJECT_TYPE)) - { - - v = new ProjectViewer (); - - } - - if (p.getType ().equals (Project.EDITOR_PROJECT_TYPE)) - { - - v = new EditorProjectViewer (); - - } - - if (p.getType ().equals (Project.WARMUPS_PROJECT_TYPE)) - { - - v = new WarmupsViewer (); - - } - - if (v == null) - { - - throw new GeneralException ("Project type: " + - p.getType () + - " is not supported."); - - } - - v.init (); - - return v; - - } - - public static AbstractProjectViewer getProjectViewerForType (ProjectInfo p) - throws Exception - { - - AbstractProjectViewer v = null; - - if (p.getType ().equals (Project.NORMAL_PROJECT_TYPE)) - { - - v = new ProjectViewer (); - - } - - if (p.getType ().equals (Project.EDITOR_PROJECT_TYPE)) - { - - v = new EditorProjectViewer (); - - } - - if (p.getType ().equals (Project.WARMUPS_PROJECT_TYPE)) - { - - v = new WarmupsViewer (); - - } - - if (v == null) - { - - throw new GeneralException ("Project type: " + - p.getType () + - " is not supported."); - - } - - v.init (); - - return v; - - } - - public static String getButtonLabel (String preferredValue, - String id) - { - - if (preferredValue != null) - { - - return preferredValue; - - } - - return Environment.getButtonLabel (id); - - } - - public static String getButtonLabel (String id) - { - - if (!id.startsWith (Constants.BUTTON_LABEL_ID_PREFIX)) - { - - return id; - - } - - - return Environment.getUIString (LanguageStrings.buttons, - id); - - } - - private static void initProjectsDBFromProjectsFile () - throws Exception - { - - File f = new File (Environment.getUserQuollWriterDir () + "/" + Constants.PROJECTS_FILE_NAME); - - if (!f.exists ()) - { - - return; - - } - - // Get the projects file. - Element root = JDOMUtils.getFileAsElement (f, - Environment.GZIP_EXTENSION); - - List pels = JDOMUtils.getChildElements (root, - Project.OBJECT_TYPE, - false); - - for (int i = 0; i < pels.size (); i++) - { - - Element pEl = (Element) pels.get (i); - - Project p = null; - - try - { - - p = new Project (pEl); - - } catch (Exception e) { - - Environment.logError ("Unable to convert element: " + - JDOMUtils.getPath (pEl) + - " to a project", - e); - - continue; - - } - - ProjectInfo pi = null; - - // Try and load the project. - try - { - - pi = new ProjectInfo (p); - - ObjectManager om = Environment.getProjectObjectManager (pi, - null); - - // Now deal with the real project. - pi = new ProjectInfo (om.getProject ()); - - pi.setEncrypted (p.isEncrypted ()); - pi.setNoCredentials (p.isNoCredentials ()); - - om.closeConnectionPool (); - - } catch (Exception e) { - - Environment.logError ("Unable to load project: " + - p, - e); - - } - - if (pi == null) - { - - try - { - - pi = new ProjectInfo (p); - - } catch (Exception e) { - - Environment.logError ("Unable to convert project: " + - p + - " to a project info", - e); - - continue; - - } - - } - - try - { - - Environment.projectInfoManager.saveObject (pi, - null); - - } catch (Exception e) { - - Environment.logError ("Unable to load project: " + - p + - ", path: " + - JDOMUtils.getPath (pEl) + - " into the project db", - e); - - } - - } - - // Remove the projects file (rename for now). - f.renameTo (new File (f.getParentFile (), f.getName () + ".old")); - - } - - public static Set getAllProjectInfos (String limitToType) - throws Exception - { - - Set all = new LinkedHashSet (Environment.projectInfoManager.getObjects (ProjectInfo.class, - null, - null, - true)); - - if (limitToType != null) - { - - Set pis = new LinkedHashSet (); - - for (ProjectInfo p : all) - { - - if (p.getType ().equals (limitToType)) - { - - pis.add (p); - - } - - } - - all = pis; - - } - - return all; - - } - - public static Set getAllProjectInfos () - throws Exception - { - - return Environment.getAllProjectInfos (null); - - } - - public static ProjectInfo getWarmupsProject () - throws Exception - { - - Set projs = Environment.getAllProjectInfos (); - - for (ProjectInfo pi : projs) - { - - if (pi.isWarmupsProject ()) - { - - return pi; - - } - - } - - return null; - - } - - public static boolean getPropertyAsBoolean (String name) - { - - return UserProperties.getAsBoolean (name); - //return Environment.userProperties.getPropertyAsBoolean (name); - - } - - public static String getProperty (String name) - { - - return UserProperties.get (name); - //return Environment.userProperties.getProperty (name); - - } - - public static File getUserQuollWriterDir () - { - - File d = new File (System.getProperty ("user.home") + "/" + Constants.QUOLL_WRITER_DIR_NAME + "/"); - - d.mkdirs (); - - return d; - - } -/* - public static File getDictionaryDirectory (String lang) - { - - return new File (Environment.getUserQuollWriterDir ().getPath () + Constants.DICTIONARIES_DIR + lang); - - } - */ - public static File getDictionaryFile (String lang) - { - - return Environment.getUserFile (Constants.DICTIONARIES_DIR + lang + ".zip"); - - } - - public static boolean hasSynonymsDirectory (String lang) - { - - File f = Environment.getUserFile (Constants.THESAURUS_DIR + lang); - - return (f.exists () && f.isDirectory ()); - - } - - public static File getLogDir () - { - - File d = Environment.getUserFile (Constants.LOGS_DIR); - - d.mkdirs (); - - return d; - - } - - public static File getUserFile (String name) - { - - return new File (Environment.getUserQuollWriterDir ().getPath (), name); - - } - - public static File getUserObjectTypeNamesFile () - { - - return Environment.getUserFile (Constants.OBJECT_TYPE_NAMES_FILE_NAME); - - } - - /** - * No longer used, since properties now stored in projects db. - * This is only used for legacy versions that need to port the properties over - * to the new storage method. - */ - private static File getUserPropertiesFile () - { - - return Environment.getUserFile (Constants.PROPERTIES_FILE_NAME); - - } - - public static void saveUserProperties () - throws Exception - { - - Environment.projectInfoManager.setUserProperties (UserProperties.getProperties ());//Environment.userProperties); - - } - - public static void saveDefaultProperties (String objType, - com.gentlyweb.properties.Properties props) - throws Exception - { - - File f = new File (Environment.getUserQuollWriterDir ().getPath () + "/default-" + objType + "-properties.xml"); - - JDOMUtils.writeElementToFile (props.getAsJDOMElement (), - f, - true); - - } - - public static Date parseDate (String d) - { - - if (d == null) - { - - return null; - - } - - try - { - - return Environment.dateFormatter.parse (d); - - } catch (Exception e) { - - // Bugger - Environment.logError ("Unable to parse date: " + - d, - e); - - } - - return null; - - } - - public static String formatDateTime (Date d) - { - - return Environment.formatDate (d) + " " + Environment.formatTime (d); - - } - - public static String formatDate (Date d) - { - - return Environment.dateFormatter.format (d); - - } - - public static String formatTime (Date d) - { - - return Environment.timeFormatter.format (d); - - } - - public static void init () - throws Exception - { - - // Start the timer, it is done here so that any other code that needs it can start running things - // straightaway. - Environment.generalTimer = new ScheduledThreadPoolExecutor (5, - new ThreadFactory () - { - - @Override - public Thread newThread (Runnable r) - { - - Thread t = new Thread (r); - - t.setDaemon (true); - t.setPriority (Thread.MIN_PRIORITY); - t.setName ("Environment-general-" + t.getId ()); - - return t; - - } - - }); - - File f = Environment.getErrorLogFile (); - - f.delete (); - - Environment.errorLog = new Logger (); - Environment.errorLog.initLogFile (f); - - f = Environment.getGeneralLogFile (); - - f.delete (); - - Environment.generalLog = new Logger (); - Environment.generalLog.initLogFile (f); - - f = Environment.getSQLLogFile (); - - f.delete (); - - Environment.sqlLog = new Logger (); - Environment.sqlLog.initLogFile (f); - - Environment.incrStartupProgress (); - - Header.defaultPaintLeftColor = UIUtils.getComponentColor (); //UIUtils.getColor ("#516CA3"); - GradientPanel.defaultPaintLeftColor = UIUtils.getComponentColor (); //UIUtils.getColor ("#516CA3"); - Header.defaultPaintRightColor = UIUtils.getComponentColor (); //UIUtils.getColor ("#516CA3"); - GradientPanel.defaultPaintRightColor = UIUtils.getComponentColor (); //UIUtils.getColor ("#516CA3"); - Header.defaultTitleColor = UIUtils.getTitleColor (); - - Environment.isWindows = System.getProperty ("os.name").startsWith ("Windows"); - - Environment.isMac = System.getProperty ("os.name").startsWith ("Mac"); - - Environment.isLinux = System.getProperty ("os.name").startsWith ("Linux"); - - //System.setErr (Environment.nullOut); - //System.setOut (Environment.nullOut); - - // Setup our stream handler for the objectref protocol. - URL.setURLStreamHandlerFactory (new ObjectRefURLStreamHandlerFactory ()); - - Environment.dateFormatter = new SimpleDateFormat ("d MMM yyyy"); - Environment.timeFormatter = new SimpleDateFormat ("HH:mm"); - - UIManager.put("SplitPane.background", UIUtils.getComponentColor ()); - UIManager.put("TabbedPane.contentBorderInsets", new Insets(0, 0, 1, 0)); - //UIManager.put("TabbedPane.tabInsets", new Insets(0, 5, 0, 0)); - UIManager.put("Tree.selectionBackground", UIUtils.getColor ("#aaaaaa"));//UIUtils.getTitleColor ()); - UIManager.put("SplitPane.shadow", UIUtils.getColor ("#aaaaaa")); - UIManager.put("Tree.textForeground", UIUtils.getTitleColor ()); - UIManager.put("Tree.rowHeight", 0); - UIManager.put("Tree.leftChildIndent", 6); - UIManager.put("ProgressBar.cellSpacing", 0); - UIManager.put("PopupMenu.background", UIUtils.getComponentColor ()); - UIManager.put("PopupMenu.foreground", UIUtils.getTitleColor ()); - - if (Environment.isWindows) - { - - try - { - - com.jgoodies.looks.Options.setUseSystemFonts (true); - - UIManager.setLookAndFeel (new WindowsLookAndFeel ()); - - } catch (Exception e) - { - - Environment.logError ("Unable to set laf to: " + - WindowsLookAndFeel.class.getName (), - e); - - } - - } - - System.setProperty ("swing.aatext", - "true"); - - System.setProperty ("aawt.useSystemAAFontSettings", - "true"); - - // Remove border around splitpane divider. - UIManager.put ("SplitPaneDivider.border", - BorderFactory.createEmptyBorder ()); - - UIManager.put ("Button.margin", - new java.awt.Insets (3, - 3, - 3, - 3)); - - // Try and get a lock on the file. - File l = new File (Environment.getUserQuollWriterDir (), - "___quollwriter_lock.lock"); - - FileChannel ch = new RandomAccessFile (l, "rw").getChannel (); - - FileLock lock = ch.tryLock (); - - if (lock == null) - { - - throw new OverlappingFileLockException (); - - } - - Environment.lock = lock; - - l.deleteOnExit (); - - Environment.appVersion = new Version (Environment.getResourceFileAsString (Constants.VERSION_FILE).trim ()); - - try - { - - Environment.schemaVersion = Integer.parseInt (Environment.getResourceFileAsString (Constants.SCHEMA_VERSION_FILE).trim ()); - - } catch (Exception e) - { - - // Ignore. - - } - - try - { - - Environment.projectInfoSchemaVersion = Integer.parseInt (Environment.getResourceFileAsString (Constants.PROJECT_INFO_SCHEMA_VERSION_FILE).trim ()); - - } catch (Exception e) - { - - // Ignore. - - } - - com.gentlyweb.properties.Properties sysProps = new com.gentlyweb.properties.Properties (Environment.class.getResourceAsStream (Constants.DEFAULT_PROPERTIES_FILE), - null); - - sysProps.setId ("system"); - - // Temporarily set the user properties to the system properties. - UserProperties.init (sysProps); - //Environment.userProperties = sysProps; - - com.gentlyweb.properties.Properties userProps = sysProps; - - Environment.incrStartupProgress (); - - Environment.defaultUILanguageStrings = new LanguageStrings (Environment.getResourceFileAsString (Constants.DEFAULT_UI_LANGUAGE_STRINGS_FILE)); -/* - Map> errs = Environment.defaultUILanguageStrings.getErrors (); - - for (LanguageStrings.Value v : errs.keySet ()) - { - - System.out.println (v); - System.out.println (errs.get (v)); - System.out.println (); - } -*/ - Environment.uiLanguageStrings = Environment.defaultUILanguageStrings; - - // Load the default object type names. - // Object type names may be needed when initing the legacy object types. - /* - try - { - - Environment.loadObjectTypeNames (JDOMUtils.getStringAsElement (Environment.getResourceFileAsString (Constants.DEFAULT_OBJECT_TYPE_NAMES_FILE))); - - } catch (Exception e) { - - Environment.logError ("Unable to load default object type names from resource file: " + - Constants.DEFAULT_OBJECT_TYPE_NAMES_FILE); - - } -*/ - // See if this is first use. - Environment.isFirstUse = (Environment.getProjectInfoSchemaVersion () == 0); - - // Get the username and password. - String username = Environment.getProperty (Constants.DB_USERNAME_PROPERTY_NAME); - String password = Environment.getProperty (Constants.DB_PASSWORD_PROPERTY_NAME); - - Environment.projectInfoManager = new ProjectInfoObjectManager (); - - Environment.projectInfoManager.init (Environment.getProjectInfoDBFile (), - username, - password, - null, - Environment.getProjectInfoSchemaVersion ()); - - try - { - - userProps = Environment.projectInfoManager.getUserProperties (); - - } catch (Exception e) { - - Environment.logError ("Unable to load user properties", - e); - - } - - if (userProps == null) - { - - // Check for legacy properties.xml. Pre v2.5. - File pf = Environment.getUserPropertiesFile (); - - if (pf.exists ()) - { - - try - { - - userProps = new com.gentlyweb.properties.Properties (pf, - Environment.GZIP_EXTENSION); - - } catch (Exception e) - { - - Environment.logError ("Unable to load user properties from file: " + - pf, - e); - - } - - pf.delete (); - - } - - } - - if (userProps == null) - { - - userProps = new com.gentlyweb.properties.Properties (); - - } - - if (userProps != sysProps) - { - - userProps.setId ("user"); - - userProps.setParentProperties (sysProps); - - } - - if (userProps == null) - { - - // If this is legacy and we can't load the properties file (is corrupted) then - // use the system properties as the properties. - userProps = sysProps; - - } - - UserProperties.init (userProps); - - // Do a save here so that if we are loading for the first time they will be saved. - try - { - - Environment.saveUserProperties (); - - } catch (Exception e) { - - Environment.logError ("Unable to save user properties", - e); - - } - - // Load the user default, if appropriate. - final String uilangid = UserProperties.get (Constants.USER_UI_LANGUAGE_PROPERTY_NAME); - - if (uilangid != null) - { - - if (!LanguageStrings.isEnglish (uilangid)) - { - - LanguageStrings ls = Environment.getUILanguageStrings (uilangid); - - if ((ls == null) - || - // Have we updated QW and need to get newer versions? - ((ls != null) - && - (ls.getQuollWriterVersion ().isNewer (Environment.getQuollWriterVersion ())) - ) - ) - { - - // Something has gone wrong, try and download again. - Environment.downloadUILanguageFile (uilangid, - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - try - { - - Environment.setUILanguage (uilangid); - - } catch (Exception e) { - - Environment.logError ("Unable to set ui language to: " + uilangid, - e); - - UIUtils.showErrorMessage (null, - getUIString (uilanguage,set,downloading,errors,download)); - //"Warning! Quoll Writer has been unable to re-download the User Interface strings for your selected language. There may be multiple reasons for this, such as a connection error to the internet or that the Quoll Writer server is unavailable.

It is recommended that you either restart Quoll Writer to try again or try downloading the strings from the Options panel.

In the interim Quoll Writer has fallen back to using English."); - - } - - UIUtils.showMessage (null, - getUIString (uilanguage,set,downloading,redownload,confirmpopup,title), - //"Language strings re-downloaded", - getUIString (uilanguage,set,downloading,redownload,confirmpopup,text), - //"Quoll Writer has re-downloaded the User Interface language strings you are using because they were missing from your local system. In the interim the User Interface has fallen back to using English.

To return to using your selected language Quoll Writer must be restarted.", - null, - null); - - } - - }, - // On error. - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - UIUtils.showErrorMessage (null, - getUIString (uilanguage,set,downloading,redownload,actionerror)); - //"Warning! Quoll Writer has been unable to re-download the User Interface strings for your selected language. There may be multiple reasons for this, such as a connection error to the internet or that the Quoll Writer server is unavailable.

It is recommended that you either restart Quoll Writer to try again or try downloading the strings from the Options panel.

In the interim Quoll Writer has fallen back to using English."); - - } - - }); - - } else { - - Environment.uiLanguageStrings = ls; - - if (!ls.isUser ()) - { - - // See if there is an update to the strings. - Environment.downloadUILanguageFile (uilangid, - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - if (ev.getID () > 0) - { - - try - { - - Environment.setUILanguage (uilangid); - - } catch (Exception e) { - - Environment.logError ("Unable to set ui language to: " + uilangid, - e); - - UIUtils.showErrorMessage (null, - getUIString (uilanguage,set,downloading,update,actionerror)); - //"Warning! Quoll Writer has been unable to update the User Interface strings for your selected language. There may be multiple reasons for this, such as a connection error to the internet or that the Quoll Writer server is unavailable.

It is recommended that you either restart Quoll Writer to try again or try downloading the strings from the Options panel.

In the interim Quoll Writer has fallen back to using English."); - - } - - UIUtils.showMessage (null, - getUIString (uilanguage,set,downloading,update,confirmpopup,title), - //"Language strings updated", - getUIString (uilanguage,set,downloading,update,confirmpopup,text), - //"Quoll Writer has updated the User Interface language strings you are using because a new version was available.

To make full use of the updated strings Quoll Writer must be restarted.", - null, - null); - - } - - } - - }, - // On error. - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - } - - }); - - } - - } - - } - - } - - try - { - - Environment.loadUserObjectTypeNames (); - - } catch (Exception e) { - - Environment.logError ("Unable to load user object type names.", - e); - - } - - // Add a property listener for name changes to user config object types. - Environment.userConfigurableObjectTypeNameListener = new PropertyChangedListener () - { - - @Override - public void propertyChanged (PropertyChangedEvent ev) - { - - UserConfigurableObjectType type = (UserConfigurableObjectType) ev.getSource (); - - String id = type.getObjectTypeId (); - - Environment.objectTypeNamesSingular.put (id, - type.getObjectTypeName ()); - - Environment.objectTypeNamesPlural.put (id, - type.getObjectTypeNamePlural ()); - - } - - }; - - // Init our legacy object types, if needed. - Environment.projectInfoManager.initLegacyObjectTypes (); - - // The user session needs the properties. - Environment.userSession = new UserSession (); - - // Override the debug mode. - /* - if (UserProperties.get (Constants.DEBUG_MODE_PROPERTY_NAME) != null) - { - - Environment.setDebugModeEnabled (UserProperties.getAsBoolean (Constants.DEBUG_MODE_PROPERTY_NAME)); - - } -*/ - - // Get the system default project properties. - com.gentlyweb.properties.Properties sysDefProjProps = new com.gentlyweb.properties.Properties (Environment.class.getResourceAsStream (Constants.DEFAULT_PROJECT_PROPERTIES_FILE), - UserProperties.getProperties ()); - - File defUserPropsFile = Environment.getUserDefaultProjectPropertiesFile (); - - if (defUserPropsFile.exists ()) - { - - com.gentlyweb.properties.Properties userDefProjProps = new com.gentlyweb.properties.Properties (defUserPropsFile, - Environment.GZIP_EXTENSION); - - userDefProjProps.setParentProperties (sysDefProjProps); - - sysDefProjProps = userDefProjProps; - - } - - // Load the default project properties. - Environment.defaultObjectProperties.put (Project.OBJECT_TYPE, - sysDefProjProps); - - // Create the text properties, they are derived from the user properties so need to be done after - // the user props are inited. - Environment.projectTextProps = new ProjectTextProperties (); - - Environment.fullScreenTextProps = new FullScreenTextProperties (); - - Environment.playSoundOnKeyStroke = UserProperties.getAsBoolean (Constants.PLAY_SOUND_ON_KEY_STROKE_PROPERTY_NAME); - - String sf = UserProperties.get (Constants.KEY_STROKE_SOUND_FILE_PROPERTY_NAME); - - try - { - - File ksf = null; - - if (sf != null) - { - - ksf = new File (sf); - - } - - Environment.setKeyStrokeSoundFile (ksf); - - } catch (Exception e) - { - - Environment.logError ("Unable to get sound file to play on key stroke using file: " + sf, - e); - - } - - Environment.incrStartupProgress (); - -/* - Environment.userPropertyHandlers.put (Constants.OBJECT_TYPES_PROPERTY_NAME, - new UserPropertyHandler (Constants.OBJECT_TYPES_PROPERTY_NAME, - null)); -*/ - Environment.userPropertyHandlers.put (Constants.NOTE_TYPES_PROPERTY_NAME, - new UserPropertyHandler (Constants.NOTE_TYPES_PROPERTY_NAME, - null, - notetypes,defaulttypes)); - Environment.userPropertyHandlers.put (Constants.PROJECT_STATUSES_PROPERTY_NAME, - new UserPropertyHandler (Constants.PROJECT_STATUSES_PROPERTY_NAME, - null, - allprojects,defaultstatuses)); - Environment.userPropertyHandlers.put (Constants.TAGS_PROPERTY_NAME, - new UserPropertyHandler (Constants.TAGS_PROPERTY_NAME, - null, - // Prevents the compiler whining... - (String[]) null)); - - try - { - - Prompts.init (); - - } catch (Exception e) - { - - Environment.logError ("Unable to init prompts", - e); - - } - - try - { - - RuleFactory.init (); - - } catch (Exception e) - { - - Environment.logError ("Unable to init rule factory", - e); - - } - - try - { - - Environment.achievementsManager = new AchievementsManager (); - - } catch (Exception e) { - - Environment.logError ("Unable to init achievements manager", - e); - - } - - Environment.schedule (new Runnable () - { - - @Override - public void run () - { - - try - { - - Importer.init (); - - } catch (Exception e) { - - Environment.logError ("Unable to init importer", - e); - - } - - } - - }, - 1 * Constants.SEC_IN_MILLIS, - -1); - - Environment.incrStartupProgress (); - - KeyboardFocusManager.getCurrentKeyboardFocusManager ().addKeyEventPostProcessor (new java.awt.KeyEventPostProcessor () - { - - public boolean postProcessKeyEvent (KeyEvent ev) - { - - if (!(ev.getSource () instanceof JComponent)) - { - - return true; - - } - - final JComponent focused = (JComponent) ev.getSource (); - - Environment.scrollIntoView (focused); - - return true; - - } - }); - - try - { - - // Get the user editor properties. - com.gentlyweb.properties.Properties eprops = new com.gentlyweb.properties.Properties (); - - File edPropsFile = Environment.getUserEditorsPropertiesFile (); - - if (edPropsFile.exists ()) - { - - eprops = new com.gentlyweb.properties.Properties (edPropsFile, - Environment.GZIP_EXTENSION); - - } - - eprops.setParentProperties (UserProperties.getProperties ()); - - EditorsEnvironment.init (eprops); - - } catch (Exception e) { - - Environment.logError ("Unable to init editors environment", - e); - - } - - // Pre 2.4. - // See if there is a projects.xml file, if so load the db. - try - { - - Environment.initProjectsDBFromProjectsFile (); - - } catch (Exception e) { - - Environment.logError ("Unable to init project info from projects file", - e); - - } - - if (Environment.isFirstUse) - { - - Environment.isFirstUse = (Environment.getAllProjectInfos ().size () == 0); - - } - - Environment.targets = new TargetsData (UserProperties.getProperties ()); - - Environment.addStartupProgressListener (new PropertyChangedListener () - { - - public void propertyChanged (PropertyChangedEvent ev) - { - - if (Environment.isStartupComplete ()) - { - - Environment.userSession.start (new Date ()); - - // See if we should be doing a warmup exercise. - if (UserProperties.getAsBoolean (Constants.DO_WARMUP_ON_STARTUP_PROPERTY_NAME)) - { - - UIUtils.doLater (new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - AbstractViewer viewer = Environment.getFocusedViewer (); - - if (viewer != null) - { - - viewer.showWarmupPromptSelect (); - - viewer.fireProjectEvent (Warmup.OBJECT_TYPE, - ProjectEvent.WARMUP_ON_STARTUP); - - } - - } - - }); - - } - - Date d = new Date (System.currentTimeMillis () + (Constants.DAY_IN_MILLIS)); - - d = Utils.zeroTimeFields (d); - - Environment.schedule (new Runnable () - { - - @Override - public void run () - { - - try - { - - Environment.projectInfoManager.addSession (Environment.userSession.createSnapshot ()); - - } catch (Exception e) { - - Environment.logError ("Unable to take session snapshot", - e); - - } - - } - - }, - d.getTime (), - // Run every 24 hours. It will drift over the days but not by much. - Constants.DAY_IN_MILLIS); - - Environment.schedule (new Runnable () - { - - @Override - public void run () - { - - java.util.List prefix = new ArrayList (); - prefix.add (LanguageStrings.targets); - prefix.add (LanguageStrings.types); - - Set met = new LinkedHashSet (); - int sessWC = 0; - - try - { - - if (!Environment.targets.isShowMessageWhenSessionTargetReached ()) - { - - return; - - } - - sessWC = Environment.userSession.getCurrentSessionWordCount (); - - // See if the user session has exceeded the session count. - if ((sessWC >= Environment.targets.getMySessionWriting ()) - && - (Environment.userSession.shouldShowSessionTargetReachedPopup ()) - ) - { - - met.add (Environment.getUIString (prefix, - LanguageStrings.session)); - //"Session"); - - Environment.userSession.shownSessionTargetReachedPopup (); - - } - - } catch (Exception e) { - - Environment.logError ("Unable show session target reached popup", - e); - - } - - // Check for the daily count. - // Get all sessions for today. - try - { - - // The order is important here, the userSession check is cheaper - // than the past sessions check since it doesn't require a db lookup. - if ((Environment.userSession.shouldShowDailyTargetReachedPopup ()) - && - (Environment.getPastSessionsWordCount (0) >= Environment.targets.getMyDailyWriting ()) - ) - { - - met.add (Environment.getUIString (prefix, - LanguageStrings.daily)); - //"Daily"); - - Environment.userSession.shownDailyTargetReachedPopup (); - - } - - } catch (Exception e) { - - Environment.logError ("Unable to get past session word counts", - e); - - } - - // Get all sessions for this week. - try - { - - // We perform the cheap check here since it will prevent the extra work - // with the calendar and db from having to be performed. - if (Environment.userSession.shouldShowWeeklyTargetReachedPopup ()) - { - - GregorianCalendar gc = new GregorianCalendar (); - - int fd = gc.getFirstDayOfWeek (); - - int cd = gc.get (Calendar.DAY_OF_WEEK); - - int diff = cd - fd; - - if (diff < 0) - { - - diff += 7; - - } - - if (Environment.getPastSessionsWordCount (diff) >= Environment.targets.getMyWeeklyWriting ()) - { - - met.add (Environment.getUIString (prefix, - LanguageStrings.weekly)); - //"Weekly"); - - Environment.userSession.shownWeeklyTargetReachedPopup (); - - } - - } - - } catch (Exception e) { - - Environment.logError ("Unable to get past session word counts", - e); - - } - - // Get all sessions for this month. - try - { - - // As above, do the cheap check first to prevent the extra work from - // being done. - if (Environment.userSession.shouldShowMonthlyTargetReachedPopup ()) - { - - GregorianCalendar gc = new GregorianCalendar (); - - int fd = gc.getFirstDayOfWeek (); - - int cd = gc.get (Calendar.DAY_OF_MONTH); - - int diff = cd - fd; - - if (Environment.getPastSessionsWordCount (diff) >= Environment.targets.getMyMonthlyWriting ()) - { - - AbstractViewer viewer = Environment.getFocusedViewer (); - - met.add (Environment.getUIString (prefix, - LanguageStrings.monthly)); - //"Monthly"); - - Environment.userSession.shownMonthlyTargetReachedPopup (); - - } - - } - - } catch (Exception e) { - - Environment.logError ("Unable to get past session word counts", - e); - - } - - try - { - - if (met.size () > 0) - { - - StringBuilder b = new StringBuilder (); - - for (String m : met) - { - - b.append (String.format ("
  • %s
  • ", - m)); - - } - - AbstractViewer viewer = Environment.getFocusedViewer (); - - UIUtils.showMessage ((PopupsSupported) viewer, - Environment.getUIString (LanguageStrings.targets, - LanguageStrings.writingtargetreachedpopup, - LanguageStrings.title), - //"Writing targets reached", - String.format (Environment.getUIString (LanguageStrings.targets, - LanguageStrings.writingtargetreachedpopup, - LanguageStrings.text), - //"You have reached the following writing targets by writing %s words.
      %s
    Well done and keep it up!", - Environment.formatNumber (sessWC), - b.toString ()), - UIUtils.defaultLeftCornerShowPopupAt); - - - } - - } catch (Exception e) { - - Environment.logError ("Unable to show writing targets reached popup", - e); - - } - - } - - }, - 5 * Constants.SEC_IN_MILLIS, - 5 * Constants.SEC_IN_MILLIS); - - } - - } - - }); - - } - - public static File getUserEditorsPropertiesFile () - { - - return Environment.getUserFile (Constants.EDITORS_PROPERTIES_FILE_NAME); - - } - - private static int getPastSessionsWordCount (int daysPast) - throws GeneralException - { - - List sess = Environment.projectInfoManager.getSessions (daysPast); - - int c = 0; - - Session last = null; - - for (Session s : sess) - { - - c += s.getWordCount (); - - last = s; - - } - - c += Environment.userSession.getCurrentSessionWordCount (); - - return c; - - } - - public static UserPropertyHandler getUserPropertyHandler (String userProp) - { - - return Environment.userPropertyHandlers.get (userProp); - - } - - public static int getJavaVersion () - { - - String[] els = System.getProperty("java.version").split("\\."); - - return Integer.parseInt (els[1]); - - } - - public static String getQuollWriterWebsiteLink (String url, - String linkText) - { - - if (linkText == null) - { - - return String.format ("%s:%s", - Constants.QUOLLWRITER_PROTOCOL, - url); - - } - - return String.format ("%s", - Constants.QUOLLWRITER_PROTOCOL, - url, - linkText); - - } - - public static String getQuollWriterHelpLink (String url, - String linkText) - { - - if (linkText == null) - { - - return String.format ("%s:%s", - Constants.HELP_PROTOCOL, - url); - - } - - return String.format ("%s", - Constants.HELP_PROTOCOL, - url, - linkText); - - } - - public static String getQuollWriterWebsite () - { - - if (Environment.isDebugModeEnabled ()) - { - - return Environment.getProperty (Constants.QUOLL_WRITER_DEBUG_WEBSITE_PROPERTY_NAME); - - } else { - - return Environment.getProperty (Constants.QUOLL_WRITER_WEBSITE_PROPERTY_NAME); - - } - - } - - public static String getWordTypes (String word, - String language) - throws GeneralException - { - - SynonymProvider sp = Environment.getSynonymProvider (language); - - if (sp != null) - { - - return sp.getWordTypes (word); - - } - - return null; - - } - - public static DictionaryProvider2 getDefaultDictionaryProvider () - throws Exception - { - - String lang = UserProperties.get (Constants.DEFAULT_SPELL_CHECK_LANGUAGE_PROPERTY_NAME); - - if (lang == null) - { - - lang = Constants.ENGLISH; - - } - - return new UserDictionaryProvider (lang); - -/* - if (Environment.defaultDictProv == null) - { - - String lang = UserProperties.get (Constants.DEFAULT_SPELL_CHECK_LANGUAGE_PROPERTY_NAME); - - if (lang == null) - { - - lang = Constants.ENGLISH; - - } - - Environment.defaultDictProv = new DictionaryProvider (lang, - null); - - } - - return Environment.defaultDictProv; -*/ - } - - public static SynonymProvider getSynonymProvider (String language) - throws GeneralException - { - - if (language == null) - { - - language = Constants.ENGLISH; - - } - - if (Environment.isEnglish (language)) - { - - language = Constants.ENGLISH; - - } - - // For now, until we are able to support other languages return null for non-english. - if (!language.equals (Constants.ENGLISH)) - { - - return null; - - } - - SynonymProvider prov = Environment.synonymProviders.get (language.toLowerCase ()); - - if (prov != null) - { - - return prov; - - } - - String synCl = Environment.getProperty (Constants.SYNONYM_PROVIDER_CLASS_PROPERTY_NAME); - - if (synCl != null) - { - - Class c = null; - - try - { - - c = Class.forName (synCl); - - } catch (Exception e) - { - - throw new GeneralException ("Unable to load synonym provider class: " + - synCl + - " specified by property: " + - Constants.SYNONYM_PROVIDER_CLASS_PROPERTY_NAME, - e); - - } - - if (!SynonymProvider.class.isAssignableFrom (c)) - { - - throw new GeneralException ("Expected synonym provider class: " + - synCl + - " specified by property: " + - Constants.SYNONYM_PROVIDER_CLASS_PROPERTY_NAME + - " to implement interface: " + - SynonymProvider.class.getName ()); - - } - - // Create the instance. - try - { - - prov = (SynonymProvider) c.newInstance (); - - } catch (Exception e) - { - - // Record the error but don't barf, it's just a service that isn't available - Environment.logError ("Unable to create new instance of synonym provider class: " + - synCl + - " specified by property: " + - Constants.SYNONYM_PROVIDER_CLASS_PROPERTY_NAME, - e); - - } - - if (!prov.isLanguageSupported (language)) - { - - return null; - - } - - try - { - - - - prov.init (language); - - } catch (Exception e) { - - Environment.logError ("Unable to init synonym provider instance for language: " + - language + - ", class: " + - synCl + - ", specified by property: " + - Constants.SYNONYM_PROVIDER_CLASS_PROPERTY_NAME, - e); - - } - - Environment.synonymProviders.put (language.toLowerCase (), - prov); - - } - - return prov; - - } - - public static void scrollIntoView (JComponent c) - { - - if (c == null) - { - - return; - - } - - if (!(c.getParent () instanceof JComponent)) - { - - return; - - } - - JComponent parent = (JComponent) c.getParent (); - - if (!(parent instanceof JComponent)) - { - - return; - - } - - if (parent == null) - { - - return; - - } - - if (parent instanceof JViewport) - { - - parent = (JComponent) parent.getParent (); - - } - - parent.scrollRectToVisible (c.getBounds ()); - - } - - public static boolean isEnglish (String language) - { - - if (language == null) - { - - return false; - - } - - return Constants.ENGLISH.equalsIgnoreCase (language) - || - Constants.BRITISH_ENGLISH.equalsIgnoreCase (language) - || - Constants.US_ENGLISH.equalsIgnoreCase (language); - - } - - public static void resetObjectTypeNamesToDefaults () - { - - Environment.objectTypeNamesSingular.clear (); - Environment.objectTypeNamesPlural.clear (); -/* - // Load the default object type names. - try - { - - Environment.loadObjectTypeNames (JDOMUtils.getStringAsElement (Environment.getResourceFileAsString (Constants.DEFAULT_OBJECT_TYPE_NAMES_FILE))); - - } catch (Exception e) { - - Environment.logError ("Unable to load default object type names from resource file: " + - Constants.DEFAULT_OBJECT_TYPE_NAMES_FILE); - - } -*/ - File otf = Environment.getUserObjectTypeNamesFile (); - - // Remove the file. - otf.delete (); - - otf = Environment.getUserFile (Constants.LEGACY_OBJECT_TYPE_NAMES_FILE_NAME); - - otf.delete (); - - Environment.loadUserConfigurableObjectTypeNames (); - - // Load the - UserConfigurableObjectType chapterType = Environment.getUserConfigurableObjectType (Chapter.OBJECT_TYPE); - - if (chapterType != null) - { - - Environment.objectTypeNamesPlural.put (Chapter.OBJECT_TYPE, - getUIString (objectnames,plural,Chapter.OBJECT_TYPE)); - Environment.objectTypeNamesSingular.put (Chapter.OBJECT_TYPE, - getUIString (objectnames,singular,Chapter.OBJECT_TYPE)); - - } - - - } - - private static void loadUserObjectTypeNames () - throws Exception - { - - File f = Environment.getUserObjectTypeNamesFile (); - - if (f.exists ()) - { - - // Use this one. - Map t = (Map) JSONDecoder.decode (IOUtils.getFile (f)); - - Environment.objectTypeNamesSingular = (Map) t.get (LanguageStrings.singular); - Environment.objectTypeNamesPlural = (Map) t.get (LanguageStrings.plural); - - } else { - - // Legacy: pre 2.6.2 - f = Environment.getUserFile (Constants.LEGACY_OBJECT_TYPE_NAMES_FILE_NAME); - - if (f.exists ()) - { - - Environment.loadLegacyObjectTypeNames (JDOMUtils.getStringAsElement (IOUtils.getFile (f))); - - Environment.setUserObjectTypeNames (Environment.objectTypeNamesSingular, - Environment.objectTypeNamesPlural); - - f.delete (); - - } - - } - - Environment.loadUserConfigurableObjectTypeNames (); - - } - - private static void loadUserConfigurableObjectTypeNames () - { - - Map singular = Environment.objectTypeNamesSingular; - Map plural = Environment.objectTypeNamesPlural; - - // Load the names from the configurable types. - for (UserConfigurableObjectType t : Environment.userConfigObjTypes) - { - - if (t.getUserObjectType () != null) - { -/* - plural.put (t.getUserObjectType (), - t.getObjectTypeNamePlural ()); - - singular.put (t.getUserObjectType (), - t.getObjectTypeName ()); -*/ - } else { - - if (t.isAssetObjectType ()) - { - - plural.put ("asset:" + t.getKey (), - t.getObjectTypeNamePlural ()); - singular.put ("asset:" + t.getKey (), - t.getObjectTypeName ()); - - } - - } - - } -/* - // TODO: Fix this, special for now. - UserConfigurableObjectType chapterType = Environment.getUserConfigurableObjectType (Chapter.OBJECT_TYPE); - - if (chapterType != null) - { -xxx - plural.put (Chapter.OBJECT_TYPE, - chapterType.getObjectTypeNamePlural ()); - singular.put (Chapter.OBJECT_TYPE, - chapterType.getObjectTypeName ()); - - } -*/ - - } - - private static void loadLegacyObjectTypeNames (Element root) - throws Exception - { - - Map singular = new HashMap (); - Map plural = new HashMap (); - - List els = JDOMUtils.getChildElements (root, - XMLConstants.object, - false); - - for (int i = 0; i < els.size (); i++) - { - - Element el = (Element) els.get (i); - - String objType = JDOMUtils.getAttributeValue (el, - XMLConstants.type); - - objType = objType.toLowerCase (); - - String s = JDOMUtils.getChildElementContent (el, - XMLConstants.singular, - false); - - if (!s.equals ("")) - { - - singular.put (objType, - s); - - } - - String p = JDOMUtils.getChildElementContent (el, - XMLConstants.plural, - false); - - if (!p.equals ("")) - { - - plural.put (objType, - p); - - } - - } -/* - // Load the names from the configurable types. - for (UserConfigurableObjectType t : Environment.userConfigObjTypes) - { - - if (t.getUserObjectType () != null) - { - - plural.put (t.getUserObjectType (), - t.getObjectTypeNamePlural ()); - - singular.put (t.getUserObjectType (), - t.getObjectTypeName ()); - - } else { - - if (t.isAssetObjectType ()) - { - - plural.put ("asset:" + t.getKey (), - t.getObjectTypeNamePlural ()); - singular.put ("asset:" + t.getKey (), - t.getObjectTypeName ()); - - } - - } - - } - - // TODO: Fix this, special for now. - UserConfigurableObjectType chapterType = Environment.getUserConfigurableObjectType (Chapter.OBJECT_TYPE); - - if (chapterType != null) - { - - plural.put (Chapter.OBJECT_TYPE, - chapterType.getObjectTypeNamePlural ()); - singular.put (Chapter.OBJECT_TYPE, - chapterType.getObjectTypeName ()); - - } -*/ - - Environment.objectTypeNamesSingular.putAll (singular); - Environment.objectTypeNamesPlural.putAll (plural); - - } - - public static URL getSupportUrl (String pagePropertyName) - throws Exception - { - - return Environment.getSupportUrl (pagePropertyName, - null); - - } - - public static URL getSupportUrl (String pagePropertyName, - String parms) - throws Exception - { - - String prefName = Constants.SUPPORT_URL_BASE_PROPERTY_NAME; - - if (Environment.isDebugModeEnabled ()) - { - - prefName = Constants.DEBUG_SUPPORT_URL_BASE_PROPERTY_NAME; - - } - - return new URL (Environment.getProperty (prefName) + Environment.getProperty (pagePropertyName) + (parms != null ? parms : "")); - - } - - public static File getGeneralLogFile () - { - - return new File (Environment.getLogDir ().getPath () + "/" + Constants.GENERAL_LOG_NAME); - - } - - public static File getSQLLogFile () - { - - return new File (Environment.getLogDir ().getPath () + "/" + Constants.SQL_LOG_NAME); - - } - - public static File getErrorLogFile () - { - - return new File (Environment.getLogDir ().getPath () + "/" + Constants.ERROR_LOG_NAME); - - } - - public static File getUserDictionaryFile () - { - - return new File (Environment.getUserQuollWriterDir ().getPath () + "/" + Constants.USER_DICTIONARY_FILE_NAME); - - } - - public static Set getBackgroundImages () - throws Exception - { - - Set ret = new LinkedHashSet (); - - Set bgImages = Environment.getResourceListing (Constants.BACKGROUND_THUMB_IMGS_DIR); - - for (String s : bgImages) - { - - ret.add (new BackgroundImage (s)); - - } - - return ret; - - } - - public static Image getBackgroundImage (String name) - { - - Image im = Environment.backgroundImages.get (name); - - if (im != null) - { - - return im; - - } - - if (name == null) - { - - return null; - - } - - name = Constants.BACKGROUND_IMGS_DIR + name; - - URL url = Environment.class.getResource (name); - - if (url == null) - { - - // Can't find image, log the problem but keep going. - Environment.logError ("Unable to find/load image: " + - name + - ", check images jar to ensure file is present.", - - // Gives a stack trace - new Exception ()); - - return null; - - } - - im = new ImageIcon (url).getImage (); - - Environment.backgroundImages.put (name, - im); - - return im; - - } - - public static Image getBackgroundThumbImage (String name) - { - - if (name == null) - { - - return null; - - } - - name = Constants.BACKGROUND_THUMB_IMGS_DIR + name; - - URL url = Environment.class.getResource (name); - - if (url == null) - { - - // Can't find image, log the problem but keep going. - Environment.logError ("Unable to find/load image: " + - name + - ", check images jar to ensure file is present.", - - // Gives a stack trace - new Exception ()); - - return null; - - } - - return new ImageIcon (url).getImage (); - - } - - public static ImageIcon getAchievementIcon () - { - - URL url = Environment.class.getResource (Constants.ACHIEVEMENT_ICON_FILE); - - if (url == null) - { - - // Can't find image, log the problem but keep going. - Environment.logError ("Unable to find/load achievement image: " + - Constants.ACHIEVEMENT_ICON_FILE + - ", check images jar to ensure file is present.", - - // Gives a stack trace - new Exception ()); - - return null; - - } - - return new ImageIcon (url); - - } - - public static ImageIcon getObjectIcon (String ot, - int iconType) - { - - return Environment.getIcon (ot, - iconType); - - } - - public static ImageIcon getObjectIcon (DataObject d, - int iconType) - { - - String ot = d.getObjectType (); - - if (d instanceof Note) - { - - Note n = (Note) d; - - if (n.isEditNeeded ()) - { - - ot = Constants.EDIT_NEEDED_NOTE_ICON_NAME; - - } - - } - - return Environment.getObjectIcon (ot, - iconType); - - } - - public static int getIconPixelWidthForType (int type) - { - - int size = 16; - - if (type == Constants.ICON_EDITOR_MESSAGE) - { - - size = 20; - - } - - if (type == Constants.ICON_TOOLBAR) - { - - size = 20; - - } - - if (type == Constants.ICON_MENU_INNER) - { - - size = 16; - - } - - if (type == Constants.ICON_PANEL_MAIN) - { - - size = 24; - - } - - if (type == Constants.ICON_NOTIFICATION) - { - - size = 24; - - } - - if (type == Constants.ICON_ACHIEVEMENT_HEADER) - { - - size = 24; - - } - - if (type == Constants.ICON_PANEL_ACTION) - { - - size = 20; - - } - - if (type == Constants.ICON_TITLE_ACTION) - { - - size = 24; - - } - - if (type == Constants.ICON_BG_SWATCH) - { - - size = 37; - - } - - if (type == Constants.ICON_FULL_SCREEN_ACTION) - { - - size = 24; - - } - - if (type == Constants.ICON_TITLE) - { - - size = 24; - - } - - if (type == Constants.ICON_EDITORS_LIST_TAB_HEADER) - { - - size = 24; - - } - - return size; - - } - - public static URL getIconURL (String name, - int type) - //boolean large) - { - - if (name == null) - { - - return null; - - } - - if (name.indexOf ('.') == -1) - { - - int size = Environment.getIconPixelWidthForType (type); - - name = Constants.IMGS_DIR + name + size + ".png"; - - } else - { - - name = Constants.IMGS_DIR + name; - - } - - return Environment.class.getResource (name); - - } - - public static ImageIcon getTypingIcon () - { - - URL url = Environment.class.getResource (Constants.IMGS_DIR + Constants.TYPING_GIF_NAME); - - if (url == null) - { - - if (Environment.isDebugModeEnabled ()) - { - - // Can't find image, log the problem but keep going. - Environment.logError ("Unable to find loading image: " + - Constants.TYPING_GIF_NAME + - ", check images jar to ensure file is present.", - // Gives a stack trace - new Exception ()); - - } - - return null; - - } - - try - { - - // Can't use ImageIO here, won't animate only reads first frame. - return new ImageIcon (url); - - } catch (Exception e) { - - Environment.logError ("Unable to find loading image: " + - Constants.TYPING_GIF_NAME, - e); - - } - - return null; - - } - - public static ImageIcon getLoadingIcon () - { - - URL url = Environment.class.getResource (Constants.IMGS_DIR + Constants.LOADING_GIF_NAME); - - if (url == null) - { - - if (Environment.isDebugModeEnabled ()) - { - - // Can't find image, log the problem but keep going. - Environment.logError ("Unable to find loading image: " + - Constants.LOADING_GIF_NAME + - ", check images jar to ensure file is present.", - // Gives a stack trace - new Exception ()); - - } - - return null; - - } - - try - { - - // Can't use ImageIO here, won't animate only reads first frame. - return new ImageIcon (url); - - } catch (Exception e) { - - Environment.logError ("Unable to find loading image: " + - Constants.LOADING_GIF_NAME, - e); - - } - - return null; - - } - - public static ImageIcon getIcon (String name, - int type) - { - - if (name == null) - { - - return null; - - } - - if (name.equals (Constants.LOADING_GIF_NAME)) - { - - return Environment.getLoadingIcon (); - - } - - URL url = Environment.getIconURL (name, - type); - - if (url == null) - { - - if (Environment.isDebugModeEnabled ()) - { - - // Can't find image, log the problem but keep going. - Environment.logError ("Unable to find/load image: " + - name + - ", type: " + type + - ", check images jar to ensure file is present.", - // Gives a stack trace - new Exception ()); - - } - - return null; - - } - - try - { - - return new ImageIcon (ImageIO.read (url)); - - } catch (Exception e) { - - Environment.logError ("Unable to find/load image: " + - name, - e); - - } - - return null; - - } - - public static ImageIcon getWindowIcon () - { - - return new ImageIcon (Environment.class.getResource (Constants.IMGS_DIR + Constants.WINDOW_ICON_PNG_NAME)); - - } - - public static BufferedImage getNoEditorAvatarImage () - { - - return Environment.getImage (Constants.EDITOR_NO_AVATAR_IMAGE); - - } - - public static BufferedImage getImage (String fileName) - { - - try - { - - return ImageIO.read (Environment.class.getResource (fileName)); - - } catch (Exception e) { - - Environment.logError ("Unable to read resource stream for image: " + - fileName, - e); - - } - - return null; - - //return new ImageIcon (Environment.class.getResource (fileName)).getImage (); - - } - - public static Image getTransparentImage () - { - - return new ImageIcon (Environment.class.getResource (Constants.IMGS_DIR + Constants.TRANSPARENT_PNG_NAME)).getImage (); - - } - - public static ImageIcon getLogo () - { - - return new ImageIcon (Environment.class.getResource (Constants.IMGS_DIR + Constants.LOGO_PNG_NAME)); - - } - - public static ImageIcon get3rdPartyLogo (String type) - { - - return new ImageIcon (Environment.class.getResource (Constants.IMGS_DIR + type + "-logo.png")); - - } - - public static String getWindowTitle (String title) - { - - return title + Environment.getWindowNameSuffix (); - - } - - public static String getWindowNameSuffix () - { - - return " - " + Constants.QUOLL_WRITER_NAME; - - } - - public static Color getBorderColor () - { - - return com.quollwriter.ui.UIUtils.getBorderColor (); - - } - - public static Color getInnerBorderColor () - { - - return com.quollwriter.ui.UIUtils.getColor ("#CCCCCC"); - - } - - public static Color getHighlightColor () - { - - // #DAE4FC - return new Color (218, - 228, - 252); - - } - - public static Version getQuollWriterVersion () - { - - return Environment.appVersion; - - } - - public static void extractResourceToFile (String name, - File outFile) - throws GeneralException - { - - try - { - - BufferedInputStream bin = new BufferedInputStream (Environment.class.getResourceAsStream (name)); - - BufferedOutputStream bout = new BufferedOutputStream (new FileOutputStream (outFile)); - - IOUtils.streamTo (bin, - bout, - 4096); - - } catch (Exception e) - { - - throw new GeneralException ("Unable to stream resource: " + - name + - " to output file: " + - outFile, - e); - - } - - } - - public static InputStream getResourceStream (String name) - { - - return Environment.class.getResourceAsStream (name); - - } - - public static String getResourceFileAsString (String name) - throws GeneralException - { - - InputStream is = Environment.getResourceStream (name); - - if (is == null) - { - - return null; - - } - - StringBuilder b = new StringBuilder (); - - BufferedReader r = null; - - try - { - - r = new BufferedReader (new InputStreamReader (is, "utf-8")); - - String line = r.readLine (); - - while (line != null) - { - - b.append (line); - b.append ('\n'); - - line = r.readLine (); - - } - - } catch (Exception e) - { - - throw new GeneralException ("Unable to read from resource: " + - name, - e); - - } finally - { - - // Oh how I hate this... - try - { - - if (r != null) - { - - r.close (); - - } - - } catch (Exception e) - { - - // Ignore... What could we do otherwise? - - } - - } - - return b.toString (); - - } - - public static File getProjectInfoDBFile () - { - - File dir = null; - - String dv = UserProperties.get (Constants.PROJECT_INFO_DB_DIR_PROPERTY_NAME); - - if (dv != null) - { - - dir = new File (dv); - - } else { - - dir = Environment.getUserQuollWriterDir (); - - } - - return new File (dir, Constants.PROJECT_INFO_DB_FILE_NAME_PREFIX); - - } - - public static int getProjectInfoSchemaVersion () - { - - File f = new File (Environment.getProjectInfoDBFile ().getPath () + Constants.H2_DB_FILE_SUFFIX); - - // See if we already have a project info db. - if (f.exists ()) - { - - return Environment.projectInfoSchemaVersion; - - } - - // No file, so need to create the schema. - return 0; - - } - - public static int getSchemaVersion () - { - - return Environment.schemaVersion; - - } - - public static File writeStreamToTempFile (InputStream in) - throws IOException - { - - File f = File.createTempFile ("___" + Constants.QUOLL_WRITER_DIR_NAME + System.currentTimeMillis (), - null); - - BufferedOutputStream bout = new BufferedOutputStream (new FileOutputStream (f)); - - IOUtils.streamTo (new BufferedInputStream (in), - bout, - 4096); - - bout.flush (); - bout.close (); - - return f; - - } - - public static URL getUpgradeURL (Version version) - throws Exception - { - - String parms = "?version=" + version.getVersion (); - - return Environment.getSupportUrl (Constants.GET_UPGRADE_FILE_PAGE_PROPERTY_NAME, - parms); - - } - - private static URL getNewsAndVersionCheckURL () - throws Exception - { - - String parms = "?"; - - if (UserProperties.getAsBoolean (Constants.OPTIN_TO_BETA_VERSIONS_PROPERTY_NAME)) - { - - parms += "beta=true&"; - - } - - String lastVersionCheckTime = UserProperties.get (Constants.LAST_VERSION_CHECK_TIME_PROPERTY_NAME); - - if (lastVersionCheckTime != null) - { - - parms += "since=" + lastVersionCheckTime; - - } - - return Environment.getSupportUrl (Constants.GET_LATEST_VERSION_PAGE_PROPERTY_NAME, - parms); - - } - - public static void doNewsAndVersionCheck (final AbstractViewer viewer) - { - - if (Environment.doneVersionCheck) - { - - return; - - } - - String updaterClass = UserProperties.get (Constants.UPDATER_CLASS_PROPERTY_NAME, - null); - - Class updaterCl = null; - - try - { - - updaterCl = Class.forName (updaterClass); - - if (!QuollWriterUpdater.class.isAssignableFrom (updaterCl)) - { - - Environment.logError (String.format ("Expected class: %s, given by property: %s to be an instance of: %s", - updaterClass, - Constants.UPDATER_CLASS_PROPERTY_NAME, - QuollWriterUpdater.class.getName ())); - - updaterCl = null; - - } - - } catch (Exception e) { - - Environment.logError (String.format ("Unable to load class: %s given by property: %s", - updaterClass, - Constants.UPDATER_CLASS_PROPERTY_NAME), - e); - - } - - QuollWriterUpdater updater = null; - - if (updaterCl != null) - { - - try - { - - updater = (QuollWriterUpdater) updaterCl.newInstance (); - - } catch (Exception e) { - - Environment.logError (String.format ("Unable to create new instance of: %s, given by property: %s", - updaterClass, - Constants.UPDATER_CLASS_PROPERTY_NAME), - e); - - } - - } - - if ((UserProperties.getAsBoolean (Constants.DO_AUTO_UPDATE_CHECK_PROPERTY_NAME)) - && - (updater != null) - ) - { - - Environment.doneVersionCheck = true; - - final QuollWriterUpdater _updater = updater; - - Runner r = new Runner () - { - - public void run () - { - - try - { - - _updater.doUpdate (viewer); - -/* -Removed for now -TODO: Add back in when appropriate. - // Get the news. - List news = (List) data.get ("news"); - - if (news != null) - { - - final Set seenIds = new HashSet (); - - String seenNewsIds = UserProperties.get (Constants.SEEN_NEWS_IDS_PROPERTY_NAME); - - if (seenNewsIds == null) - { - - seenNewsIds = ""; - - } - - StringTokenizer t = new StringTokenizer (seenNewsIds, - ","); - - while (t.hasMoreTokens ()) - { - - seenIds.add (t.nextToken ().trim ()); - - } - - for (int i = 0; i < news.size (); i++) - { - - Map ndata = (Map) news.get (i); - - final String id = (String) ndata.get ("id"); - - if (seenIds.contains (id)) - { - - continue; - - } - - String m = (String) ndata.get ("message"); - - Box ib = new Box (BoxLayout.Y_AXIS); - ib.setMaximumSize (new Dimension (Short.MAX_VALUE, - Short.MAX_VALUE)); - - JTextPane p = UIUtils.createHelpTextPane (m, - viewer); - p.setAlignmentX (Component.LEFT_ALIGNMENT); - - p.setMaximumSize (new Dimension (Short.MAX_VALUE, - Short.MAX_VALUE)); - p.setBorder (null); - - ib.add (p); - ib.add (Box.createVerticalStrut (5)); - - JButton ok = new JButton ("Ok, got it"); - - Box bb = new Box (BoxLayout.X_AXIS); - bb.add (ok); - - ib.add (bb); - bb.setAlignmentX (Component.LEFT_ALIGNMENT); - - final ActionListener removeNot = viewer.addNotification (ib, - "notify", - -1); - - ok.addActionListener (new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - seenIds.add (id); - - StringBuilder sb = new StringBuilder (); - - for (String s : seenIds) - { - - if (sb.length () > 0) - { - - sb.append (","); - - } - - sb.append (s); - - } - - UserProperties.set (Constants.SEEN_NEWS_IDS_PROPERTY_NAME, - sb.toString ()); - - removeNot.actionPerformed (ev); - - } - - }); - - } - - } -*/ - } catch (Exception e) - { - - Environment.logError ("Unable to perform update check", - e); - - } - - } - - }; - - Thread t = new Thread (r); - - t.setDaemon (true); - t.setPriority (Thread.MIN_PRIORITY); - - t.start (); - - } - - } - - public static long[] getAsLongs (List l) - { - - long[] arr = new long[l.size ()]; - - for (int i = 0; i < l.size (); i++) - { - - arr[i] = l.get (i); - - } - - return arr; - - } - - public static DecimalFormat getNumberFormatter () - { - - return Environment.numFormat; - - } - - public static String formatNumber (int i) - { - - return Environment.numFormat.format (i); - - } - - public static String formatNumber (long i) - { - - return Environment.numFormat.format (i); - - } - - public static String formatNumber (float f) - { - - return Environment.floatNumFormat.format (f); - - } - - public static String formatNumber (double f) - { - - return Environment.floatNumFormat.format (f); - - } - - public static Double parseToDouble (String v) - throws GeneralException - { - - if (v == null) - { - - return null; - - } - - try - { - - return Double.valueOf (Environment.floatNumFormat.parse (v, - new ParsePosition (0)).doubleValue ()); - - } catch (Exception e) { - - throw new GeneralException ("Unable to convert: " + - v + - " to a double.", - e); - - } - - } - -/* - public static String formatNumber (Number n) - { - - if (n == null) - { - - return "N/A"; - - } - - if (n instanceof Float) - { - - return Environment.floatNumFormat.format (n); - - } - - return Environment.numFormat.format (n); - - } -*/ - public static void sendMessageToSupport (final String type, - final Map info, - final ActionListener onComplete) - { - - Thread t = new Thread (new Runnable () - { - - public void run () - { - - try - { - - info.put ("quollWriterVersion", - Environment.getQuollWriterVersion ().toString ()); - info.put ("beta", - Environment.appVersion.isBeta ()); - info.put ("javaVersion", - System.getProperty ("java.version")); - info.put ("osName", - System.getProperty ("os.name")); - info.put ("osVersion", - System.getProperty ("os.version")); - info.put ("osArch", - System.getProperty ("os.arch")); - - Element root = new Element ("message"); - root.setAttribute ("quollWriterVersion", - Environment.getQuollWriterVersion ().toString ()); - root.setAttribute ("beta", - String.valueOf (Environment.appVersion.isBeta ())); - root.setAttribute ("javaVersion", - System.getProperty ("java.version")); - root.setAttribute ("osName", - System.getProperty ("os.name")); - root.setAttribute ("osVersion", - System.getProperty ("os.version")); - root.setAttribute ("osArch", - System.getProperty ("os.arch")); - root.setAttribute ("type", - type); - - // Encode as XML. - Iterator iter = info.keySet ().iterator (); - - while (iter.hasNext ()) - { - - Object k = iter.next (); - - Object v = info.get (k); - - Element el = new Element (k.toString ()); - - if (v != null) - { - - el.addContent (v.toString ()); - - } - - root.addContent (el); - - } - - // Get as a string. - String data = JDOMUtils.getElementAsString (root); - - List l = new ArrayList (); - - URL u = Environment.getSupportUrl (Constants.SEND_MESSAGE_TO_SUPPORT_PAGE_PROPERTY_NAME); - - HttpURLConnection conn = (HttpURLConnection) u.openConnection (); - - conn.setDoInput (true); - conn.setDoOutput (true); - - conn.connect (); - - BufferedWriter bout = new BufferedWriter (new OutputStreamWriter (conn.getOutputStream ())); - - bout.write (data); - bout.flush (); - bout.close (); - - BufferedReader b = new BufferedReader (new InputStreamReader (conn.getInputStream ())); - - String detail = b.readLine (); - - b.close (); - - if (((detail == null) - || - (!detail.equals ("SUCCESS")) - ) - && - (!type.equals ("error")) - ) - { - - throw new GeneralException ("Unable to get send message to support for url: " + - u + - ", response is: " + - detail); - - } - - if (onComplete != null) - { - - final ActionEvent ev = new ActionEvent (this, - 0, - "success"); - - UIUtils.doLater (onComplete); - - } - - } catch (Exception e) { - - if (onComplete != null) - { - - final ActionEvent ev = new ActionEvent (this, - 0, - "error"); - - UIUtils.doLater (onComplete); - - } - - if (!type.equals ("error")) - { - - Environment.logError ("Unable to send message to support", - e); - - } - - } - - } - - }); - - t.setDaemon (true); - t.start (); - - } - - - /** - * List directory contents for a resource folder. Not recursive. - * This is basically a brute-force implementation. - * Works for regular files and also JARs. - * - * @author Greg Briggs - * @param clazz Any java class that lives in the same place as the resources you want. - * @param path Should end with "/", but not start with one. - * @return Just the name of each member item, not the full paths. - * @throws URISyntaxException - * @throws IOException - */ - public static Set getResourceListing (String path) - throws URISyntaxException, - GeneralException, - IOException - { - - URL dirURL = Environment.class.getResource (path); - - if (dirURL == null) - { - - throw new GeneralException ("Unable to find resource: " + path); - - } - - if (dirURL.getProtocol ().equals ("jar")) - { - - /* A JAR path */ - String jarPath = dirURL.getPath ().substring (5, - dirURL.getPath ().indexOf ("!")); // strip out only the JAR file - - JarFile jar = new JarFile (URLDecoder.decode (jarPath, - "UTF-8")); - - Enumeration entries = jar.entries (); // gives ALL entries in jar - - Set result = new HashSet (); // avoid duplicates in case it is a subdirectory - - while (entries.hasMoreElements ()) - { - - String name = "/" + entries.nextElement ().getName (); - - if (name.startsWith (path)) - { // filter according to the path - - String entry = name.substring (path.length ()); - - if (entry.length () == 0) - { - - continue; - - } - - int checkSubdir = entry.indexOf ("/"); - - if (checkSubdir >= 0) - { - - // if it is a subdirectory, we just return the directory name - entry = entry.substring (0, - checkSubdir); - - } - - result.add (entry); - } - - } - - return result; - - } - - throw new UnsupportedOperationException ("Cannot list files for URL " + dirURL); - } - - public static Map> getAchievedAchievementIds (AbstractViewer viewer) - { - - return Environment.achievementsManager.getAchievedAchievementIds (viewer); - - } - - public static void removeAchievedAchievement (String achievementType, - String id, - AbstractViewer viewer) - throws Exception - { - - Environment.achievementsManager.removeAchievedAchievement (achievementType, - id, - viewer); - - } - - public static void showAchievement (AchievementRule ar) - { - - AbstractViewer v = Environment.getFocusedViewer (); - - if (v != null) - { - - v.showAchievement (ar); - - } - - } - - public static void eventOccurred (ProjectEvent ev) - { - - Environment.achievementsManager.eventOccurred (ev); - - } - - public static Set getPerProjectAchievementRules () - { - - return Environment.achievementsManager.getPerProjectRules (); - - } - - public static Set getUserAchievementRules () - { - - return Environment.achievementsManager.getUserRules (); - - } - - public static AchievementsManager getAchievementsManager () - { - - return Environment.achievementsManager; - - } - - public static AbstractProjectViewer getFullScreenProjectViewer () - { - - for (AbstractProjectViewer v : Environment.openProjects.values ()) - { - - if (v.isInFullScreen ()) - { - - return v; - - } - - } - - return null; - - } - - public static FullScreenTextProperties getFullScreenTextProperties () - { - - return Environment.fullScreenTextProps; - - } - - public static ProjectTextProperties getProjectTextProperties () - { - - return Environment.projectTextProps; - - } - - public static boolean isInFullScreen () - { - - return Environment.getFullScreenProjectViewer () != null; - - } - - public static void doForOpenProjects (final String projectType, - final ProjectViewerAction act) - { - - UIUtils.doLater (new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - for (ProjectInfo p : Environment.openProjects.keySet ()) - { - - AbstractProjectViewer pv = Environment.openProjects.get (p); - - if ((projectType == null) - || - (p.getType ().equals (projectType)) - ) - { - - act.doAction (pv); - - } - - } - - } - - }); - - } - - public static void doForOpenProjectViewers (final Class projectViewerType, - final ProjectViewerAction act) - { - - UIUtils.doLater (new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - for (ProjectInfo p : Environment.openProjects.keySet ()) - { - - AbstractProjectViewer pv = Environment.openProjects.get (p); - - if ((projectViewerType == null) - || - (projectViewerType.isAssignableFrom (pv.getClass ())) - ) - { - - act.doAction (pv); - - } - - } - - } - - }); - - } - - public static String formatObjectToStringProperties (DataObject d) - { - - Map props = new LinkedHashMap (); - - d.fillToStringProperties (props); - - return Environment.formatObjectToStringProperties (props); - - } - - public static String formatObjectToStringProperties (Map props) - { - - try - { - - return JSONEncoder.encode (props, - true, - ""); - - } catch (Exception e) { - - Environment.logError ("Unable to encode properties: " + - props, - e); - - return props + ""; - - } - - } - - public static void relaunchLanding () - throws Exception - { - - if (Environment.landingViewer != null) - { - - Environment.landingViewer.removeProjectEventListener (Environment.achievementsManager); - - Environment.landingViewer.close (false, - null); - - Environment.landingViewer = null; - - } - - Environment.showLanding (); - - } - - public static Landing getLanding () - { - - return Environment.landingViewer; - - } - - public static void showLanding () - { - - if (Environment.landingViewer == null) - { - - try - { - - Environment.landingViewer = new Landing (); - - Environment.landingViewer.init (); - - Environment.landingViewer.addProjectEventListener (Environment.achievementsManager); - - Environment.userPropertyHandlers.get (Constants.PROJECT_STATUSES_PROPERTY_NAME).addPropertyChangedListener (new PropertyChangedListener () - { - - @Override - public void propertyChanged (PropertyChangedEvent ev) - { - - if (ev.getChangeType ().equals (UserPropertyHandler.VALUE_CHANGED)) - { - - List toSave = new ArrayList (); - - String oldValue = (String) ev.getOldValue (); - String newValue = (String) ev.getNewValue (); - - // Change the type for all notes with the old type. - Set pis = null; - - try - { - - pis = Environment.getAllProjectInfos (); - - } catch (Exception e) { - - Environment.logError ("Unable to save: " + - toSave + - " with new type: " + - ev.getNewValue (), - e); - - UIUtils.showErrorMessage (Environment.getFocusedViewer (), - Environment.getUIString (LanguageStrings.project, - LanguageStrings.actions, - LanguageStrings.changestatus, - LanguageStrings.actionerror)); - //"Unable to change status"); - - return; - - } - for (ProjectInfo pi : pis) - { - - if (oldValue.equals (pi.getStatus ())) - { - - pi.setStatus (newValue); - - toSave.add (pi); - - } - - } - - if (toSave.size () > 0) - { - - try - { - - Environment.updateProjectInfos (toSave); - - } catch (Exception e) - { - - Environment.logError ("Unable to save: " + - toSave + - " with new type: " + - ev.getNewValue (), - e); - - UIUtils.showErrorMessage (Environment.getFocusedViewer (), - Environment.getUIString (LanguageStrings.project, - LanguageStrings.actions, - LanguageStrings.changestatus, - LanguageStrings.actionerror)); - //"Unable to change status"); - - } - - } - - } - - } - - }); - - } catch (Exception e) { - - Environment.logError ("Unable to create landing viewer", - e); - - UIUtils.showErrorMessage (null, - Environment.getUIString (LanguageStrings.allprojects, - LanguageStrings.actionerror)); - //"Unable to show all {projects}, please contact Quoll Writer support for assistance."); - - return; - - } - - } - - Environment.landingViewer.setVisible (true); - - Environment.landingViewer.toFront (); - - } - - public static File getDefaultSaveProjectDir () - { - - try - { - - List pis = new ArrayList (Environment.getAllProjectInfos (Project.NORMAL_PROJECT_TYPE)); - - Collections.sort (pis, - new ProjectInfoSorter ()); - - if (pis.size () > 0) - { - - return pis.get (0).getProjectDirectory ().getParentFile (); - - } - - } catch (Exception e) { - - Environment.logError ("Unable to get last edited project directory", - e); - - } - - return new File (Environment.getUserQuollWriterDir (), - Constants.DEFAULT_PROJECTS_DIR_NAME); - - } - - public static void removeUserProjectEventListener (ProjectEventListener l) - { - - Environment.userProjectEventListeners.remove (l); - - } - - public static void addUserProjectEventListener (ProjectEventListener l) - { - - Environment.userProjectEventListeners.put (l, - Environment.listenerFillObj); - - } - - public static void fireUserProjectEvent (Object source, - String type, - String action, - Object contextObject) - { - - Environment.fireUserProjectEvent (new ProjectEvent (source, - type, - action, - contextObject)); - - } - - public static void fireUserProjectEvent (Object source, - String type, - String action) - { - - Environment.fireUserProjectEvent (new ProjectEvent (source, - type, - action)); - - } - - public static void fireUserProjectEvent (final ProjectEvent ev) - { - - UIUtils.doActionLater (new ActionListener () - { - - public void actionPerformed (ActionEvent aev) - { - - Set ls = null; - - // Get a copy of the current valid listeners. - synchronized (Environment.userProjectEventListeners) - { - - ls = new LinkedHashSet (Environment.userProjectEventListeners.keySet ()); - - } - - for (ProjectEventListener l : ls) - { - - l.eventOccurred (ev); - - } - - } - - }); - - } - - public static boolean isPlaySoundOnKeyStroke () - { - - return Environment.playSoundOnKeyStroke; - - } - - public static void playKeyStrokeSound () - { - - if (Environment.keyStrokeSound == null) - { - - return; - - } - - if (!Environment.playSoundOnKeyStroke) - { - - return; - - } - - try - { - - if (Environment.keyStrokeSound.isRunning ()) - { - - Environment.keyStrokeSound.stop (); - - } - - Environment.keyStrokeSound.setFramePosition (0); - - Environment.keyStrokeSound.start (); - - } catch (Exception e) - { - - Environment.logError ("Unable to play key stroke sound", - e); - - Environment.playSoundOnKeyStroke = false; - - } - - } - - public static void setKeyStrokeSoundFile (File f) - { - - try - { - - InputStream is = null; - - if (f != null) - { - - try - { - - is = new BufferedInputStream (new FileInputStream (f)); - - } catch (Exception e) { - - // Ignore. - - } - - } - - if (is == null) - { - - // Play the default. - is = new BufferedInputStream (Environment.getResourceStream (Constants.DEFAULT_KEY_STROKE_SOUND_FILE)); - - } - - // Get the clip. - AudioInputStream ais = AudioSystem.getAudioInputStream (is); - - Environment.keyStrokeSound = AudioSystem.getClip (); - - Environment.keyStrokeSound.open (ais); - - } catch (Exception e) { - - Environment.logError ("Unable to set key stroke sound file", - e); - - UserProperties.remove (Constants.KEY_STROKE_SOUND_FILE_PROPERTY_NAME); - - return; - - } - - if (f != null) - { - - UserProperties.set (Constants.KEY_STROKE_SOUND_FILE_PROPERTY_NAME, - f.getPath ()); - - } - - } - - public static void setPlaySoundOnKeyStroke (boolean v) - { - - Environment.playSoundOnKeyStroke = v; - - UserProperties.set (Constants.PLAY_SOUND_ON_KEY_STROKE_PROPERTY_NAME, - v); - - Environment.fireUserProjectEvent (new Object (), - ProjectEvent.TYPE_WRITER_SOUND, - (v ? ProjectEvent.ON : ProjectEvent.OFF)); - - - } - - public static String getI18nString (String k) - { - - return k; - - } - - public static int getSessionWordCount () - { - - return Environment.userSession.getCurrentSessionWordCount (); - - } - - public static List getSessions (int daysPast) - throws GeneralException - { - - return Environment.projectInfoManager.getSessions (daysPast); - - } - - public static TargetsData getUserTargets () - { - - return Environment.targets; - - } - - public static void saveUserTargets () - { - - try - { - - Environment.saveUserProperties (); - - } catch (Exception e) { - - Environment.logError ("Unable to update user properties", - e); - - } - - } - - public static TargetsData getDefaultUserTargets () - { - - TargetsData td = new TargetsData (UserProperties.getProperties ().getParentProperties ()); - - return td; - - } - - /** - * Un-schedule the scheduledfuture, this is returned from Environment.schedule. - * - * @param f The scheduledfuture to remove from the executor service. - * @returns Whether it was successfully removed. - */ - public static void unschedule (ScheduledFuture f) - { - - if (f == null) - { - - return; - - } - - // Let it run to completion. - f.cancel (false); - - Environment.generalTimer.purge (); - - } - - /** - * Schedule the runnable to run after delay and repeat (use -1 or 0 for no repeat). - * - * @param r The runnable to run. - * @param delay The delay, in millis. - * @param repeat The repeat time, in millis. - */ - public static ScheduledFuture schedule (final Runnable r, - final long delay, - final long repeat) - { - - if (Environment.generalTimer == null) - { - - Environment.logError ("Unable to schedule timer is no longer valid."); - - return null; - - } - - if (r == null) - { - - Environment.logError ("Unable to schedule, runnable is null."); - - return null; - - } - - if (repeat < 1) - { - - return Environment.generalTimer.schedule (r, - delay, - TimeUnit.MILLISECONDS); - - } else { - - return Environment.generalTimer.scheduleAtFixedRate (r, - delay, - repeat, - TimeUnit.MILLISECONDS); - - } - - } - - public static void addDoOnShutdown (Runnable r) - { - - Environment.doOnShutdown.add (r); - - } - - public static File getUserObjectTypeIconFile (String objType) - { - - return new File (Environment.getUserQuollWriterDir () + "/" + Constants.USER_OBJECT_TYPE_ICON_FILES_DIR + "/" + objType); - - } - - public static void setUserObjectTypeIcon (String objType, - BufferedImage image) - throws Exception - { - - ImageIO.write (image, - "png", - Environment.getUserObjectTypeIconFile (objType)); - - } - - public static Set getAssetUserConfigurableObjectTypes (boolean sortOnName) - { - - Set types = new LinkedHashSet (); - - for (UserConfigurableObjectType t : Environment.userConfigObjTypes) - { - - if (t.isAssetObjectType ()) - { - - types.add (t); - - } - - } - - if (sortOnName) - { - - List stypes = new ArrayList (types); - - Collections.sort (stypes, - new Comparator () - { - - @Override - public int compare (UserConfigurableObjectType o1, - UserConfigurableObjectType o2) - { - - return o1.getObjectTypeName ().compareTo (o2.getObjectTypeName ()); - - } - - }); - - types = new LinkedHashSet (stypes); - - } - - return types; - - } - - public static UserConfigurableObjectTypeField getUserConfigurableObjectTypeField (long key) - throws GeneralException - { - - return (UserConfigurableObjectTypeField) Environment.projectInfoManager.getObjectByKey (UserConfigurableObjectTypeField.class, - key, - null, - null, - true); - - } - - public static UserConfigurableObjectType getUserConfigurableObjectType (long key) - throws GeneralException - { - - return (UserConfigurableObjectType) Environment.projectInfoManager.getObjectByKey (UserConfigurableObjectType.class, - key, - null, - null, - true); - - } - - public static boolean hasUserConfigurableObjectType (String userObjType) - { - - return Environment.getUserConfigurableObjectType (userObjType) != null; - - } - - public static UserConfigurableObjectType getUserConfigurableObjectType (String userObjType) - { - - for (UserConfigurableObjectType t : Environment.userConfigObjTypes) - { - - if ((t.getUserObjectType () != null) - && - (t.getUserObjectType ().equals (userObjType)) - ) - { - - return t; - - } - - } - - return null; - - } - - public static void removeUserConfigurableObjectType (UserConfigurableObjectType type) - throws GeneralException - { - - Environment.userConfigObjTypes.remove (type); - - Environment.projectInfoManager.deleteObject (type, - true); - - type.removePropertyChangedListener (Environment.userConfigurableObjectTypeNameListener); - - String id = type.getObjectTypeId (); - - Environment.objectTypeNamesSingular.remove (id); - - Environment.objectTypeNamesPlural.remove (id); - - // Tell all projects about it. - Environment.fireUserProjectEvent (type, - ProjectEvent.USER_OBJECT_TYPE, - ProjectEvent.DELETE, - type); - - } - - public static void updateUserConfigurableObjectTypeFieldOrdering (UserConfigurableObjectType type) - throws GeneralException - { - - UserConfigurableObjectTypeDataHandler dh = (UserConfigurableObjectTypeDataHandler) Environment.projectInfoManager.getHandler (type.getClass ()); - - dh.updateFieldOrdering (type); - - // Tell all projects about it. - Environment.fireUserProjectEvent (type, - ProjectEvent.USER_OBJECT_TYPE, - ProjectEvent.CHANGED, - type); - - } - - public static void updateUserConfigurableObjectType (UserConfigurableObjectType type) - throws GeneralException - { - - if (!Environment.userConfigObjTypes.contains (type)) - { - - Environment.addUserConfigurableObjectType (type); - - return; - - } - - Environment.projectInfoManager.saveObject (type); - - String id = type.getObjectTypeId (); - - Environment.objectTypeNamesSingular.put (id, - type.getObjectTypeName ()); - - Environment.objectTypeNamesPlural.put (id, - type.getObjectTypeNamePlural ()); - - // Tell all projects about it. - Environment.fireUserProjectEvent (type, - ProjectEvent.USER_OBJECT_TYPE, - ProjectEvent.CHANGED, - type); - - } - - public static void addUserConfigurableObjectType (UserConfigurableObjectType type) - throws GeneralException - { - - if (type.getKey () == null) - { - - Environment.projectInfoManager.saveObject (type); - - } - - Environment.userConfigObjTypes.add (type); - - // Register ourselves as a listener for the name changes. - type.addPropertyChangedListener (Environment.userConfigurableObjectTypeNameListener); - - String id = type.getObjectTypeId (); - - if (!type.isLegacyObjectType ()) - { - - Environment.objectTypeNamesSingular.put (id, - type.getObjectTypeName ()); - - Environment.objectTypeNamesPlural.put (id, - type.getObjectTypeNamePlural ()); - - } - - // Tell all projects about it. - Environment.fireUserProjectEvent (type, - ProjectEvent.USER_OBJECT_TYPE, - ProjectEvent.NEW, - type); - - } - - public static void removeUserConfigurableObjectTypeField (UserConfigurableObjectTypeField field) - throws GeneralException - { - - Environment.projectInfoManager.deleteObject (field, - true); - - // Tell all projects about it. - Environment.fireUserProjectEvent (field, - ProjectEvent.USER_OBJECT_TYPE_FIELD, - ProjectEvent.DELETE, - field); - - } - - public static void updateUserConfigurableObjectTypeField (UserConfigurableObjectTypeField field) - throws GeneralException - { - - String ev = ProjectEvent.CHANGED; - - if (field.getKey () == null) - { - - ev = ProjectEvent.NEW; - - } - - Environment.projectInfoManager.saveObject (field); - - // Tell all projects about it. - Environment.fireUserProjectEvent (field, - ProjectEvent.USER_OBJECT_TYPE_FIELD, - ev, - field); - - Environment.fireUserProjectEvent (field.getUserConfigurableObjectType (), - ProjectEvent.USER_OBJECT_TYPE, - ProjectEvent.CHANGED, - field.getUserConfigurableObjectType ()); - - } - - /** - * Save a tag, this will either create or update it. - * - * @param tag The tag. - * @throws GeneralException If the tag can't be saved. - */ - public static void saveTag (Tag tag) - throws GeneralException - { - - String ev = ProjectEvent.CHANGED; - - if (tag.getKey () == null) - { - - ev = ProjectEvent.NEW; - - } - - Environment.projectInfoManager.saveObject (tag); - - if (ev.equals (ProjectEvent.NEW)) - { - - Environment.tags.add (tag); - - } - - // Tell all projects about it. - Environment.fireUserProjectEvent (tag, - ProjectEvent.TAG, - ev, - tag); - - } - - /** - * Delete a tag. - * - * @param tag The tag to delete. - * @throws GeneralException If the delete goes wrong. - */ - public static void deleteTag (Tag tag) - throws GeneralException - { - - Environment.projectInfoManager.deleteObject (tag, - true); - - Environment.tags.remove (tag); - - // Tell all projects about it. - Environment.fireUserProjectEvent (tag, - ProjectEvent.TAG, - ProjectEvent.DELETE, - tag); - - } - - /** - * Get a tag by its key. - * - * @param key The key. - * @return The tag. - * @throws GeneralException If the tag can't be retrieved. - */ - public static Tag getTagByKey (long key) - throws GeneralException - { - - Set tags = Environment.getAllTags (); - - for (Tag t : tags) - { - - if (t.getKey () == key) - { - - return t; - - } - - } - - return null; - - } - - /** - * Get a tag by name. - * - * @return The tag, if found. - * @throws GeneralException If the tags can't be retrieved from the db. - */ - public static Tag getTagByName (String name) - throws GeneralException - { - - Set tags = Environment.getAllTags (); - - for (Tag t : tags) - { - - if (t.getName ().equalsIgnoreCase (name)) - { - - return t; - - } - - } - - return null; - - } - - /** - * Get all the tags. - * - * @return The tags. - * @throws GeneralException if the tags can't be retrieved from the db. - */ - public static Set getAllTags () - throws GeneralException - { - - if (Environment.tags == null) - { - - Environment.tags = new LinkedHashSet (Environment.projectInfoManager.getObjects (Tag.class, - null, - null, - true)); - - } - - return Environment.tags; - - } - - public static String getDefaultTextAlignment () - { - - return getUIString (textalignments,left); - - } - - public static String getDefaultChapterName () - { - - return getUIString (general,defaultchaptername); - - } - - public static String getUIString (String... ids) - { - - return Environment.getUIString (Arrays.asList (ids)); - - } - - public static String getUIString (List prefix, - String id) - { - - List ids = new ArrayList (prefix); - - ids.add (id); - - return Environment.getUIString (ids); - - } - - public static String getUIString (List prefix, - String... ids) - { - - List _ids = new ArrayList (prefix); - - for (String s : ids) - { - - _ids.add (s); - - } - - return Environment.getUIString (_ids); - - } - - private static String getUIString (List ids) - { - - String s = Environment.uiLanguageStrings.getString (ids); - - if (s == null) - { - - s = LanguageStrings.toId (ids); - - } - - return s; - - } - - public static LanguageStringsEditor editUILanguageStrings (LanguageStrings userStrings, - Version baseQWVersion) - { - - LanguageStringsEditor lse = Environment.getUILanguageStringsEditor (userStrings); - - if (lse != null) - { - - lse.toFront (); - - return lse; - - } - - try - { - - LanguageStringsEditor _ls = new LanguageStringsEditor (userStrings, - baseQWVersion); - _ls.init (); - - return _ls; - - } catch (Exception e) { - - Environment.logError ("Unable to create language strings editor", - e); - - UIUtils.showErrorMessage (null, - getUIString (uilanguage,edit,actionerror)); - - return null; - - } - - } - - public static LanguageStringsEditor getUILanguageStringsEditor (LanguageStrings ls) - { - - for (AbstractViewer v : Environment.openViewers) - { - - if (v instanceof LanguageStringsEditor) - { - - LanguageStringsEditor lse = (LanguageStringsEditor) v; - - if (lse.getUserLanguageStrings ().equals (ls)) - { - - return lse; - - } - - } - - } - - return null; - - } - -} diff --git a/src/com/quollwriter/LanguageStrings.java b/src/com/quollwriter/LanguageStrings.java deleted file mode 100644 index 440661b2..00000000 --- a/src/com/quollwriter/LanguageStrings.java +++ /dev/null @@ -1,4429 +0,0 @@ -package com.quollwriter; - -import java.io.*; -import java.util.*; -import java.nio.charset.*; - -import org.jdom.*; - -import com.gentlyweb.utils.*; - -import com.quollwriter.data.*; - -public class LanguageStrings extends NamedObject implements RefValueProvider, Comparable -{ - - public static final String ENGLISH_ID = ":" + Constants.ENGLISH; - public static final String OBJECT_TYPE = "languagestrings"; - - public static String ID_PART_SEP = "."; - public static String ID_REF_START = "${"; - public static String ID_REF_END = "}"; - - private String languageName = null; - private int stringsVersion = 0; - private Date created = null; - private Date lastModified = null; - private String _email = null; - private LanguageStrings parent = null; - private Map nodes = new HashMap<> (); - private Version qwVersion = null; - private Set
    sections = null; - private boolean isUser = false; - - private LanguageStrings () - { - - super (OBJECT_TYPE, - null); - - this.qwVersion = Environment.getQuollWriterVersion (); - - } - - public LanguageStrings (LanguageStrings derivedFrom) - { - - this (); - - // Clone the nodes in the derivedFrom. - //this.nodes = derivedFrom.cloneNodes (); - this.parent = derivedFrom; - this.setId (UUID.randomUUID ().toString ()); - this.created = new Date (); - - } - - public LanguageStrings (File f) - throws GeneralException - { - - this (); - - if ((f == null) - || - (!f.exists ()) - || - (!f.isFile ()) - ) - { - - throw new IllegalArgumentException ("No file provided."); - - } - - String v = null; - - try - { - - Reader in = new BufferedReader (new InputStreamReader (new FileInputStream (f), - StandardCharsets.UTF_8)); - - long length = f.length (); - - char[] chars = new char[(int) length]; - - in.read (chars, - 0, - (int) length); - - in.close (); - - v = new String (chars); - - } catch (Exception e) { - - throw new GeneralException ("Unable to get contents of file: " + f, - e); - - } - - this.init (v); - - } - - public LanguageStrings (String jsonData) - throws GeneralException - { - - this (); - - this.init (jsonData); - - } - - public void setUser (boolean v) - { - - this.isUser = v; - - } - - public boolean isUser () - { - - return this.isUser; - - } - - public void setQuollWriterVersion (Version v) - { - - this.qwVersion = v; - - } - - public Version getQuollWriterVersion () - { - - return this.qwVersion; - - } - - public int getStringsVersion () - { - - return this.stringsVersion; - - } - - public void setStringsVersion (int v) - { - - this.stringsVersion = v; - - } - - public static boolean isEnglish (String id) - { - - return id.equals (ENGLISH_ID); - - } - - public boolean isEnglish () - { - - return isEnglish (this.getId ()); - - } - - public Set
    getSections () - { - - return this.sections; - - } - - @Override - public boolean equals (Object o) - { - - if (!(o instanceof LanguageStrings)) - { - - return false; - - } - - LanguageStrings ls = (LanguageStrings) o; - - return this.compareTo (ls) == 0; - - } - - @Override - public int compareTo (LanguageStrings obj) - { - - if (obj == null) - { - - return -1; - - } - - if (this.getId ().equals (obj.getId ())) - { - - return this.qwVersion.compareTo (obj.qwVersion); - - } - - int v = this.qwVersion.compareTo (obj.qwVersion); - - if (v == 0) - { - - return this.getName ().compareTo (obj.getName ()); - - } - - return v; - - } - - private void init (String jsonData) - throws GeneralException - { - - Object obj = JSONDecoder.decode (jsonData); - - if (!(obj instanceof Map)) - { - - throw new IllegalArgumentException ("String does parse to a Map"); - - } - - this.init ((Map) obj); - - } - - private void init (Map obj) - throws GeneralException - { - - if (obj == null) - { - - throw new IllegalArgumentException ("No object provided."); - - } - - Map m = (Map) obj; - - this.setId (this.getString (":id", - m)); - - String did = this.getString (":derivedfrom", - m); - - if (did != null) - { - - // Get the parent. - try - { - - this.parent = Environment.getUILanguageStrings (did); - - } catch (Exception e) { - - throw new GeneralException ("Unable to find language strings for id: " + - did, - e); - - } - - } - - String qwv = (String) m.get (":qwversion"); - - if (qwv == null) - { - - throw new GeneralException ("Expected to find a QW version."); - - } - - Number sv = (Number) m.get (":version"); - - if (sv != null) - { - - this.stringsVersion = sv.intValue (); - - } - - this.qwVersion = new Version (qwv); - - Number n = (Number) m.get (":created"); - - if (n == null) - { - - throw new GeneralException ("Expected to find a created date."); - - } - - this.created = new Date (); - this.created.setTime (n.longValue ()); - - n = (Number) m.get (":lastmodified"); - - if (n != null) - { - - Date d = new Date (); - d.setTime (n.longValue ()); - - this.lastModified = d; - - } - - Boolean b = (Boolean) m.get (":user"); - - if (b != null) - { - - this.isUser = b.booleanValue (); - - } - - this.languageName = this.getString (":language", - m); - - super.setName (this.getString (":nativename", - m)); - - if (this.getName () == null) - { - - throw new IllegalArgumentException ("No native language name found."); - - } - - this._email = this.getString (":email", - m); - - Collection s = (Collection) m.get (":sections"); - - if (s != null) - { - - this.sections = new LinkedHashSet<> (); - - Iterator iter = ((Collection) s).iterator (); - - while (iter.hasNext ()) - { - - Object o = iter.next (); - - if (o instanceof Map) - { - - this.sections.add (new Section ((Map) o)); - - } - - } - - } - - // Ensure we can resolve everything. - Iterator iter = m.keySet ().iterator (); - - while (iter.hasNext ()) - { - - String k = iter.next ().toString (); - - if (LanguageStrings.isSpecialId (k)) - { - - continue; - - } - - List ids = new ArrayList (); - - ids.add (k); - - Object v = m.get (k); - - if (v instanceof Map) - { - - Map om = (Map) v; - - this.nodes.put (k, - new Node (k, - null, - om)); - - continue; - - } - - if (v instanceof String) - { - - String val = v.toString (); - - this.nodes.put (k, - new Value (k, - null, - val, - m)); - - } - - } - - } - - public Set getAllNamedChildObjects () - { - - return new HashSet<> (); - - } - - @Override - public Date getLastModified () - { - - return this.lastModified; - - } - - public void getChanges (NamedObject old, - Element root) - { - - } - - @Override - public void fillToStringProperties (Map props) - { - - super.fillToStringProperties (props); - - this.addToStringProperties (props, - "language", - this.languageName); - this.addToStringProperties (props, - "nativename", - this.getName ()); - this.addToStringProperties (props, - "email", - this._email); - this.addToStringProperties (props, - "created", - this.created); - this.addToStringProperties (props, - "qwversion", - this.qwVersion.getVersion ()); - this.addToStringProperties (props, - "stringsversion", - this.stringsVersion); - - if (this.parent != null) - { - - this.addToStringProperties (props, - "derivedfrom", - this.parent.getId ()); - - } - - } - - /** - * Returns a data structure that is suitable for JSON encoding. - * - * @return The data - */ - public Map getAsJSON () - { - - Map m = new HashMap (); - - m.put (":language", - this.languageName); - m.put (":nativename", - this.getName ()); - m.put (":email", - this._email); - m.put (":id", - this.getId ()); - m.put (":created", - this.created.getTime ()); - m.put (":qwversion", - this.qwVersion.getVersion ()); - m.put (":user", - this.isUser); - m.put (":version", - this.stringsVersion); - - if (this.lastModified != null) - { - - m.put (":lastmodified", - this.lastModified.getTime ()); - - } - - if (this.parent != null) - { - - m.put (":derivedfrom", - this.parent.getId ()); - - } - - if (this.sections != null) - { - - List> sects = new ArrayList<> (); - - m.put (":sections", - sects); - - for (Section s : this.sections) - { - - Map ms = new HashMap<> (); - - ms.put ("id", - s.id); - ms.put ("name", - s.name); - ms.put ("icon", - s.icon); - - sects.add (ms); - - } - - } - - for (String idPrefix : this.nodes.keySet ()) - { - - m.put (idPrefix, - this.nodes.get (idPrefix).getAsJSON ()); - - } - - return m; - - } - - public Node createNode (String id) - { - - return new Node (id, - null); - - } - - public static Id getId (String text, - int offset) - { - - Set ids = LanguageStrings.getIds (text); - - for (Id id : ids) - { - - if ((id.getStart () <= offset) - && - (id.getEnd () >= offset) - ) - { - - return id; - - } - - } - - return null; - - } - - public static Set getIds (String text) - { - - Set ret = new LinkedHashSet<> (); - - if ((text == null) - || - (text.trim ().length () == 0) - ) - { - - return ret; - - } - - java.util.List lines = Utils.splitString (text, - "\n"); - - for (String l : lines) - { - - int start = 0; - - while ((start = l.indexOf (LanguageStrings.ID_REF_START, start)) != -1) - { - - String id = null; - boolean partial = false; - - start += LanguageStrings.ID_REF_START.length (); - - int ind = start; - - int idendind = l.indexOf (LanguageStrings.ID_REF_END, start); - - if (idendind > -1) - { - - id = l.substring (start, idendind); - - partial = false; - //hasClosingBrace = true; - start += id.length (); - start += LanguageStrings.ID_REF_END.length (); - - } else { - - StringBuilder b = new StringBuilder (); - - for (int i = start; i < l.length (); i++) - { - - char c = text.charAt (i); - - if (Character.isWhitespace (c)) - { - - break; - - } - - b.append (c); - - } - - id = b.toString (); - start += id.length (); - partial = true; - - } - - ret.add (new Id (ind, id, partial)); - - } - - } - - return ret; - - } - - public static Set getRefIds (String text) - { - - Set ids = new LinkedHashSet<> (); - - int start = 0; - - while ((start = text.indexOf (ID_REF_START, - start)) > -1) - { - - int end = text.indexOf (ID_REF_END, - start); - - if (end > (start + ID_REF_START.length ())) - { - - String sid = text.substring (start + ID_REF_START.length (), - end); - - sid = sid.trim (); - - if (sid.length () > 0) - { - - ids.add (sid); - - } - - start = end + ID_REF_END.length (); - - } else { - - start += ID_REF_START.length (); - - } - - } - - return ids; - - } - - public static List buildRefValsTree (String text, - String rootId, - RefValueProvider prov, - List ids) - { - - if (text == null) - { - - return null; - - } - - Set refids = LanguageStrings.getIds (text); - - for (Id rid : refids) - { - - if (rid.isPartial ()) - { - - continue; - - } - //Value v = strings.getValue (rid); - - if (rid.getId ().equals (rootId)) - { - - return ids; - - } - - if (ids.contains (rid.getId ().trim ())) - { - - // Already have this, got a loop. - return ids; - - } - - ids.add (rid.getId ().trim ()); - - int ind = ids.size () - 1; - - String rv = prov.getRawText (rid.getId ().trim ());//getString (rid); - - if (rv == null) - { - - return null; - - } - - List nids = LanguageStrings.buildRefValsTree (rv, - rootId, - prov, - new ArrayList<> (ids)); - - if (nids != null) - { - - return nids; - - } else { - - ids = ids.subList (0, ind); - - } - - } - - return null; - - } - - public static Set getErrors (String text, - String textId, - int scount, - RefValueProvider prov) - { - - Set errors = new LinkedHashSet<> (); - - List vals = LanguageStrings.buildRefValsTree (text, - textId, - prov, - new ArrayList ()); - - if (vals != null) - { - - StringBuilder b = new StringBuilder (); - - for (String v : vals) - { - - if (b.length () > 0) - { - - b.append (" -> "); - - } - - b.append (v); - - } - - errors.add ("Reference loop detected between: " + textId + " and: " + b.toString ()); - - return errors; - - } - - Set ids = LanguageStrings.getIds (text); - - for (Id id : ids) - { - - if (id.isPartial ()) - { - - errors.add (String.format ("No matching %s found for opening %s at location: %s", - ID_REF_END, - ID_REF_START, - id.getStart ())); - - } - - if (!id.getId ().trim ().equals (id.getId ())) - { - - errors.add (String.format ("Id %s at location: %s contains invalid characters", - id.getId (), - id.getStart ())); - - } - - if (id.getId ().trim ().equals ("")) - { - - errors.add (String.format ("No id provided at location: %s", - id.getStart ())); - - } - - if (prov.getRawText (id.getId ()) == null) - { - - errors.add (String.format ("Id: %s, referenced at location: %s does not exist.", - id.getId (), - id.getStart ())); - - } - - } - - scount = prov.getSCount (textId); - - if (scount > 0) - { - - for (int i = 0; i < scount; i++) - { - - String sid = "%" + (i + 1) + "$s"; - - if (text.indexOf (sid) < 0) - { - - errors.add ("Expected to find value: " + sid); - - } - - } - - - } - - // Check for values beyond the scount. - for (int i = 0; i < 10; i++) - { - - if ((scount < 1) - || - (i > scount) - ) - { - - String sid = "%" + (i + 1) + "$s"; - - if (text.indexOf (sid) > -1) - { - - errors.add ("Invalid value used: " + sid + ", scount: " + scount); - - } - - } - - } - - try - { - - if (scount > 0) - { - - Object[] test = new String[scount]; - - for (int i = 0; i < scount; i++) - { - - test[i] = "test"; - - } - - String.format (text, - test); - - } else { - - //String.format (text); - - } - - } catch (Exception e) { - - errors.add ("Invalid value used: " + e.getMessage ()); - - } - -/* - Set refids = LanguageStrings.getRefIds (text); - - if (refids.contains (textId)) - { - - errors.add ("Value uses itself O_o"); - - } -*/ - - return errors; - - } - - public static String buildText (String text, - RefValueProvider prov) - { - - StringBuilder b = new StringBuilder (text); - - int start = 0; - - while ((start = b.indexOf (ID_REF_START, - start)) > -1) - { - - int end = b.indexOf (ID_REF_END, - start); - - if (end > (start + ID_REF_START.length ())) - { - - String sid = b.substring (start + ID_REF_START.length (), - end); - - int bind = sid.indexOf ("|"); - String sub = null; - - if (bind > -1) - { - - sub = sid.substring (0, bind); - - sid = sid.substring (bind + 1); - - } - - String sv = prov.getString (sid); - - if (sub != null) - { - - if (sub.equalsIgnoreCase ("u")) - { - - // Uppercase the first letter. - - } - - if (sub.equalsIgnoreCase ("l")) - { - - // Lowercase the first letter. - //char c[] = idv.toCharArray (); - - //c[0] = Character.toLowerCase (c[0]); - - //idv = new String (c); - - } - - if (sub.equalsIgnoreCase ("ua")) - { - - // Uppercase the first letter of each word. - - } - - if (sub.equalsIgnoreCase ("la")) - { - - // Lowercase the first letter of each word. - - } - - } - - if (sv != null) - { - - b.replace (start, - end + ID_REF_END.length (), - sv); - - start += sv.length (); - - } else { - - start = end + 1; - - } - - } else { - - start += ID_REF_START.length (); - - } - - } - - String s = b.toString (); - - s = LanguageStrings.replaceSpecialValues (s); - - return s; - - } - - public static String replaceSpecialValues (String t) - { - - if (t == null) - { - - return t; - - } - - StringBuilder b = new StringBuilder (t); - - int start = b.indexOf ("{"); - - while (start > -1) - { - - int end = b.indexOf ("}", - start); - - if (end > start) - { - - String ot = b.substring (start + 1, - end); - - String newot = ot.toLowerCase (); - - if (newot.equals ("qw")) - { - - newot = Constants.QUOLL_WRITER_NAME; - - } - - b.replace (start, - end + 1, - newot); - - start += newot.length (); - - } else { - - start++; - - } - - start = b.indexOf ("{", - start); - - } - - return b.toString (); - - } - - public Map> getErrors () - { - - Map> ret = new LinkedHashMap<> (); - - for (Value v : this.getAllValues ()) - { - - Set errors = v.getErrors (this); - - if ((errors != null) - && - (errors.size () > 0) - ) - { - - ret.put (v, - errors); - - } - - // Special checks for the base strings. - if ((this.isEnglish ()) - && - (!this.isUser ()) - ) - { - - int c = 0; - boolean invalid = false; - - String rawText = v.getRawText (); - - // This is a cheap check to determine whether there are strings but the scount is wrong. - for (int i = 0; i < 5; i++) - { - - if (rawText.indexOf ("%" + i + "$s") != -1) - { - - c++; - - } - - if (rawText.indexOf ("%" + i + "s") != -1) - { - - invalid = true; - - } - - if (rawText.indexOf ("$" + i + "$") != -1) - { - - invalid = true; - - } - - } - - if (rawText.indexOf ("%$") != -1) - { - - invalid = true; - - } - - if (invalid) - { - - errors.add (String.format ("Invalid %$ or %Xs value found.")); - - } - - if (v.getSCount () != c) - { - - errors.add (String.format (":scount value is incorrect or not present, expected: %s, scount is %s.", - c, - v.getSCount ())); - - } - - if ((c > 0) - && - (v.getComment () == null) - ) - { - - errors.add (String.format ("Value contains one or more %s values but not have an associated comment.", - "%x$s")); - - } - - if ((v.getSCount () > 0) - && - (v.getComment () == null) - ) - { - - errors.add ("S count present but no comment provided."); - - } - - } - - } - - return ret; - - } - - public Map> getErrors (List id) - { - - Map> ret = new LinkedHashMap<> (); - - for (Value v : this.getAllValues (id)) - { - - Set errors = v.getErrors (this); - - if ((errors != null) - && - (errors.size () > 0) - ) - { - - ret.put (v, - errors); - - } - - } - - return ret; - - } - - private String getString (String id, - Map from) - { - - Object o = from.get (id); - - if (o == null) - { - - return null; - - } - - return o.toString (); - - } - - public Map cloneNodes () - { - - Map ret = new LinkedHashMap<> (); - - for (String id : this.nodes.keySet ()) - { - - ret.put (id, - this.nodes.get (id).cloneNode ()); - - } - - return ret; - - } - - public boolean containsId (String id) - { - - return this.containsId (LanguageStrings.getIdParts (id)); - - } - - public boolean containsId (List idparts) - { - - if (idparts.size () < 1) - { - - return false; - - } - - Node n = this.nodes.get (idparts.get (0)); - - if (n != null) - { - - return n.getChild (idparts.subList (1, idparts.size ())) != null; - - } - - return false; - - } - - /** - * Return a list of values that this set contains but the old does not or if the old - * has the value then is the raw text value different. - * - * @return The set of new or raw text different values. - */ - public Set diff (LanguageStrings old) - { - - Set ret = new LinkedHashSet<> (); - - Set allVals = this.getAllValues (); - - for (Value v : allVals) - { - - Value ov = old.getValue (v.getId ()); - - if (ov == null) - { - - // This is a new value. - ret.add (v); - - } else { - - if (!v.getRawText ().equals (ov.getRawText ())) - { - - ret.add (v); - - } - - } - - } - - return ret; - - } - - public Map> getNodesInSections (String defSection) - { - - Map> sects = new LinkedHashMap<> (); - - for (Node n : this.nodes.values ()) - { - - String s = n.getSection (); - - if (s == null) - { - - s = defSection; - - } - - Set nns = sects.get (s); - - if (nns == null) - { - - nns = new TreeSet<> (); - - sects.put (s, - nns); - - } - - nns.add (n); - - } - - return sects; - - } - - public Set getNodes (List idparts, - Filter filter) - { - - Set vals = new LinkedHashSet<> (); - - if (idparts.size () < 1) - { - - return vals; - - } - - Node n = this.nodes.get (idparts.get (0)); - - if (n == null) - { - - return vals; - - } - - if (idparts.size () > 1) - { - - return n.getNodes (idparts.subList (1, idparts.size ()), - filter); - - } - - return n.getNodes (filter); - - } - - public Set getNodes (List idParts) - { - - return this.getNodes (idParts, - null); - - } - - public Set getNodes (Filter filter) - { - - Set vals = new LinkedHashSet<> (); - - for (Node n : this.nodes.values ()) - { - - vals.addAll (n.getNodes (filter)); - - } - - return vals; - - } - - public Set getAllValues () - { - - return this.getAllValues ((Filter) null); -/* - Set vals = new LinkedHashSet<> (); - - for (Node n : this.nodes.values ()) - { - - vals.addAll (n.getAllValues ()); - - } - - return vals; -*/ - } - - public Set getAllValues (Filter filter) - { - - Set vals = new LinkedHashSet<> (); - - for (Node n : this.nodes.values ()) - { - - vals.addAll (n.getAllValues (filter)); - - } - - return vals; - - } - - public Set getAllValues (List idparts) - { - - return this.getAllValues (idparts, - null); -/* - Set vals = new LinkedHashSet<> (); - - if (idparts.size () < 1) - { - - return vals; - - } - - Node n = this.nodes.get (idparts.get (0)); - - if (n == null) - { - - return vals; - - } - - if (idparts.size () > 1) - { - - return n.getAllValues (idparts.subList (1, idparts.size ())); - - } - - return n.getAllValues (); -*/ - } - - public Set getAllValues (List idparts, - Filter filter) - { - - Set vals = new LinkedHashSet<> (); - - if (idparts.size () < 1) - { - - return vals; - - } - - Node n = this.nodes.get (idparts.get (0)); - - if (n == null) - { - - return vals; - - } - - if (idparts.size () > 1) - { - - return n.getAllValues (idparts.subList (1, idparts.size ()), - filter); - - } - - return n.getAllValues (filter); - - } - - public void setEmail (String em) - { - - this._email = em; - - } - - public String getEmail () - { - - return this._email; - - } - - public void setNativeName (String n) - { - - super.setName (n); - - } - - public String getNativeName () - { - - return this.getName (); - - } - - public void setLanguageName (String n) - { - - this.languageName = n; - - } - - public String getLanguageName () - { - - return this.languageName; - - } - - public static String toId (List ids) - { - - return Utils.joinStrings (ids, - ID_PART_SEP); - - } - - public static List getIdParts (String id) - { - - return Utils.splitString (id, - ID_PART_SEP); - - } - - public TreeSet getIdMatches (String id) - { - - if (id.endsWith (".")) - { - - id += "*"; - - } - - List idparts = LanguageStrings.getIdParts (id); - - TreeSet matches = new TreeSet<> (); - - if (idparts.size () > 1) - { - - // Get the first node. - Node n = this.nodes.get (idparts.get (0)); - - if (n == null) - { - - return matches; - - } - - return n.getIdMatches (idparts.subList (1, idparts.size ())); - - } else { - - for (String nid : this.nodes.keySet ()) - { - - if (nid.startsWith (id)) - { - - matches.add (nid); - - } - - } - - return matches; - - } - - } - - public Node getNode (String id) - { - - List idparts = LanguageStrings.getIdParts (id); - - return this.getNode (idparts); - - } - - public Node getNode (List idparts) - { - - Node n = null; - - if (idparts.size () > 0) - { - - n = this.nodes.get (idparts.get (0)); - - } - - if ((idparts.size () > 1) - && - (n != null) - ) - { - - - return n.getChild (idparts.subList (1, idparts.size ())); - - } - - return n; - - } - - public static boolean isSpecialId (List id) - { - - for (String _id : id) - { - - if (LanguageStrings.isSpecialId (_id)) - { - - return true; - - } - - } - - return false; - - } - - public static boolean isSpecialId (String id) - { - - return id.startsWith (":"); - - } - - public Value getValue (List idparts) - { - - return this.getValue (idparts, - false); - - } - - public Value getValue (List idparts, - boolean thisOnly) - { - - if (idparts.size () < 1) - { - - return null; - - } - - if (!this.containsId (idparts)) - { - - if ((this.parent != null) - && - (!thisOnly) - ) - { - - return this.parent.getValue (idparts); - - } - - return null; - - } - - Node n = this.nodes.get (idparts.get (0)); - - if (n == null) - { - - return null; - - } - - if (idparts.size () > 1) - { - - n = n.getChild (idparts.subList (1, idparts.size ())); - - } - - if (n instanceof Value) - { - - return (Value) n; - - } - - return null; - - } - - public Node removeNode (List idparts) - throws GeneralException - { - - if ((idparts == null) - || - (idparts.size () == 0) - ) - { - - throw new IllegalArgumentException ("No id provided."); - - } - - String f = idparts.get (0); - - // See if we already have the first node. - Node n = this.nodes.get (f); - - if (n == null) - { - - return null; - - } - - if (idparts.size () == 1) - { - - this.nodes.remove (n); - - return n; - - } - - return n.removeNode (idparts.subList (1, idparts.size ())); - - } - - public Value insertValue (List idparts) - throws GeneralException - { - - if ((idparts == null) - || - (idparts.size () == 0) - ) - { - - throw new IllegalArgumentException ("No id provided."); - - } - - String f = idparts.get (0); - - // See if we already have the first node. - Node n = this.nodes.get (f); - - if (idparts.size () == 1) - { - - if (n != null) - { - - throw new GeneralException ("Already have a node called: " + f); - - } else { - - Value v = new Value (f, - null, - null, - null, - 0); - - this.nodes.put (f, v); - - } - - } else { - - if (n == null) - { - - n = new Node (f, - null); - - this.nodes.put (f, n); - - } - - } - - return n.insertValue (idparts.subList (1, idparts.size ())); - - } - - public String getBuiltText (String text) - { - - return new Value (null, null, text, null, 0).getBuiltText (this); - - } - - public Value getValue (String id) - { - - return this.getValue (LanguageStrings.getIdParts (id)); - - } - - public boolean isIdValid (String id) - { - - return this.getNode (id) != null; - - } - - @Override - public int getSCount (String id) - { - - return this.getSCount (LanguageStrings.getIdParts (id)); - - } - - @Override - public String getRawText (String id) - { - - return this.getRawText (LanguageStrings.getIdParts (id)); - - } - - @Override - public String getString (String id) - { - - return this.getString (LanguageStrings.getIdParts (id)); - - } - - public int getSCount (List idparts) - { - - if (this.parent != null) - { - - // Defer to our parent. - return this.parent.getSCount (idparts); - - } - - if (idparts.size () < 1) - { - - return 0; - - } - - Value v = this.getValue (idparts); - - if (v != null) - { - - return v.getSCount (); - - } - - return 0; - - } - - public String getString (List idparts) - { - - if (idparts.size () < 1) - { - - return null; - - } - - Value v = this.getValue (idparts); - - if (v != null) - { - - return v.getBuiltText (this); - - } - - return null; - - } - - public String getRawText (List idparts) - { - - if (idparts.size () < 1) - { - - return null; - - } - - Value v = this.getValue (idparts); - - if (v != null) - { - - return v.getRawText (); - - } - - return null; - - } - - public interface Filter - { - - public boolean accept (E n); - - } - - public class Section - { - - public String id = null; - public String icon = null; - public String name = null; - - public Section (Map data) - { - - Object id = data.get ("id"); - - if (id == null) - { - - throw new IllegalArgumentException ("Expected to find an id."); - - } - - this.id = id.toString (); - - Object icon = data.get ("icon"); - - if (icon == null) - { - - throw new IllegalArgumentException ("Expected to find an icon."); - - } - - this.icon = icon.toString (); - - Object name = data.get ("name"); - - if (name == null) - { - - throw new IllegalArgumentException ("Expected to find a name."); - - } - - this.name = name.toString (); - - } - - } - - public class Node implements Comparable - { - - protected Node parent = null; - private Map children = null; - protected String id = null; - protected String comment = null; - protected String section = null; - private String title = null; - - public Node (String id, - Node parent) - { - - this.id = id; - this.parent = parent; - - } - - public Node (String id, - Node parent, - Map data) - { - - this (id, - parent); - - Iterator iter = data.keySet ().iterator (); - - while (iter.hasNext ()) - { - - Object ko = iter.next (); - - if (!(ko instanceof String)) - { - - continue; - - } - - String kid = ko.toString (); - - Object o = data.get (kid); - - if (o instanceof Map) - { - - Map m = (Map) o; - - if (this.children == null) - { - - this.children = new LinkedHashMap<> (); - - } - - this.children.put (kid, - new Node (kid, - this, - m)); - - } - - if (o instanceof String) - { - - String v = o.toString (); - - if (LanguageStrings.isSpecialId (kid)) - { - - if (kid.equals (":comment")) - { - - this.comment = v; - - } - - if (kid.equals (":title")) - { - - this.title = v; - - } - - if (kid.equals (":section")) - { - - this.section = v; - - } - - continue; - - } - - if (this.children == null) - { - - this.children = new LinkedHashMap<> (); - - } - - this.children.put (kid, - new Value (kid, - this, - v, - data)); - - } - - } - - } - - public Node getRoot () - { - - if (this.parent == null) - { - - return this; - - } - - return this.parent.getRoot (); - - } - - public Set getNodes (List idparts, - Filter filter) - { - - if (this.children == null) - { - - return new LinkedHashSet<> (); - - } - - if (idparts.size () > 0) - { - - Node n = this.children.get (idparts.get (0)); - - if (n == null) - { - - return new LinkedHashSet<> (); - - } - - return n.getNodes (idparts.subList (1, idparts.size ()), - filter); - - } else { - - return this.getNodes (filter); - - } - - } - - public Set getAllNodes () - { - - return this.getNodes (null); - - } - - public Set getValues (Filter filter) - { - - Set ret = new LinkedHashSet<> (); - - if (filter != null) - { - - if (!filter.accept (this)) - { - - return ret; - - } - - } - - if (this instanceof Value) - { - - ret.add ((Value) this); - - } - - if (this.children != null) - { - - for (Node n : this.children.values ()) - { - - ret.addAll (n.getValues (filter)); - - } - - } - - return ret; - - } - - public Set getNodes (Filter filter) - { - - Set ret = new LinkedHashSet<> (); - - if (filter != null) - { - - if (!filter.accept (this)) - { - - return ret; - - } - - } - - ret.add (this); - - if (this.children != null) - { - - for (Node n : this.children.values ()) - { - - ret.addAll (n.getNodes (filter)); - - } - - } - - return ret; - - } - - public Value insertValue (List idparts) - throws GeneralException - { - - if ((idparts == null) - || - (idparts.size () == 0) - ) - { - - throw new IllegalArgumentException ("No id provided."); - - } - - String f = idparts.get (0); - - Node n = this.getChild (f); - - if (idparts.size () == 1) - { - - if (n == null) - { - - Value v = new Value (f, - null, - null, - null, - 0); - - this.addNode (v); - - return v; - - } else { - - throw new GeneralException ("Already have value: " + n + " with id: " + f); - - } - - } - - if (n == null) - { - - n = new Node (f, - null); - - this.addNode (n); - - } - - return n.insertValue (idparts.subList (1, idparts.size ())); - - } - - public Node removeNode (List idparts) - throws GeneralException - { - - if ((idparts == null) - || - (idparts.size () == 0) - ) - { - - throw new IllegalArgumentException ("No id provided."); - - } - - String f = idparts.get (0); - - Node n = this.getChild (f); - - if (n == null) - { - - return null; - - } - - if (idparts.size () == 1) - { - - this.children.remove (idparts.get (0)); - - return n; - - } - - return n.removeNode (idparts.subList (1, idparts.size ())); - - } - - public Map getAsJSON () - { - - Map m = new LinkedHashMap (); - - if (this.comment != null) - { - - m.put (":comment", - this.comment); - - } - - if (this.title != null) - { - - m.put (":title", - this.title); - - } - - if (this.section != null) - { - - m.put (":section", - this.section); - - } - - if (this.children != null) - { - - for (String idPrefix : this.children.keySet ()) - { - - Node n = this.children.get (idPrefix); - - if (n instanceof Value) - { - - Value v = (Value) n; - - m.put (idPrefix, - v.getRawText ()); - - if (v.getComment () != null) - { - - m.put (":comment." + idPrefix, - v.getComment ()); - - } - - if (v.getSCount () > 0) - { - - m.put (":scount." + idPrefix, - v.getSCount ()); - - } - - continue; - - } - - m.put (idPrefix, - n.getAsJSON ()); - - } - - } - - return m; - - } - - @Override - public int compareTo (Node n) - { - - return this.id.compareTo (n.id); - - } - - public void addNode (Node n) - { - - if (this.children == null) - { - - this.children = new LinkedHashMap<> (); - - } - - if (this.children.containsKey (n.id)) - { - - throw new IllegalArgumentException ("Node already contains child with id: " + n.id); - - } - - n.parent = this; - - this.children.put (n.id, - n); - - } - - public String getSection () - { - - return this.section; - - } - - public String getTitle () - { - - return this.title; - - } - - public Node cloneNode () - { - - Node n = new Node (this.id, - null); - - n.comment = this.comment; - n.title = this.title; - n.section = this.section; - - if (this.children != null) - { - - for (String cid : this.children.keySet ()) - { - - Node cn = this.children.get (cid); - - Node nn = cn.cloneNode (); - - n.addNode (nn); - - } - - } - - return n; - - } - - public String getComment () - { - - return this.comment; - - } - - @Override - public String toString () - { - - return (this.getId () + "(node,:section=" + this.section + ",:title=" + this.title + ",:comment=" + this.comment + ",children=" + (this.children != null ? this.children.size () : 0) + ")"); - - } - - public Map getChildren () - { - - return this.children; - - } - - public Node getParent () - { - - return this.parent; - - } - - public Node getChild (String id) - { - - if (this.children == null) - { - - return null; - - } - - return this.children.get (id); - - } - - public Node getChild (List ids) - { - - if (ids.size () < 1) - { - - return null; - - } - - Node c = this.getChild (ids.get (0)); - - if (c == null) - { - - return null; - - } - - if (ids.size () > 1) - { - - return c.getChild (ids.subList (1, ids.size ())); - - } - - return c; - - } - - public String getNodeId () - { - - return this.id; - - } - - public List getId () - { - - if (this.parent == null) - { - - List r = new ArrayList<> (); - r.add (this.id); - - return r; - - } - - List r = this.parent.getId (); - - r.add (this.id); - - return r; - - } - - public TreeSet getIdMatches (List idparts) - { - - TreeSet matches = new TreeSet<> (); - - if (this.children == null) - { - - return matches; - - } - - if (idparts.size () > 1) - { - - Node n = this.children.get (idparts.get (0)); - - if (n == null) - { - - return matches; - - } - - return n.getIdMatches (idparts.subList (1, idparts.size ())); - - } - - // Should only be one left here... - String id = idparts.get (0); - - for (String nid : this.children.keySet ()) - { - - if ((nid.startsWith (id)) - || - (id.equals ("*")) - ) - { - - matches.add (nid); - - } - - } - - return matches; - - } - - public Set getAllValues (List idparts) - { - - return this.getAllValues (idparts, - null); - - } - - public Set getAllValues (List idparts, - Filter filter) - { - - if (this.children == null) - { - - return new LinkedHashSet<> (); - - } - - if (idparts.size () > 0) - { - - Node n = this.children.get (idparts.get (0)); - - if (n == null) - { - - return new LinkedHashSet<> (); - - } - - return n.getAllValues (idparts.subList (1, idparts.size ()), - filter); - - } else { - - return this.getAllValues (filter); - - } - - } - - public Set getAllValues () - { - - return this.getAllValues ((Filter) null); - - } - - public Set getAllValues (Filter filter) - { - - Set vals = new LinkedHashSet<> (); - - if (this instanceof Value) - { - - Value v = (Value) this; - - if (filter != null) - { - - if (!filter.accept (v)) - { - - return vals; - - } - - } - - vals.add (v); - - return vals; - - } - - if (this.children != null) - { - - for (Node n : this.children.values ()) - { - - if (n instanceof Value) - { - - Value v = (Value) n; - - if (filter != null) - { - - if (!filter.accept (v)) - { - - continue; - - } - - } - - vals.add (v); - - continue; - - } - - vals.addAll (n.getAllValues (filter)); - - } - - } - - return vals; - - } - - @Override - public boolean equals (Object o) - { - - if (!(o instanceof Node)) - { - - return false; - - } - - Node n = (Node) o; - - if ((this.parent != null) - && - (n.parent != null) - ) - { - - if (this.parent.equals (n.parent)) - { - - return this.id.equals (n.id); - - } - - } - - if ((this.parent == null) - && - (n.parent == null) - ) - { - - return this.id.equals (n.id); - - } - - return false; - - } - - } - - public class Value extends Node - { - - private int scount = 0; - private String text = null; - private String builtText = null; - - public Value (String id, - Node parent, - String text, - Map parentData) - { - - super (id, - parent); - - this.text = text; - - Object co = parentData.get (":comment." + id); - - String comm = null; - - if (co != null) - { - - this.comment = co.toString (); - - } - - Object so = parentData.get (":scount." + id); - - if ((so != null) - && - (so instanceof Number) - ) - { - - this.scount = ((Number) so).intValue (); - - } - - } - - public Value (String id, - Node parent, - String text, - String comment, - int scount) - { - - super (id, - parent); - - this.text = text; - this.comment = comment; - this.scount = scount; - - } - - @Override - public Node cloneNode () - { - - Value n = new Value (this.id, - null, - null, /* no value */ - this.comment, - this.scount); - - //n.title = this.title; - //n.section = this.section; - - return n; - - } - - public void setSCount (int s) - { - - this.scount = s; - - } - - public int getSCount () - { - - return this.scount; - - } - - @Override - public String toString () - { - - return (this.getId () + "(value,scount=" + this.scount + ",text=" + this.text + ",comment=" + this.comment + ")"); - - } - - @Override - public Set getAllValues () - { - - return new LinkedHashSet<> (); - - } - - @Override - public Node getChild (List idparts) - { - - return null; - - } - - public Set getErrors (RefValueProvider prov) - { - - return LanguageStrings.getErrors (this.text, - LanguageStrings.toId (this.getId ()), - this.scount, - prov); - -/* - Set errors = new LinkedHashSet<> (); - - int start = 0; - - while ((start = this.text.indexOf (ID_REF_START, - start)) > -1) - { - - int end = this.text.indexOf (ID_REF_END, - start); - - if (end < 0) - { - - errors.add (String.format ("No matching %s found for opening %s at location: %s", - ID_REF_END, - ID_REF_START, - start)); - - // This breaks parsing so have to return. - return errors; - - } - - if (end > (start + ID_REF_START.length ())) - { - - String sid = this.text.substring (start + ID_REF_START.length (), - end); - - int bind = sid.indexOf ("|"); - String sub = null; - - if (bind > -1) - { - - sub = sid.substring (0, bind); - - sid = sid.substring (bind + 1); - - } - - if (strings.getValue (sid) == null) - { - - errors.add ("Id: " + sid + ", referenced at location: " + start + " does not exist."); - start += end + ID_REF_END.length (); - - continue; - - } else { - - start += ID_REF_START.length (); - - } - - } else { - - start += ID_REF_START.length (); - - } - - } - - if (this.scount > 0) - { - - for (int i = 0; i < this.scount; i++) - { - - String sid = "%" + (i + 1) + "$s"; - - if (this.text.indexOf (sid) < 0) - { - - errors.add ("Expected to find value: " + sid); - - } - - } - - } - - Set refids = this.getRefIds (); - - if (refids.contains (this.getId ())) - { - - errors.add ("Value references itself O_o"); - - } - - Set refs = new HashSet<> (); - Map tree = new HashMap (); - List vals = this.buildRefValsTree (this, - strings, - new ArrayList ()); - - if (vals != null) - { - - StringBuilder b = new StringBuilder (); - - for (Value v : vals) - { - - if (b.length () > 0) - { - - b.append (" -> "); - - } - - b.append (v.getId ()); - - } - - errors.add ("Reference loop detected between: " + this.getId () + " and: " + b.toString ()); - - } - - return errors; -*/ - } -/* - public List buildRefValsTree (Value root, - LanguageStrings strings, - List ids) - { - - Set refids = this.getRefIds (); - - for (String rid : refids) - { - - Value v = strings.getValue (rid); - - if (rid.equals (this.getId ())) - { - - return ids; - - } - - if (v == null) - { - - continue; - - } - - if (v.equals (root)) - { - - return ids; - - } - - if (ids.contains (v)) - { - - // Already have this, got a loop. - return ids; - - } - - ids.add (v); - - int ind = ids.size () - 1; - - List nids = v.buildRefValsTree (root, - strings, - new ArrayList (ids)); - - if (nids != null) - { - - return nids; - - } else { - - ids = ids.subList (0, ind); - - } - - } - - return null; - - } -*/ - public void clearBuiltText () - { - - this.builtText = null; - - } - - public void setRawText (String t) - { - - this.text = t; - this.clearBuiltText (); - - } - - public String getRawText () - { - - return this.text; - - } - - public String getBuiltText (RefValueProvider prov) - { - - if (this.builtText != null) - { - - return this.builtText; - - } - - if (this.getErrors (prov).size () > 0) - { - - return this.text; - - } - - String s = LanguageStrings.buildText (this.text, - prov); - - this.builtText = s; - - return this.builtText; - - } -/* - public Set getRefIds () - { - - Set ids = new LinkedHashSet<> (); - - int start = 0; - - while ((start = this.text.indexOf (ID_REF_START, - start)) > -1) - { - - int end = this.text.indexOf (ID_REF_END, - start); - - if (end > (start + ID_REF_START.length ())) - { - - String sid = this.text.substring (start + ID_REF_START.length (), - end); - - ids.add (sid); - start = end + ID_REF_END.length (); - - } else { - - start += ID_REF_START.length (); - - } - - } - - return ids; - - } -*/ - } - - public static class Id - { - - private int start = -1; - private boolean partial = false; - private String id = null; - private List parts = null; - - public Id (int start, - String id, - boolean partial) - { - - this.start = start; - this.id = id; - this.partial = partial; - - java.util.List parts = Utils.splitString (this.id, - LanguageStrings.ID_PART_SEP); - - this.parts = new ArrayList<> (); - - int cind = start; - - Part prevp = null; - - for (int i = 0; i < parts.size (); i++) - { - - if (i > 0) - { - - cind++; - - } - - String ps = parts.get (i); - - if (ps.trim ().length () != ps.length ()) - { - - //this.hasErrors = true; - - } - - Part p = new Part (this, - cind, - ps, - prevp); - - prevp = p; - cind += ps.length (); - - this.parts.add (p); - - } - - } - - public String getId () - { - - return this.id; - - } - - public boolean isIdValid (LanguageStrings baseStrings) - { - - return baseStrings.isIdValid (this.id); - - } - - public boolean isPartial () - { - - return this.partial; - - } - - public int getStart () - { - - return this.start; - - } - - public int getEnd () - { - - return this.getStart () + this.id.length (); - - } - - public Part getLastPart () - { - - if (this.parts.size () == 0) - { - - return null; - - } - - return this.parts.get (this.parts.size () - 1); - - } - - public Set getPartMatches (int offset, - LanguageStrings baseStrings) - { - - Part p = this.getPart (offset); - - if (p != null) - { - - return baseStrings.getIdMatches (p.getFullId ()); - - } - - return this.getMatches (baseStrings); - - } - - public String toString () - { - - return "id[start=" + this.start + ",text=" + this.id + ",partial=" + this.partial + "]"; - - } - - public Set getMatches (LanguageStrings baseStrings) - { - - return baseStrings.getIdMatches (this.id); - - } - - public Part getPart (int offset) - { - - for (int i = 0; i < this.parts.size (); i++) - { - - Part p = this.parts.get (i); - - if ((offset >= p.start) - && - (offset <= p.end) - ) - { - - return p; - - } - - } - - return null; - - } - - public class Part - { - - public int start = -1; - public int end = -1; - public String part = null; - public Id parent = null; - public Part previous = null; - - public Part (Id parent, - int start, - String part, - Part prev) - { - - this.start = start; - this.end = this.start + part.length (); - this.parent = parent; - this.part = part; - this.previous = prev; - - } - - public String getFullId () - { - - StringBuilder b = new StringBuilder (this.part); - - Part prev = this.previous; - - while (prev != null) - { - - b.insert (0, prev.part + "."); - prev = prev.previous; - - } - - return b.toString (); - - } - - } - - } - - public static final String project = "project"; - public static final String settingsmenu = "settingsmenu"; - public static final String items = "items"; - - public static final String renameproject = "renameproject"; - public static final String statistics = "statistics"; - public static final String targets = "targets"; - public static final String createbackup = "createbackup"; - public static final String openproject = "openproject"; - public static final String newproject = "newproject"; - public static final String deleteproject = "deleteproject"; - public static final String closeproject = "closeproject"; - public static final String exportproject = "exportproject"; - public static final String ideaboard = "ideaboard"; - public static final String dowarmup = "dowarmup"; - - public static final String actionerror = "actionerror"; - public static final String label = "label"; - public static final String filetype = "filetype"; - public static final String stages = "stages"; - public static final String wheretosave = "wheretosave"; - public static final String finder = "finder"; - public static final String tooltip = "tooltip"; - public static final String button = "button"; - public static final String title = "title"; - public static final String text = "text"; - public static final String help = "help"; - public static final String nexterror = "nexterror"; - public static final String previouserror = "previouserror"; - public static final String exportcompletepopup = "exportcompletepopup"; - public static final String sectiontitles = "sectiontitles"; - public static final String plan = "plan"; - public static final String goals = "goals"; - public static final String assets = "assets"; - public static final String notes = "notes"; - public static final String scenesoutlineitems = "scenesoutlineitems"; - public static final String chapterinfo = "chapterinfo"; - public static final String howtosave = "howtosave"; - public static final String otheritems = "otheritems"; - public static final String onefileperitemtype = "onefileperitemtype"; - public static final String types = "types"; - public static final String singlefile = "singlefile"; - public static final String onefileperchapter = "onefileperchapter"; - public static final String selectitems = "selectitems"; - public static final String importproject = "importproject"; - public static final String projectslist = "projectslist"; - public static final String selectproject = "selectproject"; - public static final String getallprojectserror = "getallprojectserror"; - public static final String moretextindicator = "moretextindicator"; - public static final String choose = "choose"; - public static final String importfromfile = "importfromfile"; - public static final String importfile = "importfile"; - public static final String options = "options"; - public static final String importfromproject = "importfromproject"; - public static final String selectfile = "selectfile"; - public static final String decide = "decide"; - public static final String textextra = "textextra"; - public static final String addtoproject = "addtoproject"; - public static final String importcompletepopup = "importcompletepopup"; - public static final String unabletosave = "unabletosave"; - public static final String supportedfiletypesdescription = "supportedfiletypesdescription"; - public static final String unabletocreateproject = "unabletocreateproject"; - public static final String nofileselected = "nofileselected"; - public static final String filenotexist = "filenotexist"; - public static final String dirselected = "dirselected"; - public static final String openfile = "openfile"; - public static final String cantopenproject = "cantopenproject"; - public static final String popup = "popup"; - public static final String wizard = "wizard"; - public static final String buttons = "buttons"; - public static final String confirm = "confirm"; - public static final String problemfinder = "problemfinder"; - public static final String config = "config"; - public static final String removerule = "removerule"; - public static final String thisproject = "thisproject"; - public static final String allprojects = "allprojects"; - public static final String rulebox = "rulebox"; - public static final String find = "find"; - public static final String info = "info"; - public static final String delete = "delete"; - public static final String edit = "edit"; - public static final String sentence = "sentence"; - public static final String paragraph = "paragraph"; - public static final String words = "words"; - public static final String addrule = "addrule"; - public static final String editrule = "editrule"; - public static final String add = "add"; - public static final String saveruleerror = "saveruleerror"; - public static final String tabtitles = "tabtitles"; - public static final String form = "form"; - public static final String labels = "labels"; - public static final String summary = "summary"; - public static final String description = "description"; - public static final String errors = "errors"; - public static final String entervalue = "entervalue"; - public static final String wordfinder = "wordfinder"; - public static final String passivesentence = "passivesentence"; - public static final String adverb = "adverb"; - public static final String wordphrase = "wordphrase"; - public static final String anywhere = "anywhere"; - public static final String where = "where"; - public static final String startofsentence = "startofsentence"; - public static final String endofsentence = "endofsentence"; - public static final String onlyindialogue = "onlyindialogue"; - public static final String ignoreindialogue = "ignoreindialogue"; - public static final String nowordserror = "nowordserror"; - public static final String rules = "rules"; - public static final String issues = "issues"; - public static final String suffixes = "suffixes"; - public static final String notindialogue = "notindialogue"; - public static final String indialogue = "indialogue"; - public static final String edittitle = "edittitle"; - public static final String insentence = "insentence"; - public static final String speechverbs = "speechverbs"; - public static final String newspeechverbs = "newspeechverbs"; - public static final String removespeechverbs = "removespeechverbs"; - public static final String separate = "separate"; - public static final String punctuationtext = "punctuationtext"; - public static final String wordtext = "wordtext"; - public static final String addtitle = "addtitle"; - public static final String doubleword = "doubleword"; - public static final String paragraphlength = "paragraphlength"; - public static final String sentencetext = "sentencetext"; - public static final String sentences = "sentences"; - public static final String paragraphreadability = "paragraphreadability"; - public static final String fr = "fr"; - public static final String fk = "fk"; - public static final String gf = "gf"; - public static final String sentencelength = "sentencelength"; - public static final String sentencecomplexity = "sentencecomplexity"; - public static final String ratio = "ratio"; - public static final String toomanyclauses = "toomanyclauses"; - public static final String clauses = "clauses"; - public static final String startup = "startup"; - public static final String cantopenlastprojecterror = "cantopenlastprojecterror"; - public static final String alreadyrunningerror = "alreadyrunningerror"; - public static final String unabletostarterror = "unabletostarterror"; - public static final String invalidemail = "invalidemail"; - public static final String functionunavailable = "functionunavailable"; - public static final String actions = "actions"; - public static final String fontunavailable = "fontunavailable"; - public static final String chaptersoverwcmaximum = "chaptersoverwcmaximum"; - public static final String multipleoverlimit = "multipleoverlimit"; - public static final String singleoverlimit = "singleoverlimit"; - public static final String multiple = "multiple"; - public static final String single = "single"; - public static final String chaptersoverreadabilitymaximum = "chaptersoverreadabilitymaximum"; - public static final String showdetail = "showdetail"; - public static final String autobackupnotification = "autobackupnotification"; - public static final String backups = "backups"; - public static final String spellchecker = "spellchecker"; - public static final String unabletosetlanguage = "unabletosetlanguage"; - public static final String achievementspanel = "achievementspanel"; - public static final String savechanges = "savechanges"; - public static final String discardchanges = "discardchanges"; - public static final String confirmpopup = "confirmpopup"; - public static final String fullscreen = "fullscreen"; - public static final String showpanelactionerror = "showpanelactionerror"; - public static final String closepanel = "closepanel"; - public static final String discard = "discard"; - public static final String save = "save"; - public static final String editors = "editors"; - public static final String vieweditorerror = "vieweditorerror"; - public static final String vieweditorserror = "vieweditorserror"; - public static final String showregistererror = "showregistererror"; - public static final String deletechapter = "deletechapter"; - public static final String toolbar = "toolbar"; - public static final String viewaddasset = "viewaddasset"; - public static final String viewchapterinformation = "viewchapterinformation"; - public static final String editchapter = "editchapter"; - public static final String viewproblemfindersidebar = "viewproblemfindersidebar"; - public static final String removetag = "removetag"; - public static final String close = "close"; - public static final String send = "send"; - public static final String email = "email"; - public static final String message = "message"; - public static final String errorlabel = "errorlabel"; - public static final String about = "about"; - public static final String keyboardshortcuts = "keyboardshortcuts"; - public static final String contactsupport = "contactsupport"; - public static final String viewuserguide = "viewuserguide"; - public static final String reportbug = "reportbug"; - public static final String whatsnew = "whatsnew"; - public static final String achievements = "achievements"; - public static final String projectmenu = "projectmenu"; - public static final String type = "type"; - public static final String vieweditors = "vieweditors"; - public static final String editorsserviceregister = "editorsserviceregister"; - public static final String showcontacts = "showcontacts"; - public static final String betabug = "betabug"; - public static final String bug = "bug"; - public static final String warmup = "warmup"; - public static final String reportproblem = "reportproblem"; - public static final String sendlogfiles = "sendlogfiles"; - public static final String sendscreenshot = "sendscreenshot"; - public static final String cancel = "cancel"; - public static final String debugmode = "debugmode"; - public static final String enabled = "enabled"; - public static final String disabled = "disabled"; - public static final String dowarmuponstart = "dowarmuponstart"; - public static final String times = "times"; - public static final String unlimited = "unlimited"; - public static final String words100 = "words100"; - public static final String words250 = "words250"; - public static final String words500 = "words500"; - public static final String words1000 = "words1000"; - public static final String hour1 = "hour1"; - public static final String mins5 = "mins5"; - public static final String mins10 = "mins10"; - public static final String mins20 = "mins20"; - public static final String mins30 = "mins30"; - public static final String week1 = "week1"; - public static final String days2 = "days2"; - public static final String days5 = "days5"; - public static final String hours12 = "hours12"; - public static final String hours24 = "hours24"; - public static final String addwarmuperror = "addwarmuperror"; - public static final String getwarmupsprojecterror = "getwarmupsprojecterror"; - public static final String starterror = "starterror"; - public static final String createwarmupsproject = "createwarmupsproject"; - public static final String openwarmupsprojecterror = "openwarmupsprojecterror"; - public static final String startwriting = "startwriting"; - public static final String saveerror = "saveerror"; - public static final String whicheverfirst = "whicheverfirst"; - public static final String andor = "andor"; - public static final String dofor = "dofor"; - public static final String ownprompt = "ownprompt"; - public static final String nextprompt = "nextprompt"; - public static final String previousprompt = "previousprompt"; - public static final String allpromptsexcluded = "allpromptsexcluded"; - public static final String visitlink = "visitlink"; - public static final String weblinks = "weblinks"; - public static final String noshowpromptagain = "noshowpromptagain"; - public static final String chooseprompt = "chooseprompt"; - public static final String acknowledgments = "acknowledgments"; - public static final String makeadonation = "makeadonation"; - public static final String releasenotes = "releasenotes"; - public static final String sourcecode = "sourcecode"; - public static final String website = "website"; - public static final String copyright = "copyright"; - public static final String qwversion = "qwversion"; - public static final String stop = "stop"; - public static final String tipspanel = "tipspanel"; - public static final String next = "next"; - public static final String previous = "previous"; - public static final String name = "name"; - public static final String tips = "tips"; - public static final String sidebar = "sidebar"; - public static final String section = "section"; - public static final String appearsinchapters = "appearsinchapters"; - public static final String showinsidebar = "showinsidebar"; - public static final String activetitle = "activetitle"; - public static final String headerpopupmenu = "headerpopupmenu"; - public static final String treepopupmenu = "treepopupmenu"; - public static final String tree = "tree"; - public static final String view = "view"; - public static final String sort = "sort"; - public static final String _new = "new"; - public static final String aboutpanel = "aboutpanel"; - public static final String linkedto = "linkedto"; - public static final String editobjecttypeinfo = "editobjecttypeinfo"; - public static final String addfileordocument = "addfileordocument"; - public static final String popupmenu = "popupmenu"; - public static final String user = "user"; - public static final String playsound = "playsound"; - public static final String playsoundinfullscreen = "playsoundinfullscreen"; - public static final String enable = "enable"; - public static final String legacyfields = "legacyfields"; - public static final String aliases = "aliases"; - public static final String webpage = "webpage"; - public static final String textalignments = "textalignments"; - public static final String left = "left"; - public static final String right = "right"; - public static final String justified = "justified"; - public static final String sidebars = "sidebars"; - public static final String othersidebarselect = "othersidebarselect"; - public static final String cantfindeditor = "cantfindeditor"; - public static final String invalidprojectdir = "invalidprojectdir"; - public static final String projectdirisfile = "projectdirisfile"; - public static final String projectdirnotexist = "projectdirnotexist"; - public static final String projectnotexist = "projectnotexist"; - public static final String openerrors = "openerrors"; - public static final String general = "general"; - public static final String writingtargetreachedpopup = "writingtargetreachedpopup"; - public static final String monthly = "monthly"; - public static final String weekly = "weekly"; - public static final String daily = "daily"; - public static final String session = "session"; - public static final String enterpasswordpopup = "enterpasswordpopup"; - public static final String novalue = "novalue"; - public static final String invalidvalue = "invalidvalue"; - public static final String projectalreadyopen = "projectalreadyopen"; - public static final String invalidpassword = "invalidpassword"; - public static final String invalidstate = "invalidstate"; - public static final String open = "open"; - public static final String changestatus = "changestatus"; - public static final String restore = "restore"; - public static final String showerror = "showerror"; - public static final String viewbackupsdir = "viewbackupsdir"; - public static final String nobackups = "nobackups"; - public static final String show = "show"; - public static final String deleteitem = "deleteitem"; - public static final String confirmword = "confirmword"; - public static final String startat = "startat"; - public static final String endat = "endat"; - public static final String splitchapter = "splitchapter"; - public static final String newchaptername = "newchaptername"; - public static final String cantreopenproject = "cantreopenproject"; - //public static final String projectexists = "projectexists"; - public static final String renamechapter = "renamechapter"; - //public static final String chapterexists = "chapterexists"; - public static final String newchapter = "newchapter"; - public static final String deletetype = "deletetype"; - public static final String warning = "warning"; - public static final String valueexists = "valueexists"; - public static final String warmups = "warmups"; - public static final String deletewarmup = "deletewarmup"; - public static final String notifications = "notifications"; - public static final String remove = "remove"; - public static final String filefinder = "filefinder"; - public static final String errormessage = "errormessage"; - public static final String generalmessage = "generalmessage"; - public static final String iconcolumn = "iconcolumn"; - public static final String distractionfreemode = "distractionfreemode"; - public static final String viewitem = "viewitem"; - public static final String edititem = "edititem"; - public static final String moveitem = "moveitem"; - public static final String linkitem = "linkitem"; - public static final String manage = "manage"; - public static final String rename = "rename"; - public static final String colorchooser = "colorchooser"; - public static final String hex = "hex"; - public static final String red = "red"; - public static final String blue = "blue"; - public static final String green = "green"; - public static final String color = "color"; - public static final String swatch = "swatch"; - public static final String reset = "reset"; - public static final String objectfinder = "objectfinder"; - public static final String renamewarmup = "renamewarmup"; - public static final String editorproject = "editorproject"; - public static final String normal = "normal"; - public static final String editor = "editor"; - public static final String plural = "plural"; - public static final String headercontrols = "headercontrols"; - public static final String loading = "loading"; - public static final String notfound = "notfound"; - public static final String results = "results"; - public static final String findall = "findall"; - public static final String ignored = "ignored"; - public static final String unignore = "unignore"; - public static final String ignore = "ignore"; - public static final String checkbox = "checkbox"; - public static final String overlay = "overlay"; - public static final String deleteall = "deleteall"; - public static final String addsection = "addsection"; - public static final String newobject = "newobject"; - public static final String hidesection = "hidesection"; - public static final String addtag = "addtag"; - public static final String below = "below"; - public static final String tags = "tags"; - public static final String newtag = "newtag"; - public static final String table = "table"; - public static final String finish = "finish"; - public static final String loadallerror = "loadallerror"; - public static final String converttoproject = "converttoproject"; - public static final String entersummaryerror = "entersummaryerror"; - public static final String maxchars = "maxchars"; - public static final String dictionary = "dictionary"; - public static final String synonyms = "synonyms"; - public static final String formatting = "formatting"; - public static final String format = "format"; - public static final String bold = "bold"; - public static final String italic = "italic"; - public static final String underline = "underline"; - public static final String spellcheck = "spellcheck"; - public static final String nosuggestions = "nosuggestions"; - public static final String nosynonyms = "nosynonyms"; - public static final String more = "more"; - public static final String redo = "redo"; - public static final String undo = "undo"; - public static final String cut = "cut"; - public static final String paste = "paste"; - public static final String copy = "copy"; - public static final String textarea = "textarea"; - public static final String charsremaining = "charsremaining"; - public static final String charsover = "charsover"; - public static final String deletetag = "deletetag"; - public static final String prompt = "prompt"; - public static final String create = "create"; - public static final String newprojectpanel = "newprojectpanel"; - public static final String encrypt = "encrypt"; - public static final String password = "password"; - public static final String confirmpassword = "confirmpassword"; - public static final String nopassword = "nopassword"; - public static final String nomatch = "nomatch"; - public static final String savein = "savein"; - public static final String newwords = "newwords"; - public static final String nodirselected = "nodirselected"; - public static final String createexporter = "createexporter"; - public static final String objectnames = "objectnames"; - public static final String singular = "singular"; - public static final String convertwarmup = "convertwarmup"; - public static final String editwarmup = "editwarmup"; - public static final String enter = "enter"; - public static final String exit = "exit"; - public static final String firsttimepopup = "firsttimepopup"; - public static final String editproperties = "editproperties"; - public static final String sessionwordcount = "sessionwordcount"; - public static final String chapterwordcount = "chapterwordcount"; - public static final String word = "word"; - public static final String distractionfreemodeenter = "distractionfreemodeenter"; - public static final String distractionfreemodeexit = "distractionfreemodeexit"; - public static final String showproperties = "showproperties"; - public static final String achievementreached = "achievementreached"; - public static final String fullscreenexit = "fullscreenexit"; - public static final String changer = "changer"; - public static final String resetchange = "resetchange"; - public static final String confirmchange = "confirmchange"; - public static final String panel = "panel"; - public static final String nolinksedit = "nolinksedit"; - public static final String file = "file"; - public static final String othernames = "othernames"; - public static final String allowmulti = "allowmulti"; - public static final String multi = "multi"; - public static final String valueseparator = "valueseparator"; - public static final String addedit = "addedit"; - public static final String bulletpoints = "bulletpoints"; - public static final String max = "max"; - public static final String min = "min"; - public static final String greaterthanmin = "greaterthanmin"; - public static final String _default = "default"; - public static final String lessthanmax = "lessthanmax"; - public static final String smallicon = "smallicon"; - public static final String bigicon = "bigicon"; - public static final String warnings = "warnings"; - public static final String basic = "basic"; - public static final String userobjects = "userobjects"; - public static final String fields = "fields"; - public static final String move = "move"; - public static final String layout = "layout"; - public static final String layouts = "layouts"; - public static final String layout0 = "0"; - public static final String layout1 = "1"; - public static final String layout2 = "2"; - public static final String layout3 = "3"; - public static final String layout4 = "4"; - public static final String layout5 = "5"; - public static final String layout6 = "6"; - public static final String layout7 = "7"; - public static final String layout8 = "8"; - public static final String spellcheckon = "spellcheckon"; - public static final String spellcheckoff = "spellcheckoff"; - public static final String tools = "tools"; - public static final String wordcount = "wordcount"; - public static final String editorpanel = "editorpanel"; - public static final String textproperties = "textproperties"; - public static final String print = "print"; - public static final String convert = "convert"; - public static final String notetypes = "notetypes"; - public static final String removeeditposition = "removeeditposition"; - public static final String seteditcomplete = "seteditcomplete"; - public static final String showchapterinfo = "showchapterinfo"; - public static final String seteditposition = "seteditposition"; - public static final String compresstext = "compresstext"; - public static final String shortcutprefix = "shortcutprefix"; - public static final String doubleclickmenu = "doubleclickmenu"; - public static final String ideatypes = "ideatypes"; - public static final String ideas = "ideas"; - public static final String on = "on"; - public static final String off = "off"; - public static final String objectpreview = "objectpreview"; - public static final String newbelow = "newbelow"; - public static final String edittextproperties = "edittextproperties"; - public static final String chapters = "chapters"; - public static final String scenes = "scenes"; - public static final String outlineitems = "outlineitems"; - public static final String seteditneeded = "seteditneeded"; - public static final String ignoreall = "ignoreall"; - public static final String manageitems = "manageitems"; - public static final String newitems = "newitems"; - public static final String separators = "separators"; - public static final String status = "status"; - public static final String clicktoclose = "clicktoclose"; - public static final String clicktoview = "clicktoview"; - public static final String clicktohide = "clicktohide"; - public static final String doubleclicktoview = "doubleclicktoview"; - public static final String readability = "readability"; - public static final String projectwords = "projectwords"; - public static final String totalwords = "totalwords"; - public static final String selected = "selected"; - public static final String edited = "edited"; - public static final String allchapters = "allchapters"; - public static final String viewdetaillink = "viewdetaillink"; - public static final String helplink = "helplink"; - public static final String sparkline = "sparkline"; - public static final String valuepercent = "valuepercent"; - public static final String a4pages = "a4pages"; - public static final String documents = "documents"; - public static final String showfolder = "showfolder"; - public static final String noobjectselectedpanel = "noobjectselectedpanel"; - public static final String upgrade = "upgrade"; - public static final String download = "download"; - public static final String start = "start"; - public static final String cantcreatetemporaryfile = "cantcreatetemporaryfile"; - public static final String newversionavailable = "newversionavailable"; - public static final String exitnow = "exitnow"; - public static final String exitlater = "exitlater"; - public static final String unabletodownload = "unabletodownload"; - public static final String later = "later"; - public static final String restart = "restart"; - public static final String complete = "complete"; - public static final String digestinvalid = "digestinvalid"; - public static final String inprogress = "inprogress"; - public static final String checkingfile = "checkingfile"; - public static final String changedisplay = "changedisplay"; - public static final String managestatuses = "managestatuses"; - public static final String sortwordcount = "sortwordcount"; - public static final String sortstatus = "sortstatus"; - public static final String sortname = "sortname"; - public static final String sortlastedited = "sortlastedited"; - public static final String sortprojects = "sortprojects"; - public static final String findprojects = "findprojects"; - public static final String importfileorproject = "importfileorproject"; - public static final String noprojects = "noprojects"; - public static final String example = "example"; - public static final String selectbackground = "selectbackground"; - public static final String removeproject = "removeproject"; - public static final String projectopen = "projectopen"; - public static final String unspecified = "unspecified"; - public static final String error = "error"; - public static final String encrypted = "encrypted"; - public static final String tooltips = "tooltips"; - public static final String managebackups = "managebackups"; - public static final String newstatus = "newstatus"; - public static final String setstatus = "setstatus"; - public static final String editcomplete = "editcomplete"; - public static final String notedited = "notedited"; - public static final String lastedited = "lastedited"; - public static final String details = "details"; - public static final String nomoreproblems = "nomoreproblems"; - public static final String limit = "limit"; - public static final String unignoreall = "unignoreall"; - public static final String noproblemsfound = "noproblemsfound"; - public static final String end = "end"; - public static final String unignoreissues = "unignoreissues"; - public static final String wordtypes = "wordtypes"; - public static final String adverbs = "adverbs"; - public static final String other = "other"; - public static final String tabs = "tabs"; - public static final String verbs = "verbs"; - public static final String adjectives = "adjectives"; - public static final String nouns = "nouns"; - public static final String notfirst = "notfirst"; - public static final String firstusewizard = "firstusewizard"; - public static final String selectprojectdb = "selectprojectdb"; - public static final String existing = "existing"; - public static final String manual = "manual"; - public static final String imageselector = "imageselector"; - public static final String viewonlypanel = "viewonlypanel"; - public static final String testboolbarbuttonmessage = "testboolbarbuttonmessage"; - public static final String test = "test"; - public static final String bulletedtext = "bulletedtext"; - public static final String charts = "charts"; - public static final String allwordcounts = "allwordcounts"; - public static final String _for = "for"; - public static final String xaxis = "xaxis"; - public static final String yaxis = "yaxis"; - public static final String lastmonth = "lastmonth"; - public static final String thismonth = "thismonth"; - public static final String alltime = "alltime"; - public static final String lastweek = "lastweek"; - public static final String thisweek = "thisweek"; - public static final String perchapter = "perchapter"; - public static final String history = "history"; - public static final String showaverage = "showaverage"; - public static final String showtarget = "showtarget"; - public static final String markers = "markers"; - public static final String average = "average"; - public static final String target = "target"; - public static final String chaptersovertarget = "chaptersovertarget"; - public static final String averagesuffix = "averagesuffix"; - public static final String now = "now"; - public static final String forchapters = "forchapters"; - public static final String notarget = "notarget"; - public static final String detail = "detail"; - public static final String timeseries = "timeseries"; - public static final String added = "added"; - public static final String removed = "removed"; - public static final String showgf = "showgf"; - public static final String showfk = "showfk"; - public static final String showtargets = "showtargets"; - public static final String averagegf = "averagegf"; - public static final String averagegfsuffix = "averagegfsuffix"; - public static final String averagefk = "averagefk"; - public static final String averagefksuffix = "averagefksuffix"; - public static final String targetfk = "targetfk"; - public static final String targetgf = "targetgf"; - public static final String overtargetfk = "overtargetfk"; - public static final String overtargetgf = "overtargetgf"; - public static final String excluded = "excluded"; - public static final String notargets = "notargets"; - public static final String sessionlength = "sessionlength"; - public static final String sessions = "sessions"; - public static final String sessionsover1hr = "sessionsover1hr"; - public static final String sessionsovertarget = "sessionsovertarget"; - public static final String sessionmostwords = "sessionmostwords"; - public static final String numsessions = "numsessions"; - public static final String totalsessiontime = "totalsessiontime"; - public static final String numzerowordsessions = "numzerowordsessions"; - public static final String longestsession = "longestsession"; - public static final String averagesessionlength = "averagesessionlength"; - public static final String showzero = "showzero"; - public static final String averagesession = "averagesession"; - public static final String hide = "hide"; - public static final String rating = "rating"; - public static final String shorttext = "shorttext"; - public static final String sortrating = "sortrating"; - public static final String sortdate = "sortdate"; - public static final String sortalpha = "sortalpha"; - public static final String newidea = "newidea"; - public static final String noideas = "noideas"; - public static final String header = "header"; - public static final String defaulttypes = "defaulttypes"; - public static final String dialogue = "dialogue"; - public static final String none = "none"; - public static final String clear = "clear"; - public static final String image = "image"; - public static final String newtypes = "newtypes"; - public static final String newnotetype = "newnotetype"; - public static final String selectitem = "selectitem"; - public static final String unavailable = "unavailable"; - public static final String affirmativevalue = "affirmativevalue"; - public static final String notification = "notification"; - public static final String preview = "preview"; - public static final String nodescription = "nodescription"; - public static final String problemcount = "problemcount"; - public static final String spellingcount = "spellingcount"; - public static final String emptychapter = "emptychapter"; - public static final String notapplicable = "notapplicable"; - public static final String apply = "apply"; - public static final String defaults = "defaults"; - public static final String names = "names"; - public static final String unabletoopenfile = "unabletoopenfile"; - public static final String unabletoopenwebpage = "unabletoopenwebpage"; - public static final String appendix = "appendix"; - public static final String bookdetails = "bookdetails"; - public static final String authorname = "authorname"; - public static final String id = "id"; - public static final String addor = "andor"; - public static final String time = "time"; - public static final String timer = "timer"; - public static final String remaining = "remaining"; - public static final String less1min = "less1min"; - public static final String over1min = "over1min"; - public static final String noname = "noname"; - public static final String adddesctochapter = "adddesctochapter"; - public static final String chapteritems = "chapteritems"; - public static final String mywriting = "mywriting"; - public static final String showmessagewhentargetreached = "showmessagewhentargetreached"; - public static final String showwarningwhenchapterexceedsmax = "showwarningwhenchapterexceedsmax"; - public static final String chaptersovermaxtarget = "chaptersovermaxtarget"; - public static final String chaptersoverreadabilitytarget = "chaptersoverreadabilitytarget"; - public static final String overlimit = "overlimit"; - public static final String maximum = "maximum"; - public static final String unabletoperformaction = "unabletoperformaction"; - public static final String fullscreentitle = "fullscreentitle"; - public static final String deletesceneoutlineitems = "deletesceneoutlineitems"; - public static final String fontsize = "fontsize"; - public static final String alignment = "alignment"; - public static final String linespacing = "linespacing"; - public static final String textborder = "textborder"; - public static final String indentfirstline = "indentfirstline"; - public static final String highlightwritingline = "highlightwritingline"; - public static final String highlightlinecolor = "highlightlinecolor"; - public static final String textcolor = "textcolor"; - public static final String bgcolor = "bgcolor"; - public static final String bgopacity = "bgopacity"; - public static final String bgimagewebsites = "bgimagewebsites"; - public static final String fullscreenproperties = "fullscreenproperties"; - public static final String areasize = "areasize"; - public static final String showtimewordcount = "showtimewordcount"; - public static final String versions = "versions"; - public static final String qwstart = "qwstart"; - public static final String showtips = "showtips"; - public static final String showlastedited = "showlastedited"; - public static final String showprojectswindow = "showprojectswindow"; - public static final String betas = "betas"; - public static final String optin = "optin"; - public static final String itemsandrules = "itemsandrules"; - public static final String autologin = "autologin"; - public static final String defaultstatus = "defaultstatus"; - public static final String statuses = "statuses"; - public static final String online = "online"; - public static final String offline = "offline"; - public static final String busy = "busy"; - public static final String away = "away"; - public static final String snooze = "snooze"; - public static final String fullscreenbusystatus = "fullscreenbusystatus"; - public static final String logmessages = "logmessages"; - public static final String problemfinderrules = "problemfinderrules"; - public static final String editingchapters = "editingchapters"; - public static final String haseditposition = "haseditposition"; - public static final String showicon = "showicon"; - public static final String autosave = "autosave"; - public static final String autosavewhen = "autosavewhen"; - public static final String viewexample = "viewexample"; - public static final String showeditposition = "showeditposition"; - public static final String seteditpositioncolor = "seteditpositioncolor"; - public static final String seteditcompleteatchapterend = "seteditcompleteatchapterend"; - public static final String compressrightclickmenu = "compressrightclickmenu"; - public static final String setspellcheckerlanguage = "setspellcheckerlanguage"; - public static final String downloadlanguagefiles = "downloadlanguagefiles"; - public static final String setasdefaultlanguage = "setasdefaultlanguage"; - public static final String nonenglishwarning = "nonenglishwarning"; - public static final String downloaddictionaryfiles = "downloaddictionaryfiles"; - public static final String managedictionary = "managedictionary"; - public static final String naming = "naming"; - public static final String changenames = "changenames"; - public static final String keepprojectswindowsopen = "keepprojectswindowsopen"; - public static final String showprojectswindownoopenproject = "showprojectswindownoopenproject"; - public static final String showpreview = "showpreview"; - public static final String shownotes = "shownotes"; - public static final String lookandsound = "lookandsound"; - public static final String interfacelayout = "interfacelayout"; - public static final String interfacelayouts = "interfacelayouts"; - public static final String showtoolbar = "showtoolbar"; - public static final String belowsidebar = "belowsidebar"; - public static final String abovesidebar = "abovesidebar"; - public static final String showtabs = "showtabs"; - public static final String showtabstop = "showtabstop"; - public static final String showtabsbottom = "showtabsbottom"; - public static final String whenfind = "whenfind"; - public static final String expandall = "expandall"; - public static final String justchapter = "justchapter"; - public static final String playtypewritersound = "playtypewritersound"; - public static final String usesound = "usesound"; - public static final String selectownwavfile = "selectownwavfile"; - public static final String highlightdividers = "highlightdividers"; - public static final String filter = "filter"; - public static final String newasset = "newasset"; - public static final String alwayspopup = "alwayspopup"; - public static final String popupifpossible = "popupifpossible"; - public static final String owntab = "owntab"; - public static final String editassetconfig = "editassetconfig"; - public static final String addtype = "addtype"; - public static final String projectandbackup = "projectandbackup"; - public static final String selectprojectdir = "selectprojectdir"; - public static final String all = "all"; - public static final String autobackup = "autobackup"; - public static final String createbackupafter = "createbackupafter"; - public static final String nobackupstokeep = "nobackupstokeep"; - public static final String selectbackupdir = "selectbackupdir"; - public static final String link = "link"; - public static final String savepropertyerror = "savepropertyerror"; - public static final String changeprojectdir = "changeprojectdir"; - public static final String backupdirchangewarning = "backupdirchangewarning"; - public static final String reopenproject = "reopenproject"; - public static final String dirnotempty = "dirnotempty"; - public static final String backupdirnotempty = "backupdirnotempty"; - public static final String changebackupdir = "changebackupdir"; - public static final String usedefault = "usedefault"; - public static final String examplechapter = "examplechapter"; - public static final String uilanguage = "uilanguage"; - //public static final String select = "select"; - public static final String downloading = "downloading"; - public static final String restartwarning = "restartwarning"; - public static final String set = "set"; - public static final String createtranslation = "createtranslation"; - public static final String edittranslation = "edittranslation"; - public static final String feedback = "feedback"; - public static final String switchtoversion = "switchtoversion"; - public static final String comment = "comment"; - public static final String unsentcommentspopup = "unsentcommentspopup"; - public static final String unsentcomments = "unsentcomments"; - public static final String editcomment = "editcomment"; - public static final String viewertitle = "viewertitle"; - public static final String viewertitleversionwrapper = "viewertitleversionwrapper"; - public static final String previouscontact = "previouscontact"; - public static final String viewcomment = "viewcomment"; - public static final String auto = "auto"; - public static final String login = "login"; - public static final String messages = "messages"; - public static final String undealtwith = "undealtwith"; - public static final String reasons = "reasons"; - public static final String updateinfotoall = "updateinfotoall"; - public static final String updateinfotocontact = "updateinfotocontact"; - public static final String sendmessagetocontact = "sendmessagetocontact"; - public static final String invitesent = "invitesent"; - public static final String sendprojectoninvite = "sendprojectoninvite"; - public static final String sendinvite = "sendinvite"; - public static final String editoroffline = "editoroffline"; - public static final String deleteaccount = "deleteaccount"; - public static final String deletealleditorprojects = "deletealleditorprojects"; - public static final String deleteprojectsforeditor = "deleteprojectsforeditor"; - public static final String avatar = "avatar"; - public static final String accept = "accept"; - public static final String reject = "reject"; - public static final String updated = "updated"; - public static final String sendproject = "sendproject"; - public static final String updateproject = "updateproject"; - public static final String firstupdatewithversion = "firstupdatewithversion"; - public static final String firstupdate = "firstupdate"; - public static final String lastupdatewithversion = "lastupdatewithversion"; - public static final String lastupdate = "lastupdate"; - public static final String sendorupdateproject = "sendorupdateproject"; - public static final String nochapters = "nochapters"; - public static final String unsavedchanges = "unsavedchanges"; - public static final String dueby = "dueby"; - public static final String updatesuffix = "updatesuffix"; - public static final String version = "version"; - public static final String editorstatus = "editorstatus"; - public static final String sendunsentcomments = "sendunsentcomments"; - public static final String comments = "comments"; - public static final String reportmessage = "reportmessage"; - public static final String from = "from"; - public static final String reason = "reason"; - public static final String changepassword = "changepassword"; - public static final String newpassword = "newpassword"; - public static final String register = "register"; - public static final String exists = "exists"; - public static final String savepasswordwarningpopup = "savepasswordwarningpopup"; - public static final String prefix = "prefix"; - public static final String invalidcredentials = "invalidcredentials"; - public static final String alreadyregistered = "alreadyregistered"; - public static final String agreetandc = "agreetandc"; - public static final String viewtandc = "viewtandc"; - public static final String youremail = "youremail"; - public static final String alreadyinvited = "alreadyinvited"; - public static final String previousrejected = "previousrejected"; - public static final String inviteeditor = "inviteeditor"; - public static final String invite = "invite"; - public static final String noemail = "noemail"; - public static final String self = "self"; - public static final String showprojectscontactisediting = "showprojectscontactisediting"; - public static final String showprojectseditingforcontact = "showprojectseditingforcontact"; - public static final String commentssent = "commentssent"; - public static final String commentsreceived = "commentsreceived"; - public static final String important = "important"; - public static final String suffix = "suffix"; - public static final String projectupdated = "projectupdated"; - public static final String inactiveaccount = "inactiveaccount"; - public static final String maxloginattempts = "maxloginattempts"; - public static final String deleteinvite = "deleteinvite"; - public static final String updateinvite = "updateinvite"; - public static final String sendchat = "sendchat"; - public static final String contactistyping = "contactistyping"; - public static final String sending = "sending"; - public static final String box = "box"; - public static final String received = "received"; - public static final String response = "response"; - public static final String update = "update"; - public static final String sent = "sent"; - public static final String report = "report"; - public static final String attention = "attention"; - public static final String resendinvite = "resendinvite"; - public static final String allmessages = "allmessages"; - public static final String removecontact = "removecontact"; - public static final String updatecontactinfo = "updatecontactinfo"; - public static final String projectscontactediting = "projectscontactediting"; - public static final String sendupdateproject = "sendupdateproject"; - public static final String viewcommentserror = "viewcommentserror"; - public static final String lastcommentssent = "lastcommentssent"; - public static final String lastcommentsreceived = "lastcommentsreceived"; - public static final String projectsuserediting = "projectsuserediting"; - public static final String projectupdates = "projectupdates"; - public static final String importantmessages = "importantmessages"; - public static final String sendmessage = "sendmessage"; - public static final String unreadchatmessages = "unreadchatmessages"; - public static final String noprojectcomments = "noprojectcomments"; - public static final String projectcomments = "projectcomments"; - public static final String undealtwithmessagecount = "undealtwithmessagecount"; - public static final String projecteditor = "projecteditor"; - public static final String onlinestatus = "onlinestatus"; - public static final String previouseditor = "previouseditor"; - public static final String pendingeditor = "pendingeditor"; - public static final String invitereceived = "invitereceived"; - public static final String currenteditor = "currenteditor"; - public static final String contactinfo = "contactinfo"; - public static final String inviteresponse = "inviteresponse"; - public static final String dealtwith = "dealtwith"; - public static final String rejected = "rejected"; - public static final String accepted = "accepted"; - public static final String contactremoved = "contactremoved"; - public static final String chatmessages = "chatmessages"; - public static final String today = "today"; - public static final String yesterday = "yesterday"; - public static final String sentbyme = "sentbyme"; - public static final String redownload = "redownload"; - public static final String editneededtitle = "editneededtitle"; - public static final String editneedednote = "editneedednote"; - public static final String font = "font"; - public static final String shortcut = "shortcut"; - public static final String projecteditstop = "projecteditstop"; - public static final String newprojectresponse = "newprojectresponse"; - public static final String extra = "extra"; - public static final String clicktoviewproject = "clicktoviewproject"; - public static final String clicktoviewcomments = "clicktoviewcomments"; - public static final String othercomments = "othercomments"; - public static final String item = "item"; - public static final String displaypassword = "displaypassword"; - public static final String resetpassword = "resetpassword"; - public static final String resendaccountconfirmationemail = "resendaccountconfirmationemail"; - public static final String updatenameavatar = "updatenameavatar"; - public static final String previouscontacts = "previouscontacts"; - public static final String preferences = "preferences"; - public static final String logout = "logout"; - public static final String invitesfromothers = "invitesfromothers"; - public static final String allcontacts = "allcontacts"; - public static final String pendinginvites = "pendinginvites"; - public static final String nocontacts = "nocontacts"; - public static final String firstlogin = "firstlogin"; - public static final String savepassword = "savepassword"; - public static final String otherversions = "otherversions"; - public static final String noversion = "noversion"; - public static final String unsent = "unsent"; - public static final String projectsent = "projectsent"; - public static final String viewchapter = "viewchapter"; - public static final String commentspanel = "commentspanel"; - public static final String logindetails = "logindetails"; - public static final String minlength = "minlength"; - public static final String reminderpopup = "reminderpopup"; - public static final String check = "check"; - public static final String selectfolder = "selectfolder"; - public static final String saving = "saving"; - public static final String newcomment = "newcomment"; - public static final String due = "due"; - public static final String latest = "latest"; - public static final String newupdateproject = "newupdateproject"; - public static final String notspecified = "notspecified"; - public static final String projectdeleted = "projectdeleted"; - public static final String previouseditors = "previouseditors"; - public static final String hidepreviouseditors = "hidepreviouseditors"; - public static final String unknownproject = "unknownproject"; - public static final String notinlist = "notinlist"; - public static final String fkfull = "fkfull"; - public static final String frfull = "frfull"; - public static final String gffull = "gffull"; - public static final String defaultchaptername = "defaultchaptername"; - public static final String defaultstatuses = "defaultstatuses"; - public static final String editneededtype = "editneededtype"; - -} diff --git a/src/com/quollwriter/QuollWriterSecurityManager.java b/src/com/quollwriter/QuollWriterSecurityManager.java deleted file mode 100644 index d5c2ddd5..00000000 --- a/src/com/quollwriter/QuollWriterSecurityManager.java +++ /dev/null @@ -1,46 +0,0 @@ -package com.quollwriter; - -import java.security.*; - - -public class QuollWriterSecurityManager extends SecurityManager -{ - - public QuollWriterSecurityManager() - { - - super (); - - } - - /* - public void checkConnect (String host, - int port) - { - - System.out.println ("CALLED: " + host + ":" + port); - - } - */ - /* - public void checkSetFactory () - { - - System.out.println ("HERE 3"); - - } - - public void checkPermission (Permission perm, - Object context) - { - System.out.println ("HERE 5: " + perm); - if (perm.getName ().equals ("setSecurityManager")) - { - System.out.println ("HERE 4"); - new KillSwitch (); - - } - - } - */ -} diff --git a/src/com/quollwriter/QuollWriterUpdater.java b/src/com/quollwriter/QuollWriterUpdater.java deleted file mode 100644 index c55ffe06..00000000 --- a/src/com/quollwriter/QuollWriterUpdater.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.quollwriter; - -import com.quollwriter.ui.*; - -public interface QuollWriterUpdater -{ - - public void doUpdate (AbstractViewer viewer); - -} diff --git a/src/com/quollwriter/RefValueProvider.java b/src/com/quollwriter/RefValueProvider.java deleted file mode 100644 index 34e59664..00000000 --- a/src/com/quollwriter/RefValueProvider.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.quollwriter; - -public interface RefValueProvider -{ - - public String getString (String id); - - public String getRawText (String id); - - public int getSCount (String id); - -} diff --git a/src/com/quollwriter/Startup.java b/src/com/quollwriter/Startup.java deleted file mode 100644 index 87759311..00000000 --- a/src/com/quollwriter/Startup.java +++ /dev/null @@ -1,156 +0,0 @@ -package com.quollwriter; - -import java.io.*; -import java.nio.channels.*; - -import java.util.*; - -import javax.swing.*; - -import com.quollwriter.data.*; - -import com.quollwriter.ui.*; - -public class Startup -{ - - public static void main (String[] argv) - { - - if ((argv != null) && - (argv.length > 0)) - { - - if (argv[0].equals ("_debugMode")) - { - - Environment.setDebugModeEnabled (true); - - } - - } - - SplashScreen ss = null; - - try - { - - ss = new SplashScreen (Environment.getLogo ().getImage (), - "Starting...", - com.quollwriter.ui.UIUtils.getColor ("#f9f9f9")); - - ss.setProgress (5); - - Environment.init (); - - if (Environment.isFirstUse ()) - { - - new FirstUseWizard ().init (); - - return; - - } - - if (Environment.getAllProjectInfos ().size () == 0) - { - - ss.finish (); - - Environment.showLanding (); - - return; - - } - - boolean showError = false; - - if (UserProperties.getAsBoolean (Constants.SHOW_LANDING_ON_START_PROPERY_NAME)) - { - - Environment.showLanding (); - - } - - // See if the user property is to open the last edited project. - if (UserProperties.getAsBoolean (Constants.OPEN_LAST_EDITED_PROJECT_PROPERTY_NAME)) - { - - try - { - - if (!Environment.openLastEditedProject ()) - { - - showError = true; - - } - - } catch (Exception e) - { - - showError = true; - - } - - } - - // Need to do this here since, if there is no visible frame (somewhere) then showErrorMessage will throw an error that crashes the jvm... nice... - if (showError) - { - - Environment.showLanding (); - - UIUtils.showMessage ((java.awt.Component) null, - Environment.getUIString (LanguageStrings.startup, - LanguageStrings.cantopenlastprojecterror, - LanguageStrings.title), - //"Unable to open last {project}", - Environment.getUIString (LanguageStrings.startup, - LanguageStrings.cantopenlastprojecterror, - LanguageStrings.text)); - //"Unable to open last edited {project}, please select another {project} or create a new one."); - - } - - } catch (Exception eee) - { - - if (eee instanceof OverlappingFileLockException) - { - - UIUtils.showErrorMessage (null, - Environment.getUIString (LanguageStrings.startup, - LanguageStrings.alreadyrunningerror)); - //"It appears that Quoll Writer is already running. Please close the other instance before starting Quoll Writer again."); - - - } else { - - Environment.logError ("Unable to open Quoll Writer", - eee); - - UIUtils.showErrorMessage (null, - Environment.getUIString (LanguageStrings.startup, - LanguageStrings.unabletostarterror)); - //"Unable to start Quoll Writer"); - - } - - } finally - { - - if (ss != null) - { - - ss.finish (); - - } - - Environment.startupComplete (); - - } - - } - -} diff --git a/src/com/quollwriter/StringWithMarkup.java b/src/com/quollwriter/StringWithMarkup.java deleted file mode 100644 index 0bad4da8..00000000 --- a/src/com/quollwriter/StringWithMarkup.java +++ /dev/null @@ -1,119 +0,0 @@ -package com.quollwriter; - -import com.quollwriter.ui.components.Markup; - -public class StringWithMarkup -{ - - private String text = null; - private Markup markup = null; - - public StringWithMarkup (String text, - Markup markup) - { - - this.text = text; - this.markup = markup; - - } - - public StringWithMarkup (String text, - String markup) - { - - this.text = text; - - if (markup != null) - { - - this.markup = new Markup (markup); - - } - - } - - public StringWithMarkup (String text) - { - - this.text = text; - - } - - public boolean hasText () - { - - if (this.text == null) - { - - return false; - - } - - return this.text.trim ().length () > 0; - - } - - public void update (StringWithMarkup t) - { - - if (t.getText () != null) - { - - this.text = new String (t.getText ()); - - } - - if (t.getMarkup () != null) - { - - this.markup = new Markup (t.getMarkup ().toString ()); - - } - - } - - public void update (String text, - Markup markup) - { - - this.text = text; - this.markup = markup; - - } - - public String getMarkedUpText () - { - - if (this.text == null) - { - - return null; - - } - - if (this.markup == null) - { - - return this.text; - - } - - return this.markup.markupAsHTML (this.text); - - } - - public String getText () - { - - return this.text; - - } - - public Markup getMarkup () - { - - return this.markup; - - } - -} \ No newline at end of file diff --git a/src/com/quollwriter/UrlDownloader.java b/src/com/quollwriter/UrlDownloader.java deleted file mode 100644 index 11cb757d..00000000 --- a/src/com/quollwriter/UrlDownloader.java +++ /dev/null @@ -1,163 +0,0 @@ -package com.quollwriter; - -import java.net.*; -import java.io.*; - -public class UrlDownloader -{ - - private URL url = null; - private DownloadListener list = null; - private File toFile = null; - private boolean stop = false; - private boolean inProgress = false; - - public UrlDownloader (URL url, - File toFile, - DownloadListener l) - { - - this.url = url; - this.toFile = toFile; - this.list = l; - - } - - public boolean isInProgress () - { - - return this.inProgress; - - } - - public void start () - { - - this.stop = false; - - if (this.inProgress) - { - - return; - - } - - this.inProgress = true; - - final UrlDownloader _this = this; - - new Thread (new Runnable () - { - - public void run () - { - - InputStream in = null; - OutputStream out = null; - - try - { - - URLConnection conn = _this.url.openConnection (); - - int length = conn.getContentLength (); - - in = new BufferedInputStream (conn.getInputStream ()); - out = new BufferedOutputStream (new FileOutputStream (_this.toFile)); - - byte[] buf = new byte[8192]; - - int bRead = -1; - - int total = 0; - - while ((bRead = in.read (buf)) != -1) - { - - if (_this.stop) - { - - in.close (); - out.flush (); - out.close (); - - return; - - } - - total += bRead; - - out.write (buf, - 0, - bRead); - - if (_this.list != null) - { - - _this.list.progress (total, - length); - - } - - } - - in.close (); - out.flush (); - out.close (); - - if (_this.list != null) - { - - _this.list.finished (length); - - } - - } catch (Exception e) { - - if (_this.list != null) - { - - _this.list.handleError (e); - - } - - } finally { - - _this.inProgress = false; - - try - { - - if (in != null) - { - - in.close (); - - } - - if (out != null) - { - - out.flush (); - out.close (); - - } - - } catch (Exception e) {} - - } - - } - - }).start (); - - } - - public void stop () - { - - this.stop = true; - - } - -} \ No newline at end of file diff --git a/src/com/quollwriter/UserProperties.java b/src/com/quollwriter/UserProperties.java deleted file mode 100644 index 338d4003..00000000 --- a/src/com/quollwriter/UserProperties.java +++ /dev/null @@ -1,331 +0,0 @@ -package com.quollwriter; - -import java.io.*; - -import java.util.Map; -import java.util.WeakHashMap; -import java.util.LinkedHashSet; -import java.util.Collections; -import java.util.Set; - -import java.awt.event.*; - -import com.gentlyweb.properties.*; - -import com.quollwriter.ui.*; -import com.quollwriter.events.*; - -public class UserProperties -{ - - private static com.gentlyweb.properties.Properties props = new com.gentlyweb.properties.Properties (); - private static Map listeners = null; - - // Just used in the map above as a placeholder for the listeners. - private static final Object listenerFillObj = new Object (); - - static - { - - UserProperties.listeners = Collections.synchronizedMap (new WeakHashMap ()); - - } - - private UserProperties () - { - - } - - public static void init (com.gentlyweb.properties.Properties props) - { - - if (props == null) - { - - throw new NullPointerException ("Properties must be specified"); - - } - - UserProperties.props = props; - - } - - public static void removeListener (UserPropertyListener l) - { - - UserProperties.listeners.remove (l); - - } - - /** - * Adds a listener for property events. Warning! This will be a soft reference that can - * disappear so make sure you have a strong reference to your listener. - * - * @param l The listener. - */ - public static void addListener (UserPropertyListener l) - { - - UserProperties.listeners.put (l, - UserProperties.listenerFillObj); - - } - - public static void fireUserPropertyEvent (Object source, - String name, - AbstractProperty prop, - UserPropertyEvent.Type action) - { - - UserProperties.fireUserPropertyEvent (new UserPropertyEvent (source, - name, - prop, - action)); - - } - - public static void fireUserPropertyEvent (final UserPropertyEvent ev) - { - - UIUtils.doActionLater (new ActionListener () - { - - public void actionPerformed (ActionEvent aev) - { - - Set ls = null; - - // Get a copy of the current valid listeners. - synchronized (UserProperties.listeners) - { - - ls = new LinkedHashSet (UserProperties.listeners.keySet ()); - - } - - for (UserPropertyListener l : ls) - { - - l.propertyChanged (ev); - - } - - } - - }); - - } - - public static void remove (String name) - { - - UserProperties.props.removeProperty (name); - - UserProperties.fireUserPropertyEvent (UserProperties.listenerFillObj, - name, - null, - UserPropertyEvent.Type.removed); - - UserProperties.save (); - - } - - public static void set (String name, - AbstractProperty prop) - { - - UserProperties.props.setProperty (name, - prop); - - UserProperties.fireUserPropertyEvent (UserProperties.listenerFillObj, - name, - prop, - UserPropertyEvent.Type.changed); - - UserProperties.save (); - - } - - public static void set (String name, - String value) - { - - UserProperties.set (name, - new StringProperty (name, - value)); - - UserProperties.save (); - - } - - public static void set (String name, - boolean value) - { - - UserProperties.set (name, - new BooleanProperty (name, - value)); - - UserProperties.save (); - - } - - public static void set (String name, - float value) - { - - UserProperties.set (name, - new FloatProperty (name, - value)); - - UserProperties.save (); - - } - - public static void set (String name, - int value) - { - - UserProperties.set (name, - new IntegerProperty (name, - value)); - - UserProperties.save (); - - } - - public static boolean getAsBoolean (String name, - String defOnNull) - { - - AbstractProperty a = UserProperties.props.getPropertyObj (name); - - if (a == null) - { - - return UserProperties.getAsBoolean (defOnNull); - - } - - return UserProperties.props.getPropertyAsBoolean (name); - - } - - public static boolean getAsBoolean (String name) - { - - return UserProperties.props.getPropertyAsBoolean (name); - - } - - public static int getAsInt (String name, - String defOnNull) - { - - AbstractProperty a = UserProperties.props.getPropertyObj (name); - - if (a == null) - { - - return UserProperties.getAsInt (defOnNull); - - } - - return UserProperties.props.getPropertyAsInt (name); - - } - - public static int getAsInt (String name) - { - - return UserProperties.props.getPropertyAsInt (name); - - } - - public static File getAsFile (String name) - { - - return UserProperties.props.getPropertyAsFile (name); - - } - - public static float getAsFloat (String name, - String defOnNull) - { - - AbstractProperty a = UserProperties.props.getPropertyObj (name); - - if (a == null) - { - - return UserProperties.getAsFloat (defOnNull); - - } - - return UserProperties.props.getPropertyAsFloat (name); - - } - - public static float getAsFloat (String name) - { - - return UserProperties.props.getPropertyAsFloat (name); - - } - - public static String get (String name, - String defOnNull) - { - - AbstractProperty a = UserProperties.props.getPropertyObj (name); - - if (a == null) - { - - return UserProperties.get (defOnNull); - - } - - return UserProperties.props.getProperty (name); - - } - - public static String get (String name) - { - - return UserProperties.props.getProperty (name); - - } - - public static AbstractProperty getProperty (String name) - { - - return UserProperties.props.getPropertyObj (name); - - } - - public static Properties getProperties () - { - - return UserProperties.props; - - } - - private static void save () - { - - try - { - - Environment.saveUserProperties (); - - } catch (Exception e) { - - Environment.logError ("Unable to set user properties", - e); - - } - - } - -} diff --git a/src/com/quollwriter/Utils.java b/src/com/quollwriter/Utils.java deleted file mode 100644 index 4c29d6f7..00000000 --- a/src/com/quollwriter/Utils.java +++ /dev/null @@ -1,1888 +0,0 @@ -package com.quollwriter; - -import java.io.*; -import java.awt.event.*; - -import java.text.*; -import java.net.*; -import java.util.*; -import java.util.zip.*; -import java.nio.file.*; -import java.nio.charset.*; - -import javax.swing.*; - -import org.jdom.*; -import org.jdom.output.*; - -import com.gentlyweb.xml.*; - -import com.gentlyweb.utils.*; -import com.quollwriter.ui.*; - -import com.quollwriter.data.*; - -public class Utils -{ - - public static String getElementAsString (Element el) - throws IOException - { - - StringWriter sout = new StringWriter (); - PrintWriter pout = new PrintWriter (new BufferedWriter (sout)); - - // Output the rule to the string... - XMLOutputter xout = new XMLOutputter (); - - xout.setFormat (org.jdom.output.Format.getPrettyFormat ()); - System.out.println ("T: " + xout.getFormat ().getEncoding ()); - xout.output (el, - pout); - - pout.flush (); - pout.close (); - - return sout.toString (); - - } - - public static String getStreamAsString (InputStream in, - Charset ch) - throws Exception - { - - BufferedInputStream _in = new BufferedInputStream (in); - - ByteArrayOutputStream out = new ByteArrayOutputStream (); - - int r = -1; - - byte[] bytes = new byte[65536]; - - while ((r = _in.read (bytes, 0, 65536)) > 0) - { - - out.write (bytes, - 0, - r); - - } - - out.flush (); - out.close (); - _in.close (); - - return (ch != null ? new String (out.toByteArray (), ch) : new String (out.toByteArray ())); - - } - - public static String getFileAsString (File f, - Charset ch) - throws Exception - { - - return Utils.getStreamAsString (new FileInputStream (f), - ch); - - } - - public static String keyStrokeToString (KeyStroke k) - { - - if (k == null) - { - - return null; - - } - - StringBuilder b = new StringBuilder (); - - String m = KeyEvent.getKeyModifiersText (k.getModifiers ()); - - if (m.length () > 0) - { - - b.append (StringUtils.replaceString (m.toLowerCase (), - "+", - " ")); - b.append (" "); - - } - - b.append (KeyEvent.getKeyText (k.getKeyCode ()).toUpperCase ()); - - return b.toString (); - - } - - public static List splitString (String str, - String separator) - { - - List ret = new ArrayList (); - - if (str == null) - { - - return ret; - - } - - StringTokenizer t = new StringTokenizer (str, - separator); - - while (t.hasMoreTokens ()) - { - - ret.add (t.nextToken ()); - - } - - return ret; - - } - - public static String joinStrings (Collection items, - String separator) - { - - if ((items == null) - || - (items.size () == 0) - ) - { - - return null; - - } - - StringBuilder b = new StringBuilder (); - - Iterator iter = items.iterator (); - - while (iter.hasNext ()) - { - - b.append (iter.next ()); - - if (iter.hasNext ()) - { - - b.append (separator != null ? separator : ", "); - - } - - } - - return b.toString (); - - } - - public static boolean isSubDir (File parent, - File sub) - { - - File p = sub.getParentFile (); - - if (p == null) - { - - return false; - - } - - if (p.equals (parent)) - { - - return true; - - } - - return Utils.isSubDir (parent, - p); - - } - - public static String checkEmail (String em) - { - - String err = Environment.getUIString (LanguageStrings.form, - LanguageStrings.errors, - LanguageStrings.invalidemail); - //"Email does not appear to be valid."; - - if ((em == null) - || - (em.trim ().equals ("")) - ) - { - - return null; - - } - - int ind = em.indexOf ("@"); - - if (ind < 1) - { - - return err; - - } - - int ind2 = em.indexOf (".", - ind + 1); - - if (ind2 < 1) - { - - return err; - - } else { - - if (em.length () - 1 == ind2) - { - - return err; - - } - - } - - return null; - - } - - public static String getStatisticsAsXML (Map stats) - { - - if (stats == null) - { - - return null; - - } - - if (stats.size () == 0) - { - - return null; - - } - - Element root = new Element (Environment.XMLConstants.stats); - - Iterator iter = stats.keySet ().iterator (); - - while (iter.hasNext ()) - { - - ProjectInfo.Statistic s = iter.next (); - - Object v = stats.get (s); - - if ((s != null) - && - (v != null) - ) - { - - Element stat = new Element (Environment.XMLConstants.stat); - - root.addContent (stat); - - stat.setAttribute (Environment.XMLConstants.id, - s.getType ()); - stat.addContent (v.toString ()); - - if (v instanceof String) - { - - stat.setAttribute (Environment.XMLConstants.type, - "string"); - - } - - if (v instanceof Number) - { - - stat.setAttribute (Environment.XMLConstants.type, - "number"); - - } - - } - - } - - try - { - - return JDOMUtils.getElementAsString (root); - - } catch (Exception e) { - - Environment.logError ("Unable to convert element to string for statistics: " + - stats, - e); - - return null; - - } - - } - - public static Map getStatisticsFromXML (String t) - { - - Map ret = new HashMap (); - - if (t == null) - { - - return ret; - - } - - Element root = null; - - try - { - - root = JDOMUtils.getStringAsElement (t); - - } catch (Exception e) { - - Environment.logError ("Unable to convert string: " + - t + - " to an element", - e); - - return ret; - - } - - List els = null; - - try - { - - els = JDOMUtils.getChildElements (root, - Environment.XMLConstants.stat, - false); - - } catch (Exception e) { - - Environment.logError ("Unable to get child stat elements: " + - e); - - return ret; - - } - - for (int i = 0; i < els.size (); i++) - { - - Element el = (Element) els.get (i); - - try - { - - String val = JDOMUtils.getChildContent (el); - - String id = JDOMUtils.getAttributeValue (el, - Environment.XMLConstants.id, - true); - - String type = JDOMUtils.getAttributeValue (el, - Environment.XMLConstants.type, - true); - - if (type.equals ("number")) - { - - ret.put (ProjectInfo.Statistic.valueOf (id), - Double.parseDouble (val)); - - } - - if (type.equals ("string")) - { - - ret.put (ProjectInfo.Statistic.valueOf (id), - val); - - } - - } catch (Exception e) { - - Environment.logError ("Unable to get stats info from element: " + - JDOMUtils.getPath (el), - e); - - } - - } - - return ret; - - } - - public static Set getFilesFromXML (String t) - { - - Set ret = new LinkedHashSet (); - - if (t == null) - { - - return ret; - - } - - Element root = null; - - try - { - - root = JDOMUtils.getStringAsElement (t); - - } catch (Exception e) { - - Environment.logError ("Unable to convert string: " + - t + - " to an element", - e); - - return ret; - - } - - List els = null; - - try - { - - els = JDOMUtils.getChildElements (root, - Environment.XMLConstants.file, - false); - - } catch (Exception e) { - - Environment.logError ("Unable to get child file elements: " + - e); - - return ret; - - } - - // Get the user ones. - for (int i = 0; i < els.size (); i++) - { - - Element el = (Element) els.get (i); - - try - { - - String tf = JDOMUtils.getChildContent (el); - - File f = new File (tf); - - ret.add (f); - - } catch (Exception e) { - - Environment.logError ("Unable to get file info from element: " + - JDOMUtils.getPath (el), - e); - - } - - } - - return ret; - - } - - public static String getFilesAsXML (Set files) - { - - if (files == null) - { - - return null; - - } - - if (files.size () == 0) - { - - return null; - - } - - Element root = new Element (Environment.XMLConstants.files); - - for (File f : files) - { - - Element fel = new Element (Environment.XMLConstants.file); - - root.addContent (fel); - - fel.addContent (f.getPath ()); - - } - - try - { - - return JDOMUtils.getElementAsString (root); - - } catch (Exception e) { - - Environment.logError ("Unable to convert element to string for files: " + - files, - e); - - return null; - - } - - } - - public static void getContentFromURL (final URL url, - final Map headers, - final ActionListener onSuccess, - final ActionListener onError, - final ActionListener onFailure) - { - - new Thread (new Runnable () - { - - public void run () - { - - try - { - - HttpURLConnection conn = (HttpURLConnection) url.openConnection (); - - if (headers != null) - { - - Iterator iter = headers.keySet ().iterator (); - - while (iter.hasNext ()) - { - - String n = iter.next (); - - conn.setRequestProperty (n, - headers.get (n)); - - } - - } - - conn.setRequestMethod ("GET"); - - conn.setDoInput (true); - conn.setDoOutput (true); - conn.connect (); - - // Try and get input stream, not all responses allow it. - InputStream in = null; - - final int resCode = conn.getResponseCode (); - - if (resCode != HttpURLConnection.HTTP_OK) - { - - in = conn.getErrorStream (); - - } else { - - in = conn.getInputStream (); - - } - - byte[] content = null; - - if (in != null) - { - - ByteArrayOutputStream bout = new ByteArrayOutputStream (); - - // Read everything. - byte[] buf = new byte[8192]; - - int count = 0; - - while ((count = in.read (buf, - 0, - 8192)) != -1) - { - - bout.write (buf, - 0, - count); - - } - - bout.flush (); - bout.close (); - in.close (); - - content = bout.toByteArray (); - - } - - final byte[] ret = content; - - conn.disconnect (); - - if (resCode != HttpURLConnection.HTTP_OK) - { - - if (onError != null) - { - - UIUtils.doLater (new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - onError.actionPerformed (new ActionEvent (ret, resCode, "error")); - - } - - }); - - } - - } else { - - if (onSuccess != null) - { - - UIUtils.doLater (new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - onSuccess.actionPerformed (new ActionEvent (ret, resCode, "success")); - - } - - }); - - } - - } - - } catch (final Exception e) { - - if (onFailure != null) - { - - UIUtils.doLater (new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - onFailure.actionPerformed (new ActionEvent (e, 0, "exception")); - - } - - }); - - } - - } - - } - - }).start (); - - } - - public static void postToURL (final URL url, - final Map headers, - final String content, - final ActionListener onSuccess, - final ActionListener onError, - final ActionListener onFailure) - { - - new Thread (new Runnable () - { - - public void run () - { - - try - { - - HttpURLConnection conn = (HttpURLConnection) url.openConnection (); - - if (headers != null) - { - - Iterator iter = headers.keySet ().iterator (); - - while (iter.hasNext ()) - { - - String n = iter.next (); - - conn.setRequestProperty (n, - headers.get (n)); - - } - - } - - byte[] cb = content.getBytes (); - conn.setRequestProperty ("content-length", - cb.length + ""); - - conn.setRequestMethod ("POST"); - - conn.setDoInput (true); - conn.setDoOutput (true); - conn.connect (); - - BufferedWriter out = new BufferedWriter (new OutputStreamWriter (conn.getOutputStream (), StandardCharsets.UTF_8)); - out.write (content); - - out.flush (); - out.close (); - - // Try and get input stream, not all responses allow it. - InputStream in = null; - - final int resCode = conn.getResponseCode (); - - if (resCode != HttpURLConnection.HTTP_OK) - { - - in = conn.getErrorStream (); - - } else { - - in = conn.getInputStream (); - - } - - String r = null; - - if (in != null) - { - - StringBuilder b = new StringBuilder (); - - BufferedReader bin = new BufferedReader (new InputStreamReader (in)); - - // Read everything. - char chars[] = new char[8192]; - - int count = 0; - - while ((count = bin.read (chars, - 0, - 8192)) != -1) - { - - b.append (chars, - 0, - count); - - } - - String s = b.toString (); - - String pref = Constants.JSON_RETURN_PREFIX; //"for(;;);"; - - if (s.startsWith (pref)) - { - - s = s.substring (pref.length ()); - - } - - r = s; - - } - - final String ret = r; - - conn.disconnect (); - - if (resCode != HttpURLConnection.HTTP_OK) - { - - if (onError != null) - { - - UIUtils.doLater (new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - onError.actionPerformed (new ActionEvent (ret, resCode, "error")); - - } - - }); - - } - - } else { - - if (onSuccess != null) - { - - UIUtils.doLater (new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - onSuccess.actionPerformed (new ActionEvent (ret, resCode, "success")); - - } - - }); - - } - - } - - } catch (final Exception e) { - - if (onFailure != null) - { - - UIUtils.doLater (new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - onFailure.actionPerformed (new ActionEvent (e, 0, "exception")); - - } - - }); - - } - - } - - } - - }).start (); - - } - - public static void addDirToZip (File f, - File dirToWrite) - throws GeneralException - { - - if ((dirToWrite == null) - || - (f == null) - ) - { - - // Naughty but shouldn't happen. - throw new IllegalArgumentException ("Invalid args"); - - } - - if (dirToWrite.isFile ()) - { - - throw new IllegalArgumentException ("To write directory is actually a file: " + - dirToWrite); - - } - - if (f.isDirectory ()) - { - - throw new IllegalArgumentException ("File to write to is a directory: " + - f); - - } - - try - { - - Map env = new HashMap (); - env.put ("create", "true"); - - FileSystem fs = FileSystems.newFileSystem (Paths.get (f.getPath ()), - null); - - File[] files = dirToWrite.listFiles (); - - for (int i = 0; i < files.length; i++) - { - - Path fp = Paths.get (files[i].toURI ()); - - Path zp = fs.getPath ("/" + files[i].getParentFile ().getName () + "/" + files[i].getName ()); - - Files.createDirectories (zp.getParent ()); - - Files.copy (fp, - zp, - StandardCopyOption.REPLACE_EXISTING); - - } - - } catch (Exception e) { - - throw new GeneralException ("Unable to write dir to file: " + - dirToWrite + - ", file: " + - f, - e); - - } - - } - - public static void extractZipFile (File f, - File toDir) - throws GeneralException - { - - if ((toDir == null) - || - (f == null) - ) - { - - // Naughty but shouldn't happen. - throw new IllegalArgumentException ("Invalid args"); - - } - - if (toDir.isFile ()) - { - - throw new IllegalArgumentException ("To directory is actually a file: " + - toDir); - - } - - if (f.isDirectory ()) - { - - throw new IllegalArgumentException ("File to extract is a directory: " + - f); - - } - - if (!f.exists ()) - { - - throw new IllegalArgumentException ("File doesn't exist: " + - f); - - } - - if (!toDir.exists ()) - { - - toDir.mkdirs (); - - } - - ZipFile zf = null; - - try - { - - zf = new ZipFile (f); - - } catch (Exception e) { - - throw new GeneralException ("Unable to open file as a zip file: " + - f, - e); - - } - - try - { - - Enumeration en = zf.entries (); - - while (en.hasMoreElements ()) - { - - ZipEntry ze = (ZipEntry) en.nextElement (); - - String n = ze.getName (); - - File zFile = new File (toDir.getPath () + "/" + n).getCanonicalFile (); - - // Make sure it is a subdirectory. - if (!zFile.getPath ().startsWith (toDir.getCanonicalFile ().getPath ())) - { - - throw new GeneralException ("Invalid zip entry: " + n + ", leads to a new file/directory that is outside of specified to dir: " + - toDir); - - } - - if (ze.isDirectory ()) - { - - if (zFile.isFile ()) - { - - throw new GeneralException ("Invalid zip entry: " + n + ", cannot create directory, a file already exists with that name: " + - zFile); - - } - - if (!zFile.exists ()) - { - - zFile.mkdirs (); - - } - - } else { - - zFile.getParentFile ().mkdirs (); - - InputStream in = null; - - try - { - - in = zf.getInputStream (ze); - - BufferedOutputStream bout = new BufferedOutputStream (new FileOutputStream (zFile)); - - IOUtils.streamTo (in, - bout, - 4096); - - bout.flush (); - bout.close (); - - } catch (Exception e) { - - throw new GeneralException ("Unable to write zip file entry: " + n + ", to: " + - zFile, - e); - - } finally { - - if (in != null) - { - - in.close (); - - } - - } - - } - - } - - } catch (Exception e) { - - throw new GeneralException ("Unable to extract file: " + - f + - " to: " + - toDir, - e); - - } finally { - - try - { - - zf.close (); - - } catch (Exception e) { - - // Not worth recording, what are we gonna do? - - } - - } - - } - - public static String toString (Collection c, - String sep) - { - - StringBuilder b = new StringBuilder (); - - Iterator iter = c.iterator (); - - while (iter.hasNext ()) - { - - Object o = iter.next (); - - String s = o + ""; - - if (b.length () > 0) - { - - b.append (sep); - - } - - b.append (s); - - } - - return b.toString (); - - } - - public static void writeBytesToFile (File f, - byte[] bytes) - throws IOException - { - - FileOutputStream fos = new FileOutputStream (f); - fos.write (bytes); - fos.close (); - - } - - public static String getFileType (File f) - { - - if (f == null) - { - - return null; - - } - - if (f.isDirectory ()) - { - - return null; - - } - - int ind = f.getName ().lastIndexOf ("."); - - if (ind > -1) - { - - return f.getName ().substring (ind + 1); - - } - - return null; - - } - - public static String stripEnd (String s) - { - - if (s == null) - { - - return s; - - } - - int end = s.length () - 1; - - for (int i = end; i > -1; i--) - { - - if (!Character.isWhitespace (s.charAt (i))) - { - - return s.substring (0, - i + 1); - - } - - } - - return s; - - } - - public static void printStackTrace () - { - - new Exception ().printStackTrace (); - - } - - public static com.gentlyweb.properties.Properties findPropertyInChain (String name, - com.gentlyweb.properties.Properties props) - { - - if (props.getPropertyNoParent (name) != null) - { - - return props; - - } - - props = props.getParentProperties (); - - while (props != null) - { - - if (props.getPropertyNoParent (name) != null) - { - - return props; - - } - - props = props.getParentProperties (); - - } - - return null; - - } - - public static String getPropertiesIdChain (com.gentlyweb.properties.Properties props) - { - - StringBuilder b = new StringBuilder (); - - b.append (props.getId ()); - - com.gentlyweb.properties.Properties parent = props.getParentProperties (); - - while (parent != null) - { - - b.append (" -> "); - b.append (parent.getId ()); - - parent = parent.getParentProperties (); - - } - - return b.toString (); - - } - - public static String getStackTrace (Throwable e) - { - - StackTraceElement[] els = (e != null ? e.getStackTrace () : new Exception ().getStackTrace ()); - - StringBuilder b = new StringBuilder (); - - for (int i = 0; i < els.length; i++) - { - - b.append (els[i]); - b.append (String.valueOf ('\n')); - - } - - Throwable c = e.getCause (); - - if (c != null) - { - - b.append ("Caused by: "); - b.append (Utils.getStackTrace (c)); - - } - - return b.toString (); - - } - - public static boolean isToday (Date d) - { - - if (d == null) - { - - return false; - - } - - Calendar now = new GregorianCalendar (); - - Calendar dCal = new GregorianCalendar (); - dCal.setTime (d); - - return (now.get (Calendar.DAY_OF_MONTH) == dCal.get (Calendar.DAY_OF_MONTH)) - && - (now.get (Calendar.MONTH) == dCal.get (Calendar.MONTH)) - && - (now.get (Calendar.YEAR) == dCal.get (Calendar.YEAR)); - - } - - public static boolean isYesterday (Date d) - { - - if (d == null) - { - - return false; - - } - - Calendar now = new GregorianCalendar (); - - // Take off one day. - now.add (Calendar.DAY_OF_MONTH, - -1); - - Calendar dCal = new GregorianCalendar (); - dCal.setTime (d); - - return (now.get (Calendar.DAY_OF_MONTH) == dCal.get (Calendar.DAY_OF_MONTH)) - && - (now.get (Calendar.MONTH) == dCal.get (Calendar.MONTH)) - && - (now.get (Calendar.YEAR) == dCal.get (Calendar.YEAR)); - - } - - public static String formatDate (Date d) - { - - return new SimpleDateFormat (Environment.getProperty (Constants.DATE_FORMAT_PROPERTY_NAME)).format (d); - - } - - public static Date getDate (String d) - { - - try - { - - return new SimpleDateFormat (Environment.getProperty (Constants.DATE_FORMAT_PROPERTY_NAME)).parse (d); - - } catch (Exception e) - { - - Environment.logError ("Unable to parse date: " + - d + - ", using format: " + - Environment.getProperty (Constants.DATE_FORMAT_PROPERTY_NAME), - e); - - return null; - - } - - } - - public static String sanitizeForFilename (String n) - { - - char[] chars = n.toLowerCase ().toCharArray (); - - StringBuilder b = new StringBuilder (); - - for (int i = 0; i < chars.length; i++) - { - - if ((Character.isLetterOrDigit (chars[i])) || - (chars[i] == ' ')) - { - - b.append (chars[i]); - - } - - } - - return b.toString ().trim (); - - } - - public static long getTimeAsMillis (String v) - { - - if (v == null) - { - - return 0; - - } - - // Is this a legacy value, pre 2.6.5? - if (v.indexOf (" ") > 0) - { - - long min = 60000; - - if (v.equals ("5 mins")) - { - - return 5 * min; - - } - - if (v.equals ("10 mins")) - { - - return 10 * min; - - } - - if (v.equals ("20 mins")) - { - - return 20 * min; - - } - - if (v.equals ("30 mins")) - { - - return 30 * min; - - } - - long hour = 60 * min; - - if (v.equals ("1 hour")) - { - - return 1 * hour; - - } - - if (v.equals ("12 hours")) - { - - return 12 * hour; - - } - - if (v.equals ("24 hours")) - { - - return 24 * hour; - - } - - long day = hour * 24; - - if (v.equals ("2 days")) - { - - return 2 * day; - - } - - if (v.equals ("5 days")) - { - - return 5 * day; - - } - - if (v.equals ("1 week")) - { - - return 7 * day; - - } - - } - - try - { - - return Long.parseLong (v); - - } catch (Exception e) { - - Environment.logError ("Unable to parse: " + v + " into a long.", - e); - - } - - return 0; - - } - - public static void createQuollWriterDirFile (File d) - throws IOException - { - - if (!d.exists ()) - { - - return; - - } - - if (d.isFile ()) - { - - return; - - } - - IOUtils.writeStringToFile (new File (d.getPath () + "/" + Constants.QUOLLWRITER_DIR_FILE_NAME), - "This file indicates to quollwriter that the parent directory can be safely deleted or copied.", - false); - - } - - public static boolean isDirectoryEmpty (File d) - { - - if (d == null) - { - - return true; - - } - - if (!d.exists ()) - { - - return true; - - } - - if (d.isFile ()) - { - - return false; - - } - - File[] files = d.listFiles (); - - if ((files != null) - && - (files.length > 0) - ) - { - - return false; - - } - - return true; - - } - - public static File getQuollWriterDirFile (File parent) - { - - return new File (parent.getPath () + "/" + Constants.QUOLLWRITER_DIR_FILE_NAME); - - } - - public static void copyFilesToDir (Set files, - File to) - throws IOException - { - - if (!to.exists ()) - { - - throw new IllegalArgumentException ("To dir must exist."); - - } - - if (to.isFile ()) - { - - throw new IllegalArgumentException ("To dir is a file."); - - } - - File tof = new File (to.getPath () + "/" + Constants.QUOLLWRITER_DIR_FILE_NAME); - - if (!tof.exists ()) - { - - throw new IllegalArgumentException ("To dir doesn't look like a Quoll Writer dir."); - - } - - for (File f : files) - { - - if (f.isFile ()) - { - - // Create the new file. - File nf = new File (to.getPath (), - f.getName ()); - - if (nf.exists ()) - { - - // Don't overwrite. - continue; - - } - - IOUtils.copyFile (f, - nf, - 4096); - - } - - } - - } - - public static void copyDir (File from, - File to) - throws IOException - { - - // Only copy directories that have the specified file in it. - File f = new File (from.getPath () + "/" + Constants.QUOLLWRITER_DIR_FILE_NAME); - - if (!f.exists ()) - { - - return; - - } - - if (to.exists ()) - { - - return; - - } - - to.mkdirs (); - - File[] files = from.listFiles (); - - for (int i = 0; i < files.length; i++) - { - - f = files[i]; - - if (f.isFile ()) - { - - // Create the new file. - File nf = new File (to.getPath () + "/" + f.getName ()); - - if (nf.exists ()) - { - - // Don't overwrite. - continue; - - } - - IOUtils.copyFile (f, - nf, - 4096); - - } else - { - - // Create a new directory. - File nd = new File (to.getPath () + "/" + f.getName ()); - - if (nd.exists ()) - { - - // Ignore. - continue; - - } - - Utils.copyDir (f, - nd); - - } - - } - - } - - public static void deleteDir (File d) - { - - if (d == null) - { - - return; - - } - - if (d.isFile ()) - { - - return; - - } - - // See if there is a file that indicates we can delete this directory and it's contents. - File canDeleteF = new File (d.getPath () + "/" + Constants.QUOLLWRITER_DIR_FILE_NAME); - - if (!canDeleteF.exists ()) - { - - return; - - } - - // If we are here then we can delete this directory and it's contents. - File[] files = d.listFiles (); - - for (int i = 0; i < files.length; i++) - { - - File f = files[i]; - - if (f.isFile ()) - { - - if (!f.delete ()) - { - - Environment.logError ("Unable to delete file: " + f); - - } - - } else - { - - Utils.deleteDir (f); - - } - - } - - d.delete (); - - } - - public static Date zeroTimeFields (Date d) - { - - GregorianCalendar gc = new GregorianCalendar (); - gc.setTime (d); - - gc.set (Calendar.HOUR_OF_DAY, - 0); - gc.set (Calendar.MINUTE, - 0); - gc.set (Calendar.SECOND, - 0); - gc.set (Calendar.MILLISECOND, - 0); - - return gc.getTime (); - - } - - public static String formatAsDuration (double duration) - { - - long millis = (long) duration; - - long days = 0; - long hours = 0; - long mins = 0; - - long min = 60 * 1000; - long hour = 60 * min; - long day = 24 * hour; - - days = millis / day; - - millis = millis - (day * days); - - hours = millis / hour; - - millis = millis - (hour * hours); - - mins = millis / min; - - StringBuilder b = new StringBuilder (); - - if (days > 0) - { - - b.append (days); - b.append ("d"); - - } - - if (hours > 0) - { - - if (b.length () > 0) - { - - b.append (" "); - - } - - b.append (hours); - b.append ("h"); - - } - - if (mins > 0) - { - - if (b.length () > 0) - { - - b.append (" "); - - } - - b.append (mins); - b.append ("m"); - - } - - if (b.length () == 0) - { - - b.append ("0m"); - - } - - return b.toString (); - - } - -} diff --git a/src/com/quollwriter/Version.java b/src/com/quollwriter/Version.java deleted file mode 100644 index e627e832..00000000 --- a/src/com/quollwriter/Version.java +++ /dev/null @@ -1,292 +0,0 @@ -package com.quollwriter; - -import java.util.*; - -/** - * Models the version numbers, format is: [version.version.version...]b[version] - * where each version is an integer. The b[version] is optional and indicates a beta version. - * - * Examples: - * - * 2.2 - * 2.3b1 - * 2.4b1 - * 2.4 - * 2.2.1b1 - * 2.3.9 - * - * A value of 2.3 is considered to be "newer" than 2.3b1 and 2.3b2 is newer than 2.3b1. - */ -public class Version implements Comparable -{ - - private String _version = null; - private int version = 0; - private int betaVersion = 0; - - public Version (String v) - { - - if (v == null) - { - - throw new IllegalArgumentException ("Version must be specified"); - - } - - this._version = v.trim (); - - String ver = this._version; - - int bind = this._version.indexOf ("b"); - - if (bind > 0) - { - - // Get the version then the beta. - ver = this._version.substring (0, bind); - - String bver = this._version.substring (bind + 1); - - this.betaVersion = Integer.parseInt (bver); - - } - - this.version = this.getVersionAsInt (ver); - - } - - @Override - public int compareTo (Version v) - { - - if (v == null) - { - - return 1; - - } - - if (this.isSame (v)) - { - - return 0; - - } - - if (this.isNewer (v)) - { - - return -1; - - } - - return 1; - - } - - public String getVersion () - { - - return this._version; - - } - - public String toString () - { - - return this._version; - - } - - private String expandVersion (String v) - { - - char[] chs = v.toCharArray (); - - int c = 0; - - for (int i = 0; i < chs.length; i++) - { - - if (chs[i] == '.') - { - - c++; - - } - - } - - if (c < 2) - { - - for (int i = c; i < 2; i++) - { - - v += ".0"; - - } - - } - - return v; - - } - - private List getVersionParts (String v) - { - - if (v == null) - { - - v = "0"; - - } - - v = this.expandVersion (v); - - StringTokenizer t = new StringTokenizer (v, - "."); - - List parts = new ArrayList (); - - while (t.hasMoreTokens ()) - { - - parts.add (Integer.parseInt (t.nextToken ())); - - } - - return parts; - - } - - private int getVersionAsInt (String version) - { - - if (version == null) - { - - return -1; - - } - - List parts = this.getVersionParts (version); - - int mult = 100; - - int t = 0; - - for (int i = 0; i < parts.size (); i++) - { - - int p = parts.get (i); - - t += p * mult; - - mult /= 10; - - } - - return t; - - } - - public boolean isBeta () - { - - return this.betaVersion > 0; - - } - - public boolean isSame (Version other) - { - - return this.equals (other); - - } - - /** - * Is the passed in version newer than this one. - * - * @param other The version to check. - * @return true if other is newer than this version. - */ - public boolean isNewer (Version other) - { - - if (other == null) - { - - return false; - - } - - if (other.version == this.version) - { - - // 2.3 is NOT newer than 2.3 - if (this.betaVersion == other.betaVersion) - { - - return false; - - } - - // 2.3 IS newer than 2.3b1 - if ((other.betaVersion == 0) - || - (other.betaVersion > this.betaVersion) - ) - { - - return true; - - } - - } - - if (other.version > this.version) - { - - return true; - - } - - return false; - - } - - @Override - public int hashCode () - { - - int hash = 7; - hash = (31 * hash) + this.version; - hash = (31 * hash) + this.betaVersion; - - return hash; - - } - - @Override - public boolean equals (Object o) - { - - if ((o == null) || (!(o instanceof Version))) - { - - return false; - - } - - Version v = (Version) o; - - return (v.version == this.version) - && - (v.betaVersion == this.betaVersion); - - } - -} \ No newline at end of file diff --git a/src/com/quollwriter/achievements/AchievementsManager.java b/src/com/quollwriter/achievements/AchievementsManager.java deleted file mode 100644 index e9189afd..00000000 --- a/src/com/quollwriter/achievements/AchievementsManager.java +++ /dev/null @@ -1,1288 +0,0 @@ -package com.quollwriter.achievements; - -import java.util.*; -import java.util.concurrent.*; -import java.io.*; -import java.awt.event.*; -import javax.swing.event.*; - -import javax.sound.sampled.*; - -import org.jdom.*; - -import com.gentlyweb.xml.*; - -import com.gentlyweb.properties.*; - -import com.quollwriter.*; -import com.quollwriter.ui.*; - -import com.quollwriter.achievements.rules.*; -import com.quollwriter.ui.components.ActionAdapter; - -public class AchievementsManager implements ProjectEventListener -{ - - public static final String USER = "user"; - public static final String PROJECT = "project"; - public static final String CHAPTER = "chapter"; - - public class XMLConstants - { - - public static final String item = "item"; - public static final String id = "id"; - public static final String category = "category"; - public static final String state = "state"; - - } - - // The key here is the AchievementRule.getEventId - private Map> userRules = new HashMap (); - - // The inner map key is the AchievementRule.getEventId. - private Map>> eventRules = new HashMap (); - private Map checkers = new HashMap (); - - // The key is the id attribute of the element. - private Map ruleEls = new LinkedHashMap (); - - private Clip achievementSound = null; - - private Map listeners = null; - private Object listenerFillObj = new Object (); - - private boolean soundRunning = false; - - public AchievementsManager () - throws Exception - { - - this.listeners = Collections.synchronizedMap (new WeakHashMap ()); - - // Load our list of user achieved achievements. - Set achieved = this.getAchievedIds (Environment.getProperty (Constants.USER_ACHIEVEMENTS_ACHIEVED_PROPERTY_NAME)); - - // Load the state for the user achievements. - Map initEls = this.getInitElements (Environment.getProperty (Constants.USER_ACHIEVEMENTS_STATE_PROPERTY_NAME)); - - // Create the achievements for the project and chapter categories. - String achFile = Environment.getResourceFileAsString (Constants.ACHIEVEMENTS_FILE); - - if (achFile == null) - { - - return; - - } - - Element root = JDOMUtils.getStringAsElement (achFile); - - List els = JDOMUtils.getChildElements (root, - XMLConstants.item, - true); - - Set userSessionRules = new HashSet (); - - // Get the user ones. - for (int i = 0; i < els.size (); i++) - { - - Element el = (Element) els.get (i); - - String id = JDOMUtils.getAttributeValue (el, - XMLConstants.id, - true).toLowerCase ().trim (); - - if (JDOMUtils.getAttributeValue (el, - XMLConstants.category).equals (USER)) - { - - // Have we achieved this one. - if (achieved.contains (id)) - { - - continue; - - } - - // Load the rule. - AchievementRule ar = AchievementRuleFactory.createRule (el); - - if (ar == null) - { - - throw new JDOMException ("Unable to create rule from element: " + - JDOMUtils.getPath (el)); - - } - - // Init. - Element initEl = initEls.get (ar.getId ()); - - if (initEl != null) - { - - ar.init (initEl); - - } - - if (ar.isEventTrigger ()) - { - - for (String eid : ar.getEventIds ()) - { - - Set rs = this.userRules.get (eid); - - if (rs == null) - { - - rs = new LinkedHashSet (); - - this.userRules.put (eid, - rs); - - } - - rs.add (ar); - - } - - } else { - - userSessionRules.add (ar); - - } - - } else { - - this.ruleEls.put (id, - el); - - } - - } - - if (userSessionRules.size () > 0) - { - - AchievementsChecker ac = new AchievementsChecker (null, - userSessionRules, - this); - - ac.scheduledFuture = Environment.schedule (ac, - 10 * 1000, - 10 * 1000); - - this.checkers.put (null, - ac); - - } - - Environment.addUserProjectEventListener (this); - - } - - public void removeAchievementReachedListener (AchievementReachedListener l) - { - - this.listeners.remove (l); - - } - - public void addAchievementReachedListener (AchievementReachedListener l) - { - - this.listeners.put (l, this.listenerFillObj); - - } - - protected void fireAchievementReachedEvent (AchievementRule ar) - { - - final AchievementsManager _this = this; - - final AchievementReachedEvent ev = new AchievementReachedEvent (ar); - - UIUtils.doActionLater (new ActionListener () - { - - public void actionPerformed (ActionEvent aev) - { - - Set ls = null; - - // Get a copy of the current valid listeners. - synchronized (_this.listeners) - { - - ls = new LinkedHashSet (_this.listeners.keySet ()); - - } - - for (AchievementReachedListener l : ls) - { - - l.achievementReached (ev); - - } - - } - - }); - - } - - public Set getUserAchievedIds () - { - - return this.getAchievedIds (Environment.getProperty (Constants.USER_ACHIEVEMENTS_ACHIEVED_PROPERTY_NAME)); - - } - - private Set getRules (String type, - boolean includeHidden) - throws Exception - { - - // Create the achievements for the project and chapter categories. - String achFile = Environment.getResourceFileAsString (Constants.ACHIEVEMENTS_FILE); - - if (achFile == null) - { - - return null; - - } - - Element root = null; - - try - { - - root = JDOMUtils.getStringAsElement (achFile); - - } catch (Exception e) { - - Environment.logError ("Unable to convert file: " + - achFile + - " to an element", - e); - - return null; - - } - - Set rules = new HashSet (); - - List els = JDOMUtils.getChildElements (root, - XMLConstants.item, - true); - - // Get the user ones. - for (int i = 0; i < els.size (); i++) - { - - Element el = (Element) els.get (i); - - try - { - - String id = JDOMUtils.getAttributeValue (el, - XMLConstants.id, - true).toLowerCase ().trim (); - - if (JDOMUtils.getAttributeValue (el, - XMLConstants.category).equals (type)) - { - - AchievementRule ar = AchievementRuleFactory.createRule (el); - - if ((!includeHidden) - && - (ar.isHidden ()) - ) - { - - continue; - - } - - rules.add (ar); - - } - - } catch (Exception e) { - - Environment.logError ("Unable to convert element: " + - JDOMUtils.getPath (el) + - " to a rule", - e); - - } - - } - - return rules; - - } - - public Set getUserRules () - { - - try - { - - return this.getRules (USER, - true); - - } catch (Exception e) { - - Environment.logError ("Unable to get user rules", - e); - - return null; - - } - - } - - public Set getPerProjectRules () - { - - try - { - - return this.getRules (PROJECT, - true); - - } catch (Exception e) { - - Environment.logError ("Unable to get project rules", - e); - - return null; - - } - - } - - - private Set getAchievedIds (String v) - { - - Set achievedM = new HashSet (); - - if (v != null) - { - - // Split on , - StringTokenizer t = new StringTokenizer (v, - ","); - - while (t.hasMoreTokens ()) - { - - achievedM.add (t.nextToken ().toLowerCase ().trim ()); - - } - - } - - return achievedM; - - } - - private String getState (Set rules) - throws Exception - { - - Element root = new Element (XMLConstants.state); - - // Now persist any user rules. - for (AchievementRule ar : rules) - { - - if (ar.shouldPersistState ()) - { - - Element el = new Element (XMLConstants.item); - - el.setAttribute (XMLConstants.id, - ar.getId ()); - ar.fillState (el); - - root.addContent (el); - - } - - } - - return JDOMUtils.getElementAsString (root); - - } - - public void stop () - throws Exception - { - - Set viewers = new HashSet (this.eventRules.keySet ()); - - for (AbstractViewer pv : viewers) - { - - this.removeViewer (pv); - - } - - UserProperties.set (Constants.USER_ACHIEVEMENTS_STATE_PROPERTY_NAME, - this.getState (new HashSet (this.userRules.values ()))); - - } - - public Map> getAchievedAchievementIds (AbstractViewer viewer) - { - - Map> achieved = new HashMap (); - - achieved.put (USER, - this.getAchievedIds (UserProperties.get (Constants.USER_ACHIEVEMENTS_ACHIEVED_PROPERTY_NAME))); - - if ((viewer != null) - && - (viewer instanceof AbstractProjectViewer) - ) - { - - AbstractProjectViewer pv = (AbstractProjectViewer) viewer; - - achieved.put ("project", - this.getAchievedIds (pv.getProject ().getProperty (Constants.PROJECT_ACHIEVEMENTS_ACHIEVED_PROPERTY_NAME))); - - } - - return achieved; - - } - - private Map getInitElements (String v) - throws Exception - { - - Map initEls = new HashMap (); - - if (v != null) - { - - try - { - - Element root = JDOMUtils.getStringAsElement (v); - - List els = JDOMUtils.getChildElements (root, - XMLConstants.item, - false); - - for (int i = 0; i < els.size (); i++) - { - - Element el = (Element) els.get (i); - - initEls.put (JDOMUtils.getAttributeValue (el, - XMLConstants.id, - true), - el); - - } - - } catch (Exception e) { - - Environment.logError ("Unable to get achievement init elements for string: " + - v, - e); - - } - - } - - return initEls; - - } - - public void removeViewer (AbstractViewer v) - throws Exception - { - - if (v == null) - { - - return; - - } - - Map> rules = this.eventRules.get (v); - - if (rules == null) - { - - // Already removed. - return; - - } - - Set rs = new HashSet (); - - if (rules != null) - { - - for (String id : rules.keySet ()) - { - - rs.addAll (rules.get (id)); - - } - - } - - this.eventRules.remove (v); - - // Check to see if we meet any of the achievements. - AchievementsChecker t = this.checkers.get (v); - - if (t != null) - { - - // Get the rules. - rs.addAll (t.getRules ()); - - } - - if (v instanceof AbstractProjectViewer) - { - - AbstractProjectViewer pv = (AbstractProjectViewer) v; - - // Save the state. - pv.getProject ().setProperty (Constants.PROJECT_ACHIEVEMENTS_STATE_PROPERTY_NAME, - this.getState (rs)); - - pv.saveProject (); - - } - - if (t != null) - { - - Environment.unschedule (t.scheduledFuture); - - } - - this.checkers.remove (v); - - } - - public void addViewer (Landing l) - throws Exception - { - - l.addProjectEventListener (this); - - } - - public void addProjectViewer (AbstractProjectViewer v) - throws Exception - { - - // Get the list of project/chapter achieved achievements. - Set achieved = this.getAchievedIds (v.getProject ().getProperty (Constants.PROJECT_ACHIEVEMENTS_ACHIEVED_PROPERTY_NAME)); - - // Load the state for the achievements and init. - Map initEls = this.getInitElements (v.getProject ().getProperty (Constants.PROJECT_ACHIEVEMENTS_STATE_PROPERTY_NAME)); - - // The key is the event id. - Map> evRules = new HashMap (); - - Set constantRules = new LinkedHashSet (); - - // Load the project/chapter achievements (not in the list above). - for (String id : this.ruleEls.keySet ()) - { - - if (achieved.contains (id)) - { - - continue; - - } - - Element el = this.ruleEls.get (id); - - // Load the rule. - AchievementRule ar = AchievementRuleFactory.createRule (el); - - if (ar == null) - { - - throw new JDOMException ("Unable to create rule from element: " + - JDOMUtils.getPath (el)); - - } - - // Init. - Element initEl = initEls.get (ar.getId ()); - - if (initEl != null) - { - - ar.init (initEl); - - } - - if (ar.isEventTrigger ()) - { - - // Get the event ids, there can be more than one for example - // if we are looking for new and/or edit events for an object type. - Set eventIds = ar.getEventIds (); - - for (String eid : eventIds) - { - - Set rules = evRules.get (eid); - - if (rules == null) - { - - rules = new LinkedHashSet (); - - evRules.put (eid, - rules); - - } - - rules.add (ar); - - } - - } else { - - constantRules.add (ar); - - } - - } - - this.eventRules.put (v, - evRules); - - if (constantRules.size () > 0) - { - - // Create the achievements checker and schedule. - AchievementsChecker ac = new AchievementsChecker (v, - constantRules, - this); - - ac.scheduledFuture = Environment.schedule (ac, - 10 * 1000, - 10 * 1000); - - this.checkers.put (v, - ac); - - } - - v.addProjectEventListener (this); - - } - - private void logAchievementReached () - { - - - } - - // TODO: Allow for just AbstractViewer. - public synchronized void projectAchievementReached (AbstractProjectViewer viewer, - AchievementRule ar) - { - - if (Environment.isDebugModeEnabled ()) - { - - Environment.logMessage ("Achievement reached: " + ar + ", enabled: " + this.isAchievementsEnabled ()); - - } - - if (!this.isAchievementsEnabled ()) - { - - return; - - } - - try - { - - // Add to the list of project achievements. - Set achieved = this.getAchievedIds (viewer.getProject ().getProperty (Constants.PROJECT_ACHIEVEMENTS_ACHIEVED_PROPERTY_NAME)); - - if (achieved.contains (ar.getId ())) - { - - return; - - } - - achieved.add (ar.getId ()); - - viewer.getProject ().getProperties ().setProperty (Constants.PROJECT_ACHIEVEMENTS_ACHIEVED_PROPERTY_NAME, - new StringProperty (Constants.PROJECT_ACHIEVEMENTS_ACHIEVED_PROPERTY_NAME, - this.getAsString (achieved))); - - viewer.saveProject (); - - viewer.showAchievement (ar); - - this.fireAchievementReachedEvent (ar); - - this.playAchievementSound (); - - viewer.createActionLogEntry (viewer.getProject (), - "Achievement: " + ar.getId () + "[" + ar.getName () + "] reached."); - - } catch (Exception e) { - - Environment.logError ("Unable to set achievement achieved: " + - ar, - e); - - } - - } - - private void removeRule (AchievementRule ar, - AbstractProjectViewer viewer) - { - - Map> rules = this.eventRules.get (viewer); - - Set eventIds = ar.getEventIds (); - - for (String eid : eventIds) - { - - Set rs = rules.get (eid); - - rs.remove (ar); - - } - - } - - public synchronized void userAchievementReached (AchievementRule ar) - { - - if (Environment.isDebugModeEnabled ()) - { - - Environment.logMessage ("User achievement reached: " + ar + ", enabled: " + this.isAchievementsEnabled ()); - - } - - if (!this.isAchievementsEnabled ()) - { - - return; - - } - - try - { - - // Add to the list of user achievements. - Set achieved = this.getAchievedIds (Environment.getProperty (Constants.USER_ACHIEVEMENTS_ACHIEVED_PROPERTY_NAME)); - - if (achieved.contains (ar.getId ())) - { - - return; - - } - - achieved.add (ar.getId ()); - - UserProperties.set (Constants.USER_ACHIEVEMENTS_ACHIEVED_PROPERTY_NAME, - this.getAsString (achieved)); - - this.fireAchievementReachedEvent (ar); - - Environment.showAchievement (ar); - - this.playAchievementSound (); - - } catch (Exception e) { - - // Log the error. - Environment.logError ("Unable to set user achievement as reached: " + - ar, - e); - - } - - } - - public void setAchievementsEnabled (boolean v) - { - - UserProperties.set (Constants.ACHIEVEMENTS_ENABLED_PROPERTY_NAME, - v); - - } - - public boolean isAchievementsEnabled () - { - - return UserProperties.getAsBoolean (Constants.ACHIEVEMENTS_ENABLED_PROPERTY_NAME) - && - !Environment.isDistractionFreeModeEnabled (); - - } - - public boolean isSoundsInFullScreenEnabled () - { - - return UserProperties.getAsBoolean (Constants.ACHIEVEMENTS_SOUND_IN_FULL_SCREEN_ENABLED_PROPERTY_NAME); - - } - - public void setSoundsInFullScreenEnabled (boolean v) - { - - UserProperties.set (Constants.ACHIEVEMENTS_SOUND_IN_FULL_SCREEN_ENABLED_PROPERTY_NAME, - v); - - } - - public void setSoundEnabled (boolean v) - { - - UserProperties.set (Constants.ACHIEVEMENTS_SOUND_ENABLED_PROPERTY_NAME, - v); - - } - - public boolean isSoundEnabled () - { - - return UserProperties.getAsBoolean (Constants.ACHIEVEMENTS_SOUND_ENABLED_PROPERTY_NAME); - - } - - public void playAchievementSound () - { - - if (!this.isSoundEnabled ()) - { - - return; - - } - - if ((Environment.isInFullScreen ()) - && - (!this.isSoundsInFullScreenEnabled ()) - ) - { - - return; - - } - - if (this.achievementSound == null) - { - - try - { - - InputStream is = new BufferedInputStream (Environment.getResourceStream (Constants.DEFAULT_ACHIEVEMENT_SOUND_FILE)); - - // Get the clip. - AudioInputStream ais = AudioSystem.getAudioInputStream (is); - - this.achievementSound = AudioSystem.getClip (); - - this.achievementSound.open (ais); - - } catch (Exception e) - { - - Environment.logError ("Unable to get sound file to play on achievement", - e); - - return; - - } - - } - - if (this.soundRunning) - { - - return; - - } - - this.soundRunning = true; - - final AchievementsManager _this = this; - - javax.swing.Timer t = new javax.swing.Timer (1000, - new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - // Play after 1s. - try - { - - _this.achievementSound.setFramePosition (0); - - _this.achievementSound.start (); - - _this.soundRunning = false; - - } catch (Exception e) - { - - Environment.logError ("Unable to play achievement sound", - e); - - } - - } - - }); - - t.setRepeats (false); - - t.start (); - - } - - private String getAsString (Set ids) - { - - StringBuilder b = new StringBuilder (); - - for (String id : ids) - { - - if (b.length () > 0) - { - - b.append (","); - - } - - b.append (id); - - } - - return b.toString (); - - } - - public void eventOccurred (ProjectEvent ev) - { - - // Get our matching user rules for the event. - if (Environment.isDebugModeEnabled ()) - { - - Environment.logMessage ("Event occurred: " + ev); - - } - - long start = System.currentTimeMillis (); - - Set rules = this.userRules.get (ev.getEventId ()); - - if (rules != null) - { - - Set achieved = new HashSet (); - - for (AchievementRule ar : rules) - { - - try - { - - if (ar.achieved (null, - ev)) - { - - // Just pick a viewer and display there. - this.userAchievementReached (ar); - - achieved.add (ar); - - } - - } catch (Exception e) { - - Environment.logError ("Unable to check for achievement: " + - ar, - e); - - } - - } - - for (AchievementRule ar : achieved) - { - - for (String eid : ar.getEventIds ()) - { - - this.userRules.remove (eid); - - } - - } - - } - - if (ev.getSource () instanceof AbstractProjectViewer) - { - - AbstractProjectViewer pv = (AbstractProjectViewer) ev.getSource (); - - Map> evRules = this.eventRules.get (pv); - - if (evRules != null) - { - - Set rs = evRules.get (ev.getEventId ()); - - if (rs != null) - { - - Set achieved = new HashSet (); - - for (AchievementRule ar : rs) - { - - try - { - - if (ar.achieved (pv, - ev)) - { - - this.projectAchievementReached (pv, - ar); - - achieved.add (ar); - - } - - } catch (Exception e) { - - Environment.logError ("Unable to check for achievement: " + - ar, - e); - - } - - } - - for (AchievementRule ar : achieved) - { - - this.removeRule (ar, - pv); - - } - - } - - } - - } - - if ((System.currentTimeMillis () - start) > 500) - { - - Environment.logMessage ("Warning! Achievements event processing took: " + (System.currentTimeMillis () - start)); - - } - - } - - public class AchievementsChecker implements Runnable - { - - public ScheduledFuture scheduledFuture = null; - public AbstractProjectViewer viewer = null; - private boolean running = false; - public AchievementsManager manager = null; - public Set rules = null; - private int count = 0; - public AchievementsChecker (AbstractProjectViewer viewer, - Set rules, - AchievementsManager manager) - { - - this.viewer = viewer; - this.rules = rules; - this.manager = manager; - - } - - public Set getRules () - { - - return this.rules; - - } - - public boolean isRunning () - { - - return this.running; - - } - - public void run () - { - - try{ - this.count++; - - if (this.running) - { - - return; - - } - - this.running = true; - - if (rules.size () == 0) - { - - try - { - - manager.removeViewer (this.viewer); - - } catch (Exception e) { - - // Ignore. - - } - - this.running = false; - - return; - - } - - Iterator iter = this.rules.iterator (); - - while (iter.hasNext ()) - { - - AchievementRule ar = iter.next (); - - try - { - - if (ar.achieved (this.viewer)) - { - - if (ar.getCategory ().equals (USER)) - { - - manager.userAchievementReached (ar); - - } else { - - manager.projectAchievementReached (this.viewer, - ar); - - } - - iter.remove (); - - } - - } catch (Exception e) { - - Environment.logError ("Unable to check achievement: " + ar, - e); - - } - - } - - this.running = false; - - }catch(Exception e) { - - Environment.logError ("Unable to check for achievements for project: " + - this.viewer.getProject (), - e); - - } - - } - - } - - public void removeAchievedAchievement (String type, - String id, - AbstractViewer viewer) - throws Exception - { - - if (type.toLowerCase ().equals (USER)) - { - - Set achieved = this.getAchievedIds (Environment.getProperty (Constants.USER_ACHIEVEMENTS_ACHIEVED_PROPERTY_NAME)); - - achieved.remove (id.toLowerCase ()); - - UserProperties.set (Constants.USER_ACHIEVEMENTS_ACHIEVED_PROPERTY_NAME, - this.getAsString (achieved)); - - } else { - - if ((viewer != null) - && - (viewer instanceof AbstractProjectViewer) - ) - { - - AbstractProjectViewer pv = (AbstractProjectViewer) viewer; - - Set achieved = this.getAchievedIds (pv.getProject ().getProperty (Constants.PROJECT_ACHIEVEMENTS_ACHIEVED_PROPERTY_NAME)); - - achieved.remove (id); - - pv.getProject ().getProperties ().setProperty (Constants.PROJECT_ACHIEVEMENTS_ACHIEVED_PROPERTY_NAME, - new StringProperty (Constants.PROJECT_ACHIEVEMENTS_ACHIEVED_PROPERTY_NAME, - this.getAsString (achieved))); - - } - - } - - } - -} diff --git a/src/com/quollwriter/achievements/rules/AchievementRule.java b/src/com/quollwriter/achievements/rules/AchievementRule.java deleted file mode 100644 index 1820f2e4..00000000 --- a/src/com/quollwriter/achievements/rules/AchievementRule.java +++ /dev/null @@ -1,44 +0,0 @@ -package com.quollwriter.achievements.rules; - -import java.util.*; - -import org.jdom.*; - -import com.quollwriter.ui.*; - -public interface AchievementRule -{ - - public String getName (); - - public String getIcon (); - - public String getDescription (); - - public String getId (); - - public Set getEventIds (); - - public boolean shouldPersistState (); - - public boolean isEventTrigger (); - - public boolean isHidden (); - - public String getCategory (); - - public boolean achieved (AbstractProjectViewer viewer, - ProjectEvent ev) - throws Exception; - - public boolean achieved (ProjectEvent ev) - throws Exception; - - public boolean achieved (AbstractProjectViewer viewer) - throws Exception; - - public void init (Element root); - - public void fillState (Element root); - -} \ No newline at end of file diff --git a/src/com/quollwriter/achievements/rules/EditorMessageAchievementRule.java b/src/com/quollwriter/achievements/rules/EditorMessageAchievementRule.java deleted file mode 100644 index e7e139cf..00000000 --- a/src/com/quollwriter/achievements/rules/EditorMessageAchievementRule.java +++ /dev/null @@ -1,220 +0,0 @@ -package com.quollwriter.achievements.rules; - -import java.util.*; - -import org.jdom.*; - -import com.gentlyweb.utils.*; -import com.gentlyweb.xml.*; - -import com.quollwriter.*; -import com.quollwriter.data.*; -import com.quollwriter.ui.*; -import com.quollwriter.editors.*; -import com.quollwriter.editors.messages.*; - -public class EditorMessageAchievementRule extends AbstractAchievementRule implements EditorMessageListener -{ - - public static final String RULE_TYPE = "editor-message"; - - public class XMLConstants - { - - public static final String messageTypes = "messageTypes"; - public static final String count = "count"; - public static final String sentByMe = "sentByMe"; - public static final String savedCount = "savedCount"; - public static final String match = "match"; - - } - - private Set messageTypes = new HashSet (); - private ObjectMatch match = null; - private int count = 0; - private boolean sentByMe = true; - private int savedCount = 0; - - public EditorMessageAchievementRule (Element root) - throws JDOMException - { - - super (root); - - Element mEl = JDOMUtils.getChildElement (root, - XMLConstants.match, - false); - - if (mEl != null) - { - - this.match = new ObjectMatch (mEl); - - } - - this.count = JDOMUtils.getAttributeValueAsInt (root, - XMLConstants.count, - false); - - if (JDOMUtils.getAttribute (root, - XMLConstants.sentByMe, - false) != null) - { - - this.sentByMe = JDOMUtils.getAttributeValueAsBoolean (root, - XMLConstants.sentByMe, - false); - - } - - String mt = JDOMUtils.getAttributeValue (root, - XMLConstants.messageTypes, - true); - - StringTokenizer t = new StringTokenizer (mt.toLowerCase (), - ","); - - while (t.hasMoreTokens ()) - { - - String tok = t.nextToken ().trim (); - - try - { - - EditorMessage m = MessageFactory.getInstance (tok); - - if (this.match != null) - { - - // Just a check to see if the accessor will work. - this.match.match (m); - - } - - this.messageTypes.add (tok); - - } catch (Exception e) { - - throw new JDOMException ("Invalid message type: " + - tok + - ", referenced by: " + - JDOMUtils.getPath (root), - e); - - } - - } - - EditorsEnvironment.addEditorMessageListener (this); - - } - - public boolean shouldPersistState () - { - - return (this.count > 0); - - } - - public void handleMessage (EditorMessageEvent ev) - { - - if (ev.getType () != EditorMessageEvent.MESSAGE_ADDED) - { - - return; - - } - - EditorMessage mess = ev.getMessage (); - - if (!this.messageTypes.contains (mess.getMessageType ())) - { - - return; - - } - - if ((mess.isSentByMe () && !this.sentByMe) - || - (!mess.isSentByMe () && this.sentByMe) - ) - { - - return; - - } - - try - { - - if ((this.match != null) - && - (!this.match.match (mess)) - ) - { - - return; - - } - - } catch (Exception e) { - - Environment.logError ("Unable to check for message match: " + - mess, - e); - - return; - - } - - this.savedCount++; - - if (this.savedCount < this.count) - { - - return; - - } - - Environment.getAchievementsManager ().userAchievementReached (this); - - EditorsEnvironment.removeEditorMessageListener (this); - - } - - public void init (Element root) - { - - if (this.count > 0) - { - - try - { - - this.savedCount = JDOMUtils.getAttributeValueAsInt (root, - XMLConstants.savedCount, - false); -this.savedCount = 0; - } catch (Exception e) { - - Environment.logError ("Unable to set saved count for rule: " + - this, - e); - - } - - } - - } - - public void fillState (Element root) - { - - root.setAttribute (XMLConstants.savedCount, - String.valueOf (this.savedCount)); - - } - -} \ No newline at end of file diff --git a/src/com/quollwriter/achievements/rules/EventAchievementRule.java b/src/com/quollwriter/achievements/rules/EventAchievementRule.java deleted file mode 100644 index 614894ef..00000000 --- a/src/com/quollwriter/achievements/rules/EventAchievementRule.java +++ /dev/null @@ -1,157 +0,0 @@ -package com.quollwriter.achievements.rules; - -import java.util.*; - -import org.jdom.*; - -import com.gentlyweb.xml.*; - -import com.quollwriter.ui.*; - -public class EventAchievementRule extends AbstractAchievementRule -{ - - public static final String RULE_TYPE = "event"; - - public class XMLConstants - { - - public static final String count = "count"; - public static final String match = "match"; - - } - - private int count = -1; - private ObjectMatch match = null; - private int matchCount = 0; - - public EventAchievementRule (Element root) - throws JDOMException - { - - super (root); - - this.count = JDOMUtils.getAttributeValueAsInt (root, - XMLConstants.count, - false); - - Element mEl = JDOMUtils.getChildElement (root, - XMLConstants.match, - false); - - if (mEl != null) - { - - this.match = new ObjectMatch (mEl); - - } - - if (this.getEventIds ().size () == 0) - { - - throw new JDOMException ("Expected at least one event/action to be defined, referenced by: " + - JDOMUtils.getPath (root)); - - } - - } - - public String toString () - { - - return super.toString () + "(count: " + this.count + ", matched: " + this.matchCount + ", match: " + this.match + ")"; - - } - - public boolean isEventTrigger () - { - - return true; - - } - - public boolean shouldPersistState () - { - - return this.matchCount > 0; - - } - - public boolean achieved (AbstractProjectViewer viewer, - ProjectEvent ev) - throws Exception - { - - return this.achieved (ev); - - } - - public boolean achieved (ProjectEvent ev) - throws Exception - { - - if (this.match != null) - { - - if (!this.match.match (ev.getContextObject ())) - { - - return false; - - } - - } - - this.matchCount++; - - return this.matchCount >= this.count; - - } - - public boolean achieved (AbstractProjectViewer viewer) - { - - return false; - - } - - public void init (Element root) - { - - // Init the count. - try - { - - if (root != null) - { - - this.matchCount = JDOMUtils.getAttributeValueAsInt (root, - XMLConstants.count, - false); - - if (this.matchCount < 0) - { - - this.matchCount = 0; - - } - - } - - } catch (Exception e) { - - // Ignore it, for now. - - } - - } - - public void fillState (Element root) - { - - root.setAttribute (XMLConstants.count, - String.valueOf (this.matchCount)); - - } - -} \ No newline at end of file diff --git a/src/com/quollwriter/achievements/rules/ItemAchievementRule.java b/src/com/quollwriter/achievements/rules/ItemAchievementRule.java deleted file mode 100644 index f6186275..00000000 --- a/src/com/quollwriter/achievements/rules/ItemAchievementRule.java +++ /dev/null @@ -1,204 +0,0 @@ -package com.quollwriter.achievements.rules; - -import java.util.*; - -import org.jdom.*; - -import com.gentlyweb.utils.*; -import com.gentlyweb.xml.*; - -import com.quollwriter.data.*; -import com.quollwriter.ui.*; - -public class ItemAchievementRule extends AbstractAchievementRule -{ - - public static final String RULE_TYPE = "item"; - - public static Map objTypeToClassMapping = new HashMap (); - - static - { - - Map m = ItemAchievementRule.objTypeToClassMapping; - - m.put (Note.OBJECT_TYPE, - Note.class); - m.put (Chapter.OBJECT_TYPE, - Chapter.class); - m.put (QCharacter.OBJECT_TYPE, - QCharacter.class); - m.put (QObject.OBJECT_TYPE, - QObject.class); - m.put (Location.OBJECT_TYPE, - Location.class); - m.put (IdeaType.OBJECT_TYPE, - IdeaType.class); - m.put (Idea.OBJECT_TYPE, - Idea.class); - m.put (OutlineItem.OBJECT_TYPE, - OutlineItem.class); - m.put (Scene.OBJECT_TYPE, - Scene.class); - m.put (ResearchItem.OBJECT_TYPE, - ResearchItem.class); - - } - - public class XMLConstants - { - - public static final String action = "action"; - public static final String actions = "actions"; - public static final String objectType = "objectType"; - public static final String count = "count"; - public static final String match = "match"; - - } - - private Set actions = new HashSet (); - private String objType = null; - private ObjectMatch match = null; - private int count = 0; - private Class objClass = null; - - public ItemAchievementRule (Element root) - throws JDOMException - { - - super (root); - - this.objType = JDOMUtils.getAttributeValue (root, - XMLConstants.objectType, - true); - - this.objClass = ItemAchievementRule.objTypeToClassMapping.get (this.objType); - - if (this.objClass == null) - { - - throw new JDOMException ("Object type: " + - this.objType + - ", referenced by: " + - JDOMUtils.getAttribute (root, - XMLConstants.objectType, - true) + - " is not supported."); - - } - - String act = JDOMUtils.getAttributeValue (root, - XMLConstants.action, - false); - - if (!act.equals ("")) - { - - this.eventIds.add (this.objType + act.toLowerCase ()); - - } - - String acts = JDOMUtils.getAttributeValue (root, - XMLConstants.actions, - false); - - if (!acts.equals ("")) - { - - StringTokenizer t = new StringTokenizer (acts, - ",;"); - - while (t.hasMoreTokens ()) - { - - this.eventIds.add (this.objType + t.nextToken ().toLowerCase ()); - - } - - } - - Element mEl = JDOMUtils.getChildElement (root, - XMLConstants.match, - false); - - if (mEl != null) - { - - this.match = new ObjectMatch (mEl); - - } - - this.count = JDOMUtils.getAttributeValueAsInt (root, - XMLConstants.count, - false); - - } - - public boolean shouldPersistState () - { - - return false; - - } - - public boolean achieved (AbstractProjectViewer viewer, - ProjectEvent ev) - throws Exception - { - - return this.achieved (viewer); - - } - - public boolean achieved (ProjectEvent ev) - { - - return false; - - } - - public boolean achieved (AbstractProjectViewer viewer) - throws Exception - { - - // Get all the objects of the required type. - Set objs = viewer.getProject ().getAllNamedChildObjects (this.objClass); - - int c = objs.size (); - - if (this.match != null) - { - - c = 0; - - for (NamedObject n : objs) - { - - if (this.match.match (n)) - { - - c++; - - } - - } - - } - - return c >= this.count; - - } - - public void init (Element root) - { - - - - } - - public void fillState (Element root) - { - - } - -} \ No newline at end of file diff --git a/src/com/quollwriter/achievements/rules/ObjectMatch.java b/src/com/quollwriter/achievements/rules/ObjectMatch.java deleted file mode 100644 index 1badfd21..00000000 --- a/src/com/quollwriter/achievements/rules/ObjectMatch.java +++ /dev/null @@ -1,155 +0,0 @@ -package com.quollwriter.achievements.rules; - -import org.jdom.*; - -import com.gentlyweb.utils.*; -import com.gentlyweb.xml.*; - -import com.quollwriter.data.*; - -public class ObjectMatch -{ - - public class XMLConstants - { - - public static final String accessor = "accessor"; - public static final String value = "value"; - - } - - private Getter accessor = null; - private String value = null; - private String acc = null; - private boolean not = false; - - public ObjectMatch (Element root) - throws JDOMException - { - - this.value = JDOMUtils.getAttributeValue (root, - XMLConstants.value, - true); - - if (this.value.startsWith ("!")) - { - - this.not = true; - this.value = this.value.substring (1); - - } - - if (this.value.equals ("null")) - { - - this.value = null; - - } - - this.acc = JDOMUtils.getAttributeValue (root, - XMLConstants.accessor, - true); - - } - - public boolean match (Object d) - throws Exception - { - - if ((d == null) - && - (this.acc.equals ("")) - ) - { - - if (this.value == null) - { - - if (this.not) - { - - return false; - - } - - return true; - - } - - } - - if (this.accessor == null) - { - - this.accessor = new Getter (this.acc, - d.getClass ()); - - } - - Object obj = this.accessor.getValue (d); - - if (obj == null) - { - - if (this.value == null) - { - - if (this.not) - { - - return false; - - } - - return true; - - } - - } else { - - if (this.value == null) - { - - if (this.not) - { - - return true; - - } - - return false; - - } - - } - - String v = obj.toString (); - - if (v.equals (this.value)) - { - - if (this.not) - { - - return false; - - } - - return true; - - } else { - - if (this.not) - { - - return true; - - } - - return false; - - } - - } - -} \ No newline at end of file diff --git a/src/com/quollwriter/achievements/rules/SentenceAchievementRule.java b/src/com/quollwriter/achievements/rules/SentenceAchievementRule.java deleted file mode 100644 index f3d9d2c1..00000000 --- a/src/com/quollwriter/achievements/rules/SentenceAchievementRule.java +++ /dev/null @@ -1,119 +0,0 @@ -package com.quollwriter.achievements.rules; - -import java.util.*; - -import org.jdom.*; - -import com.gentlyweb.xml.*; - -import com.quollwriter.data.*; -import com.quollwriter.ui.*; - -public class SentenceAchievementRule extends AbstractAchievementRule -{ - - public static final String RULE_TYPE = "sentence"; - - public class XMLConstants - { - - public static final String sentenceCount = "sentenceCount"; - public static final String chapterCount = "chapterCount"; - - } - - private int sentenceCount = -1; - private int chapterCount = -1; - - public SentenceAchievementRule (Element root) - throws JDOMException - { - - super (root); - - this.sentenceCount = JDOMUtils.getAttributeValueAsInt (root, - XMLConstants.sentenceCount, - false); - - this.chapterCount = JDOMUtils.getAttributeValueAsInt (root, - XMLConstants.chapterCount, - false); - - } - - public String toString () - { - - return super.toString () + "(sentence count: " + this.sentenceCount + ", chapter count: " + this.chapterCount + ")"; - - } - - public boolean shouldPersistState () - { - - return false; - - } - - public boolean achieved (AbstractProjectViewer viewer, - ProjectEvent ev) - throws Exception - { - - return this.achieved (viewer); - - } - - public boolean achieved (AbstractProjectViewer viewer) - { - - Set chapters = viewer.getProject ().getAllNamedChildObjects (Chapter.class); - - if (this.chapterCount > 0) - { - - if (this.chapterCount > chapters.size ()) - { - - return false; - - } - - } - - for (NamedObject c : chapters) - { - - ChapterCounts cc = viewer.getChapterCounts ((Chapter) c); - - if (cc == null) - { - - return false; - - } - - if (cc.sentenceCount >= this.sentenceCount) - { - - return true; - - } - - } - - return false; - - } - - public void init (Element root) - { - - } - - public void fillState (Element root) - { - - } - -} \ No newline at end of file diff --git a/src/com/quollwriter/achievements/rules/SessionAchievementRule.java b/src/com/quollwriter/achievements/rules/SessionAchievementRule.java deleted file mode 100644 index 142a7e75..00000000 --- a/src/com/quollwriter/achievements/rules/SessionAchievementRule.java +++ /dev/null @@ -1,473 +0,0 @@ -package com.quollwriter.achievements.rules; - -import java.util.*; - -import org.jdom.*; - -import com.gentlyweb.xml.*; - -import com.quollwriter.ui.*; - -import com.quollwriter.data.*; - -import com.quollwriter.*; - -public class SessionAchievementRule extends AbstractAchievementRule -{ - - public static final String RULE_TYPE = "session"; - - public static final String EDIT = "edit"; - public static final String NO_EDIT = "noedit"; - - public class XMLConstants - { - - - public static final String mins = "mins"; - public static final String wordCount = "wordCount"; - public static final String currentSession = "currentSession"; - public static final String count = "count"; - public static final String days = "days"; - public static final String action = "action"; - public static final String lastChecked = "lastChecked"; - - } - - private int mins = -1; - private int wordCount = 0; - private int count = -1; - private int days = 0; - private String action = null; - private boolean currentSession = false; - - private long lastChecked = 0; - - private List previousSessions = new ArrayList (); - - private SessionData currData = new SessionData (); - - private long lastEdit = -1; - private long startEdit = -1; - - private Set editedChapters = new HashSet (); - - public SessionAchievementRule (Element root) - throws JDOMException - { - - super (root); - - this.action = JDOMUtils.getAttributeValue (root, - XMLConstants.action, - false).toLowerCase (); - - this.currentSession = JDOMUtils.getAttributeValueAsBoolean (root, - XMLConstants.currentSession, - false); - - this.count = JDOMUtils.getAttributeValueAsInt (root, - XMLConstants.count, - false); - - this.wordCount = JDOMUtils.getAttributeValueAsInt (root, - XMLConstants.wordCount, - false); - - this.days = JDOMUtils.getAttributeValueAsInt (root, - XMLConstants.days, - false); - - this.mins = JDOMUtils.getAttributeValueAsInt (root, - XMLConstants.mins, - false); - - } - - public String toString () - { - - return super.toString () + "(current session: " + this.currentSession + ", action: " + this.action + ", count: " + this.count + ", wordCount: " + this.wordCount + ", days: " + this.days + ", mins: " + this.mins + ", previous session: " + this.previousSessions + ")"; - - } - - public boolean shouldPersistState () - { - - return !this.currentSession || this.lastChecked != 0; - - } - - public boolean achieved (AbstractProjectViewer viewer, - ProjectEvent ev) - { - - if (ev.getType ().equals (Project.OBJECT_TYPE)) - { - - if (ev.getAction ().equals (ProjectEvent.OPEN)) - { - - this.currData.start = System.currentTimeMillis (); - - } - - if (ev.getAction ().equals (ProjectEvent.CLOSE)) - { - - this.currData.end = System.currentTimeMillis (); - - this.currData.wordCount = viewer.getSessionWordCount (); - - this.lastChecked = System.currentTimeMillis (); - - } - - } - - long now = System.currentTimeMillis (); - - if (this.currentSession) - { - - if ((ev.getType ().equals (Chapter.OBJECT_TYPE)) - && - (ev.getAction ().equals (ProjectEvent.EDIT)) - ) - { - - if (this.count > 0) - { - - Object o = ev.getContextObject (); - - if (o != null) - { - - if (o instanceof Chapter) - { - - this.editedChapters.add (((Chapter) o).getKey ()); - - } - - if (this.editedChapters.size () >= this.count) - { - - return true; - - } - - } - - } - - if (this.mins > 0) - { - - if (this.lastEdit < 0) - { - - this.lastEdit = now; - this.startEdit = now; - - return false; - - } else { - - if ((now - this.lastEdit) > 300000) - { - - this.startEdit = now; - - } else { - - if ((now - this.startEdit) >= (this.mins * 60000)) - { - - return true; - - } - - } - - this.lastEdit = now; - - } - - } - - } - - } - - if (ev.getType ().equals (Project.OBJECT_TYPE)) - { - - if (ev.getAction ().equals (ProjectEvent.OPEN)) - { - - if (this.action.equals (NO_EDIT)) - { - - if (viewer != null) - { - - if (this.lastChecked > 0) - { - - if (this.days > 0) - { - - long diff = now - this.lastChecked; - - long time = (long) 86400000 * (long) this.days; - - if (diff > time) - { - - return true; - - } - - } - - } - - } - - } - - int sessSize = this.previousSessions.size (); - - if ((this.count > 0) - && - (sessSize < this.count) - ) - { - - return false; - - } - - // Check the days. - if (this.days > 0) - { - - long diff = this.previousSessions.get (sessSize - 1).end - this.previousSessions.get (0).start; - - int days = (int) (diff / (24 * 60 * 60 * 1000)); - - if (days != this.days) - { - - return false; - - } - - } - - if (this.wordCount > 0) - { - - // Check each session. - for (SessionData sd : this.previousSessions) - { - - if (sd.wordCount < this.wordCount) - { - - return false; - - } - - } - - } - - return true; - - } - - } - - return false; - - } - - public boolean achieved (AbstractProjectViewer viewer) - { - - if (this.currentSession) - { - - if (this.wordCount > 0) - { - - if (viewer != null) - { - - return viewer.getSessionWordCount () > this.wordCount; - - } - - } - - } - - return false; - - } - - public void init (Element root) - - { - - try - { - - List els = JDOMUtils.getChildElements (root, - SessionData.XMLConstants.root, - false); - - for (int i = 0; i < els.size (); i++) - { - - Element el = (Element) els.get (i); - - this.previousSessions.add (new SessionData (el)); - - } - - } catch (Exception e) { - - // Ignore. - Environment.logError ("Unable to init from: " + - JDOMUtils.getPath (root), - e); - - } - - try - { - - String lc = JDOMUtils.getAttributeValue (root, - XMLConstants.lastChecked, - false); - - if (!lc.equals ("")) - { - - this.lastChecked = Long.parseLong (lc); - - } - - } catch (Exception e) { - - // Ignore... - - } - - } - - public void fillState (Element root) - { - - if (this.count > 0) - { - - List sessions = new ArrayList (this.previousSessions); - - sessions.add (this.currData); - - // Only keep sessions within the past 2 weeks. - long last = System.currentTimeMillis () - (14 * 24 * 60 * 60 * 1000); - - for (SessionData sd : sessions) - { - - if (sd.end < last) - { - - continue; - - } - - root.addContent (sd.getAsElement ()); - - } - - } - - if (this.lastChecked > 0) - { - - root.setAttribute (XMLConstants.lastChecked, - String.valueOf (this.lastChecked)); - - } - - } - - public class SessionData - { - - public class XMLConstants - { - - public static final String root = "session"; - public static final String start = "start"; - public static final String end = "end"; - public static final String wordCount = "wordCount"; - - } - - public long start = 0; - public long end = 0; - public int wordCount = 0; - - public SessionData () - { - - } - - public SessionData (Element root) - throws JDOMException - { - - this.start = Long.parseLong (JDOMUtils.getAttributeValue (root, - XMLConstants.start)); - this.end = Long.parseLong (JDOMUtils.getAttributeValue (root, - XMLConstants.end)); - - this.wordCount = JDOMUtils.getAttributeValueAsInt (root, - XMLConstants.wordCount); - this.wordCount = 560; - } - - public Element getAsElement () - { - - Element root = new Element (XMLConstants.root); - - root.setAttribute (XMLConstants.start, - String.valueOf (this.start)); - root.setAttribute (XMLConstants.end, - String.valueOf (this.end)); - root.setAttribute (XMLConstants.wordCount, - String.valueOf (this.wordCount)); - - return root; - - } - - public String toString () - { - - return "start: " + new Date (this.start) + ", end: " + new Date (this.end) + ", word count: " + this.wordCount; - - } - - } - -} \ No newline at end of file diff --git a/src/com/quollwriter/achievements/rules/WordAchievementRule.java b/src/com/quollwriter/achievements/rules/WordAchievementRule.java deleted file mode 100644 index 342b8c90..00000000 --- a/src/com/quollwriter/achievements/rules/WordAchievementRule.java +++ /dev/null @@ -1,166 +0,0 @@ -package com.quollwriter.achievements.rules; - -import java.util.*; - -import org.jdom.*; - -import com.gentlyweb.xml.*; - -import com.quollwriter.data.*; -import com.quollwriter.ui.*; - -public class WordAchievementRule extends AbstractAchievementRule -{ - - public static final String RULE_TYPE = "word"; - - public class XMLConstants - { - - public static final String wordCount = "wordCount"; - public static final String count = "count"; - public static final String chapter = "chapter"; - public static final String allowRepeats = "allowRepeats"; - public static final String words = "words"; - - } - - private int count = -1; - private boolean allowRepeats = false; - private boolean chaptersOnly = false; - private Map words = new HashMap (); - - public WordAchievementRule (Element root) - throws JDOMException - { - - super (root); - - this.allowRepeats = JDOMUtils.getAttributeValueAsBoolean (root, - XMLConstants.allowRepeats, - false); - - this.count = JDOMUtils.getAttributeValueAsInt (root, - XMLConstants.count, - false); - - this.chaptersOnly = JDOMUtils.getAttributeValueAsBoolean (root, - XMLConstants.chapter, - false); - - if ((this.count < 1) - && - (this.chaptersOnly) - ) - { - - this.count = 1; - - } - - String w = JDOMUtils.getAttributeValue (root, - XMLConstants.words); - - StringTokenizer t = new StringTokenizer (w, - ",;"); - - while (t.hasMoreTokens ()) - { - - this.words.put (t.nextToken ().trim ().toLowerCase (), - ""); - - } - - } - - public String toString () - { - - return super.toString () + "(count: " + this.count + ", words: " + this.words + ", chapters only: " + this.chaptersOnly + ", allow repeats: " + this.allowRepeats + ")"; - - } - - public boolean shouldPersistState () - { - - return false; - - } - - public boolean achieved (AbstractProjectViewer viewer, - ProjectEvent ev) - throws Exception - { - - return this.achieved (viewer); - - } - - public boolean achieved (AbstractProjectViewer viewer) - { - - if (this.chaptersOnly) - { - - Set counts = viewer.getAllChapterCountsAsSet (); - - for (ChapterCounts cc : counts) - { - - int c = 0; - - for (String w : this.words.keySet ()) - { - - if (cc.wordFrequency != null) - { - - Integer wc = cc.wordFrequency.get (w); - - if (wc != null) - { - - if (this.allowRepeats) - { - - c += wc.intValue (); - - } else { - - c++; - - } - - } - - } - - } - - if (c >= this.count) - { - - return true; - - } - - } - - } - - return false; - - } - - public void init (Element root) - { - - } - - public void fillState (Element root) - { - - } - -} \ No newline at end of file diff --git a/src/com/quollwriter/achievements/rules/WordCountAchievementRule.java b/src/com/quollwriter/achievements/rules/WordCountAchievementRule.java deleted file mode 100644 index fb3f4398..00000000 --- a/src/com/quollwriter/achievements/rules/WordCountAchievementRule.java +++ /dev/null @@ -1,141 +0,0 @@ -package com.quollwriter.achievements.rules; - -import java.util.*; - -import org.jdom.*; - -import com.gentlyweb.xml.*; - -import com.quollwriter.data.*; -import com.quollwriter.ui.*; - -public class WordCountAchievementRule extends AbstractAchievementRule -{ - - public static final String RULE_TYPE = "wordcount"; - - public class XMLConstants - { - - public static final String wordCount = "wordCount"; - public static final String count = "count"; - public static final String chapter = "chapter"; - - } - - private int count = -1; - private int wordCount = 0; - private boolean chaptersOnly = false; - - public WordCountAchievementRule (Element root) - throws JDOMException - { - - super (root); - - this.count = JDOMUtils.getAttributeValueAsInt (root, - XMLConstants.count, - false); - - this.wordCount = JDOMUtils.getAttributeValueAsInt (root, - XMLConstants.wordCount); - - this.chaptersOnly = JDOMUtils.getAttributeValueAsBoolean (root, - XMLConstants.chapter, - false); - - if ((this.count < 1) - && - (this.chaptersOnly) - ) - { - - this.count = 1; - - } - - } - - public String toString () - { - - return super.toString () + "(count: " + this.count + ", wordCount: " + this.wordCount + ", chapters only: " + this.chaptersOnly + ")"; - - } - - public boolean shouldPersistState () - { - - return false; - - } - - public boolean achieved (AbstractProjectViewer viewer, - ProjectEvent ev) - throws Exception - { - - return this.achieved (viewer); - - } - - public boolean achieved (AbstractProjectViewer viewer) - { - - if (viewer == null) - { - - return false; - - } - - if (this.chaptersOnly) - { - - int c = 0; - - Set counts = viewer.getAllChapterCountsAsSet (); - - for (ChapterCounts cc : counts) - { - - if (cc.wordCount >= this.wordCount) - { - - c++; - - } - - } - - if (c >= this.count) - { - - return true; - - } - - } - - if (viewer.getAllChapterCounts ().wordCount >= this.wordCount) - { - - return true; - - } - - return false; - - } - - public void init (Element root) - { - - } - - public void fillState (Element root) - { - - } - -} \ No newline at end of file diff --git a/src/com/quollwriter/data/BlankNamedObject.java b/src/com/quollwriter/data/BlankNamedObject.java deleted file mode 100644 index 3c45807c..00000000 --- a/src/com/quollwriter/data/BlankNamedObject.java +++ /dev/null @@ -1,47 +0,0 @@ -package com.quollwriter.data; - -import java.util.*; - -import org.jdom.*; - - -public class BlankNamedObject extends NamedObject -{ - - public BlankNamedObject() - { - - super (null); - - } - - public BlankNamedObject(String objType, - String name) - { - - super (objType, - name); - - } - - public void getChanges (NamedObject old, - Element root) - { - - } - - public void setObjectType (String t) - { - - super.setObjectType (t); - - } - - public Set getAllNamedChildObjects () - { - - return new HashSet (); - - } - -} diff --git a/src/com/quollwriter/data/Chapter.java b/src/com/quollwriter/data/Chapter.java deleted file mode 100644 index 2c4be7c5..00000000 --- a/src/com/quollwriter/data/Chapter.java +++ /dev/null @@ -1,1308 +0,0 @@ -package com.quollwriter.data; - -import java.io.*; - -import java.util.*; - -import javax.swing.text.Position; -import javax.swing.text.Document; - -import com.gentlyweb.utils.*; - -import com.quollwriter.*; -import com.quollwriter.data.comparators.*; - -import org.incava.util.diff.*; - -import org.jdom.*; - -import com.quollwriter.text.*; - -public class Chapter extends LegacyUserConfigurableObject -{ - - public static final String PLAN_LEGACY_FIELD_ID = "plan"; - //public static final String PLAN_LEGACY_FIELD_FORM_NAME = "Plan"; - public static final String GOALS_LEGACY_FIELD_ID = "goals"; - //public static final String GOALS_LEGACY_FIELD_FORM_NAME = "Goals"; - - public static final String OBJECT_TYPE = "chapter"; - public static final String INFORMATION_OBJECT_TYPE = "chapterinformation"; - public static final String EDIT_POSITION = "editposition"; - - private Book book = null; - private StringWithMarkup text = null; - private StringWithMarkup goals = null; - private StringWithMarkup plan = null; - private Set outlineItems = new HashSet (); //TreeSet (new ChapterItemSorter ()); - private Set scenes = new HashSet (); //TreeSet (new ChapterItemSorter ()); - private int editPosition = -1; - private Position textEditPos = null; - private boolean editComplete = false; - private Set problemFinderIgnores = new HashSet<> (); - - private ProjectVersion projVersion = null; - - public Chapter() - { - - super (Chapter.OBJECT_TYPE); - - } - - public Chapter(Book b) - { - - this (); - - this.setBook (b); - - } - - public Chapter(Book b, - String name) - { - - this (b); - - this.setName (name); - - } - - protected Chapter(String objType) - { - - super (objType); - - } - - public boolean isFieldSupported (String id) - { - - if ((id.equals (DESCRIPTION_LEGACY_FIELD_ID)) - || - (id.equals (ALIASES_LEGACY_FIELD_ID)) - || - (id.equals (PLAN_LEGACY_FIELD_ID)) - || - (id.equals (GOALS_LEGACY_FIELD_ID)) - ) - { - - return true; - - } - - return false; - - } - - public void initProblemFinderIgnoreDocumentPositions (Document doc) - throws Exception - { - - for (Issue i : this.problemFinderIgnores) - { - - i.setStartPosition (doc.createPosition (i.getStartIssuePosition ())); - - } - - } - - public Set getProblemFinderIgnores (Rule forRule) - { - - Set ignores = new LinkedHashSet (); - - for (Issue i : this.problemFinderIgnores) - { - - if (i.getRuleId ().equals (forRule.getId ())) - { - - ignores.add (i); - - } - - } - - return ignores; - - } - - public Set getProblemFinderIgnores () - { - - return this.problemFinderIgnores; - - } - - public void setProblemFinderIgnores (Set ignores) - { - - this.problemFinderIgnores = ignores; - - } - - public void setProjectVersion (ProjectVersion v) - { - - this.projVersion = v; - - } - - public ProjectVersion getProjectVersion () - { - - if (this.projVersion == null) - { - - return this.getBook ().getProject ().getProjectVersion (); - - } - - return this.projVersion; - - } - - /** - * If a chapter item has it's position changed (say via a drag/drop operation to move it) - * then the sets need to be "reindexed" since the ordering is dependent on the position and - * it is only done once when the item is added (probably for performance sake). - * - * This method recreates the sets backing the scenes/notes/outline items and calls the - * same reindex method on child objects, so re-initing the entire tree. - */ - /* - public synchronized void reindex () - { - - super.reindex (); - - TreeSet sscenes = new TreeSet (new ChapterItemSorter ()); - - sscenes.addAll (this.scenes); - - this.scenes = sscenes; - - TreeSet ooutlineItems = new TreeSet (new ChapterItemSorter ()); - - ooutlineItems.addAll (this.outlineItems); - - this.outlineItems = ooutlineItems; - - for (Scene s : this.scenes) - { - - s.reindex (); - - } - - for (OutlineItem it : this.outlineItems) - { - - it.reindex (); - - } - - } -*/ - public boolean isEditComplete () - { - - return this.editComplete; - - } - - public void setEditComplete (boolean b) - { - - this.editComplete = b; - - } - /* - public String getMarkup () - { - - return this.markup; - - } - - public void setMarkup (String m) - { - - this.markup = m; - - } -*/ - public void getChanges (NamedObject old, - Element root) - { - - Chapter c = (Chapter) old; - - this.addFieldChangeElement (root, - "goals", - ((old != null) ? c.getGoals () : null), - this.goals); - - this.addFieldChangeElement (root, - "plan", - ((old != null) ? c.getPlan () : null), - this.plan); - - if (old != null) - { - - String ot = c.getChapterText (); - - if (ot == null) - { - - ot = ""; - - } - - ot = TextUtilities.stripNonValidXMLCharacters (ot); - - String nt = this.getChapterText (); - - if (nt == null) - { - - nt = ""; - - } - - nt = TextUtilities.stripNonValidXMLCharacters (nt); - - String[] oldText = ot.split ("\\n"); - String[] newText = nt.split ("\\n"); - - List diffs = new Diff (oldText, - newText).diff (); - - if (diffs.size () > 0) - { - - Element fieldEl = new Element ("field"); - - root.addContent (fieldEl); - - fieldEl.setAttribute ("name", - "text"); - - fieldEl.setAttribute ("type", - "diff"); - - for (int i = 0; i < diffs.size (); i++) - { - - Difference d = (Difference) diffs.get (i); - - if (d.getDeletedEnd () == Difference.NONE) - { - - // This is an addition. - for (int k = d.getAddedStart (); k < (d.getAddedEnd () + 1); k++) - { - - Element el = new Element ("change"); - fieldEl.addContent (el); - el.setAttribute ("type", - "add"); - el.setAttribute ("line", - String.valueOf (k)); - el.addContent (newText[k]); - - } - - continue; - - } - - if (d.getAddedEnd () == Difference.NONE) - { - - // This is a deletion. - for (int k = d.getDeletedStart (); k < (d.getDeletedEnd () + 1); k++) - { - - Element el = new Element ("change"); - fieldEl.addContent (el); - el.setAttribute ("type", - "remove"); - el.setAttribute ("line", - String.valueOf (k)); - el.addContent (oldText[k]); - - } - - continue; - - } - - // This is a modification. - for (int k = d.getAddedStart (); k < (d.getAddedEnd () + 1); k++) - { - - Element el = new Element ("change"); - fieldEl.addContent (el); - el.setAttribute ("type", - "change"); - el.setAttribute ("line", - String.valueOf (k)); - - Element oel = new Element ("old"); - el.addContent (oel); - - ot = ""; - - if (k < oldText.length) - { - - ot = oldText[k]; - - } - - oel.addContent (ot); - - Element nel = new Element ("new"); - el.addContent (nel); - - nt = ""; - - if (k < newText.length) - { - - nt = newText[k]; - - } - - nel.addContent (nt); - - } - - } - - } - - } else - { - - this.addFieldChangeElement (root, - "text", - null, - this.getChapterText ()); - - } - - } - - public DataObject getObjectForReference (ObjectReference r) - { - - DataObject d = super.getObjectForReference (r); - - if (d != null) - { - - return d; - - } - - for (Scene s : this.scenes) - { - - d = s.getObjectForReference (r); - - if (d != null) - { - - return d; - - } - - } - - for (OutlineItem i : this.outlineItems) - { - - d = i.getObjectForReference (r); - - if (d != null) - { - - return d; - - } - - } - - return null; - - } - - public Set getChapterItemsWithPositionGreaterThan (int pos) - { - - Set items = new TreeSet (new ChapterItemSorter ()); - - for (OutlineItem it : this.outlineItems) - { - - if (it.getPosition () > pos) - { - - items.add (it); - - } - - } - - for (Scene s : this.scenes) - { - - if (s.getPosition () > pos) - { - - items.add (s); - - } - - } - - for (Note n : this.getNotes ()) - { - - if (n.getPosition () > pos) - { - - items.add (n); - - } - - } - - return items; - - } - - public Set getChapterItemsWithPositionBetween (int start, - int end) - { - - Set items = new TreeSet (new ChapterItemSorter ()); - - for (OutlineItem it : this.outlineItems) - { - - if ((it.getPosition () >= start) - && - (it.getPosition () <= end) - ) - { - - items.add (it); - - } - - } - - for (Scene s : this.scenes) - { - - if ((s.getPosition () >= start) - && - (s.getPosition () <= end) - ) - { - - items.add (s); - - } - - } - - for (Note n : this.getNotes ()) - { - - if ((n.getPosition () >= start) - && - (n.getPosition () <= end) - ) - { - - items.add (n); - - } - - } - - return items; - - } - - public Set getItemsFromPositionToNextScene (int pos) - { - - Set items = new TreeSet (new ChapterItemSorter ()); - - for (OutlineItem it : this.outlineItems) - { - - if (it.getPosition () >= pos) - { - - items.add (it); - - } - - } - - Scene s = this.getLastScene (pos); - - if (s != null) - { - - for (OutlineItem it : s.getOutlineItems ()) - { - - if (it.getPosition () >= pos) - { - - items.add (it); - - } - - } - - } - - return items; - - } - - public Scene getSceneAt (int pos) - { - - for (Scene s : this.scenes) - { - - if (s.getPosition () == pos) - { - - return s; - - } - - } - - return null; - - } - - public Set getScenesAt (int pos) - { - - Set scenes = new TreeSet (new ChapterItemSorter ()); - - for (Scene s : this.scenes) - { - - if (s.getPosition () == pos) - { - - scenes.add (s); - - } - - } - - return scenes; - - } - - public OutlineItem getOutlineItemAt (int pos) - { - - for (Scene s : this.scenes) - { - - OutlineItem it = s.getOutlineItemAt (pos); - - if (it != null) - { - - return it; - - } - - } - - for (OutlineItem it : this.outlineItems) - { - - if (it.getPosition () == pos) - { - - return it; - - } - - } - - return null; - - } - - public Set getOutlineItemsAt (int pos) - { - - Set its = new TreeSet (new ChapterItemSorter ()); - - for (Scene s : this.scenes) - { - - its.addAll (s.getOutlineItemsAt (pos)); - - } - - for (OutlineItem it : this.outlineItems) - { - - if (it.getPosition () == pos) - { - - its.add (it); - - } - - } - - return its; - - } - - public Set getAllNamedChildObjects () - { - - Set objs = new TreeSet (new ChapterItemSorter ()); - - objs.addAll (this.scenes); - objs.addAll (this.outlineItems); - objs.addAll (this.getNotes ()); - - return objs; - - } - - public void addChapterItem (ChapterItem item) - { - - if (item.getObjectType ().equals (Note.OBJECT_TYPE)) - { - - this.addNote ((Note) item); - - } - - if (item.getObjectType ().equals (OutlineItem.OBJECT_TYPE)) - { - - this.addOutlineItem ((OutlineItem) item); - - } - - if (item.getObjectType ().equals (Scene.OBJECT_TYPE)) - { - - this.addScene ((Scene) item); - - } - - } - - public Set getAllStructureItemsWithinRange (int min, - int max) - { - - Set items = new TreeSet (new ChapterItemSorter ()); - - for (OutlineItem it : this.outlineItems) - { - - if (it.getPosition () < min || it.getPosition () > max) - { - - continue; - - } - - items.add (it); - - } - - for (Scene s : this.scenes) - { - - if (s.getPosition () >= min && s.getPosition () <= max) - { - - items.add (s); - - } - - Set oitems = s.getOutlineItems (); - - for (OutlineItem oit : oitems) - { - - if (oit.getPosition () < min || oit.getPosition () > max) - { - - continue; - - } - - items.add (oit); - - } - - } - - return items; - - } - - public Set getChapterItems (String objType) - { - - if (objType.equals (OutlineItem.OBJECT_TYPE)) - { - - return this.getOutlineItems (); - - } - - if (objType.equals (Note.OBJECT_TYPE)) - { - - return this.getNotes (); - - } - - if (objType.equals (Scene.OBJECT_TYPE)) - { - - return this.getScenes (); - - } - - return null; - - } - - public void addNote (Note n) - { - - if (this.getNotes ().contains (n)) - { - - return; - - } - - if ((n.getChapter () != null) - && - (n.getChapter () != this) - ) - { - - n.getChapter ().removeNote (n); - - } - - super.addNote (n); - - } - - public void addScene (Scene s) - { - - if (this.scenes.contains (s)) - { - - return; - - } - - if ((s.getChapter () != null) - && - (s.getChapter () != this) - ) - { - - s.getChapter ().removeScene (s); - - } - - s.setChapter (this); -/* - for (OutlineItem i : s.getOutlineItems ()) - { - - i.setChapter (this); - - } -*/ - this.scenes.add (s); - - } - - public void removeScene (Scene s) - { - - this.scenes.remove (s); - - } - - public Set getScenes () - { - - Set items = new TreeSet (new ChapterItemSorter ()); - - items.addAll (this.scenes); - - return items; - - } - - public Set getOutlineItems () - { - - Set items = new TreeSet (new ChapterItemSorter ()); - - items.addAll (this.outlineItems); - - return items; - - } -/* - private void setOutlineItems (List l) - { - - this.outlineItems = l; - - } -*/ - public void removeChapterItem (ChapterItem i) - { - - if (i.getObjectType ().equals (OutlineItem.OBJECT_TYPE)) - { - - this.removeOutlineItem ((OutlineItem) i); - - } - - if (i.getObjectType ().equals (Note.OBJECT_TYPE)) - { - - this.removeNote ((Note) i); - - } - - if (i.getObjectType ().equals (Scene.OBJECT_TYPE)) - { - - this.removeScene ((Scene) i); - - } - - } - - public void removeOutlineItem (OutlineItem i) - { - - this.outlineItems.remove (i); - - } - - public void addOutlineItem (OutlineItem i) - { - - if (i.getScene () != null) - { - - i.getScene ().removeOutlineItem (i); - - i.setScene (null); - - } - - if ((i.getChapter () != null) - && - (i.getChapter () != this) - ) - { - - i.getChapter ().removeOutlineItem (i); - - } - - i.setChapter (this); - - this.outlineItems.add (i); - - } - - public String getChapterText () - { - - return (this.text != null ? this.text.getText () : null); - - } - - public StringWithMarkup getText () - { - - return this.text; - - } - - public void setText (StringWithMarkup t) - { - - if (t != null) - { - - String _t = t.getText (); - - if (_t != null) - { - - _t = com.quollwriter.text.TextUtilities.sanitizeText (_t); -/* - _t = StringUtils.replaceString (_t, - String.valueOf ('\r'), - ""); - */ - t.update (_t, - t.getMarkup ()); - - } - - } - - this.text = t; - - this.setLastModified (new Date ()); - - } - - public StringWithMarkup getGoals () - { - - return this.goals; - - } - - public void setGoals (StringWithMarkup t) - { - - if ((t != null) - && - (t.hasText ()) - ) - { - - t.update (StringUtils.replaceString (t.getText (), - String.valueOf ('\r'), - ""), - t.getMarkup ()); - - } - - UserConfigurableObjectField f = this.getLegacyField (GOALS_LEGACY_FIELD_ID); - - if (f == null) - { - - UserConfigurableObjectTypeField type = this.getLegacyTypeField (GOALS_LEGACY_FIELD_ID); - - f = new UserConfigurableObjectField (type); - - f.setParent (this); - this.fields.add (f); - - } - - try - { - - f.setValue (t); - - } catch (Exception e) { - - throw new IllegalArgumentException ("Unable to json encode string with markup: " + - t, - e); - - } - - this.goals = t; - - this.setLastModified (new Date ()); - - } - - public StringWithMarkup getPlan () - { - - return this.plan; - - } - - public void setPlan (StringWithMarkup t) - { - - if ((t != null) - && - (t.hasText ()) - ) - { - - t.update (StringUtils.replaceString (t.getText (), - String.valueOf ('\r'), - ""), - t.getMarkup ()); - - } - - UserConfigurableObjectField f = this.getLegacyField (PLAN_LEGACY_FIELD_ID); - - if (f == null) - { - - UserConfigurableObjectTypeField type = this.getLegacyTypeField (PLAN_LEGACY_FIELD_ID); - - f = new UserConfigurableObjectField (type); - - f.setParent (this); - this.fields.add (f); - - } - - try - { - - f.setValue (t); - - } catch (Exception e) { - - throw new IllegalArgumentException ("Unable to json encode string with markup: " + - t, - e); - - } - - this.plan = t; - - this.setLastModified (new Date ()); - - } - /* - @Override - public String toString () - { - - return Environment.formatObjectToStringProperties (this); - - } - */ - @Override - public void fillToStringProperties (Map props) - { - - super.fillToStringProperties (props); - - this.addToStringProperties (props, - "editPosition", - this.editPosition); - this.addToStringProperties (props, - "editComplete", - this.editComplete); - this.addToStringProperties (props, - "textLength", - this.getChapterLength ()); - this.addToStringProperties (props, - "book", - this.book); - this.addToStringProperties (props, - "scenes", - this.scenes.size ()); - this.addToStringProperties (props, - "outlineItems", - this.outlineItems.size ()); - - } - - public void setBook (Book b) - { - - this.book = b; - - this.setParent (b); - - } - - public Book getBook () - { - - return this.book; - - } - - public Scene getNextScene (Scene s) - { - - TreeSet items = new TreeSet (new ChapterItemSorter ()); - - items.addAll (this.scenes); - - return items.higher (s); - - } - - public Scene getLastScene (int position) - { - - Scene last = null; - - for (Scene s : this.getScenes ()) - { - - if (s.getPosition () >= position) - { - - return last; - - } else - { - - last = s; - - } - - } - - return last; - - } - - public List getNotesBetween (int start, - int end) - { - - List newNotes = new ArrayList (); - - for (Note n : this.getNotes ()) - { - - if ((n.getPosition () >= start) && - (n.getPosition () <= end)) - { - - newNotes.add (n); - - } - - } - - return newNotes; - - } - - public void setTextEditPosition (Position p) - { - - this.textEditPos = p; - - if (p == null) - { - - this.editPosition = -1; - - } - - } - - public void setEditPosition (int p) - { - - int oldPos = this.editPosition; - - this.editPosition = p; - - this.textEditPos = null; - - this.firePropertyChangedEvent (EDIT_POSITION, - oldPos, - this.editPosition); - - } - - public int getEditPosition () - { - - if (this.textEditPos != null) - { - - return this.textEditPos.getOffset (); - - } - - return this.editPosition; - - } - - public int getChapterLength () - { - - if (this.text == null) - { - - return 0; - - } - - if (this.text.getText () == null) - { - - return 0; - - } - - return this.text.getText ().length (); - - } - - public boolean isPositionAtChapterEnd (int p) - { - - int cl = this.getChapterLength (); - - if (cl == 0) - { - - return p == cl; - - } - - return p >= cl - 1; - - } - -} diff --git a/src/com/quollwriter/data/ChapterCounts.java b/src/com/quollwriter/data/ChapterCounts.java deleted file mode 100644 index 24681f2c..00000000 --- a/src/com/quollwriter/data/ChapterCounts.java +++ /dev/null @@ -1,89 +0,0 @@ -package com.quollwriter.data; - -import java.util.*; - -import com.quollwriter.text.*; - -public class ChapterCounts -{ - - //public Chapter chapter = null; - public int wordCount = 0; - public int sentenceCount = 0; - public int standardPageCount = 0; - public Map wordFrequency = null; - - public ChapterCounts () - { - - } - - public ChapterCounts (String t) - { - - if (t != null) - { - - TextIterator ti = new TextIterator (t); - - this.wordCount = ti.getWordCount (); - this.sentenceCount = ti.getSentenceCount (); - - this.wordFrequency = ti.getWordFrequency (); - - } - - } - - public void add (ChapterCounts c) - { - - //this.chapter = null; - this.wordCount += c.wordCount; - this.sentenceCount += c.sentenceCount; - this.standardPageCount += c.standardPageCount; - - if (this.wordFrequency == null) - { - - this.wordFrequency = new HashMap (); - - } - - if (c.wordFrequency != null) - { - - for (Map.Entry en : c.wordFrequency.entrySet ()) - { - - String w = en.getKey (); - Integer oc = en.getValue (); - - Integer count = this.wordFrequency.get (w); - - int wc = 1; - - if (count != null) - { - - wc += count.intValue (); - - } - - if (oc != null) - { - - wc += oc.intValue (); - - } - - this.wordFrequency.put (w, - Integer.valueOf (wc)); - - } - - } - - } - -} diff --git a/src/com/quollwriter/data/ChapterItem.java b/src/com/quollwriter/data/ChapterItem.java deleted file mode 100644 index 01214d99..00000000 --- a/src/com/quollwriter/data/ChapterItem.java +++ /dev/null @@ -1,268 +0,0 @@ -package com.quollwriter.data; - -import java.util.*; - -import javax.swing.text.Position; - -import com.quollwriter.data.comparators.*; - -public abstract class ChapterItem extends NamedObject -{ - - private int position = -1; - private int endPosition = -1; - private Position textPos = null; - private Position endTextPos = null; - protected Chapter chapter = null; - protected Scene scene = null; - - public static Set getEmptyChapterItemSet () - { - - return new TreeSet (new ChapterItemSorter ()); - - } - - protected ChapterItem(String objType) - { - - super (objType); - - } - - protected ChapterItem(String objType, - int at, - Chapter c) - { - - this (objType); - - this.position = at; - this.chapter = c; - - } - - protected ChapterItem(String objType, - int start, - int end, - Chapter c) - { - - this (objType, - start, - c); - - this.endPosition = end; - - } - - @Override - public void fillToStringProperties (Map props) - { - - super.fillToStringProperties (props); - - this.addToStringProperties (props, - "position", - this.position); - this.addToStringProperties (props, - "endPosition", - this.endPosition); - this.addToStringProperties (props, - "textPosition", - (this.textPos != null ? this.textPos.getOffset () : null)); - this.addToStringProperties (props, - "endTextPosition", - (this.endTextPos != null ? this.endTextPos.getOffset () : null)); - this.addToStringProperties (props, - "scene", - this.scene); - this.addToStringProperties (props, - "chapter", - this.chapter); - - } - - public Set getAllNamedChildObjects () - { - - return new HashSet (this.getNotes ()); - - } - - public Chapter getChapter () - { - - return this.chapter; - - } - - public void setChapter (Chapter c) - { - - if ((this.chapter != null) - && - (this.chapter == c) - ) - { - - // Already set. - return; - - } - - if ((this.chapter != null) - && - (this.chapter != c) - ) - { - - // Remove this item from the existing chapter. - this.chapter.removeChapterItem (this); - - } - - this.chapter = c; - - if (this.scene == null) - { - - this.chapter.addChapterItem (this); - - } - - } - - public Scene getScene () - { - - return this.scene; - - } - - public void setScene (Scene s) - { - - this.scene = s; - - } - - public void setTextPosition (Position t) - { - - this.textPos = t; - - } - - public void setEndTextPosition (Position t) - { - - this.endTextPos = t; - - } - - public Position getTextPosition () - { - - return this.textPos; - - } - - public void setEndPosition (int p) - { - - if (p <= this.position) - { - - this.endPosition = -1; - - this.endTextPos = null; - - return; - - } - - if (p > -1) - { - - this.endPosition = p; - - } else - { - - this.endPosition = -1; - - } - - this.endTextPos = null; - - } - - public int getEndPosition () - { - - if (this.endTextPos != null) - { - - return this.endTextPos.getOffset (); - - } - - return this.endPosition; - - } - - public int getStartPosition () - { - - return this.getPosition (); - - } - - public void setPosition (int p) - { - - this.position = p; - - this.textPos = null; - - } - - public void shiftPositionBy (int p) - { - - this.setPosition (this.getPosition () + p); - - this.setEndPosition (this.getEndPosition () + p); - - } - - public int getPosition () - { - - if (this.textPos != null) - { - - return this.textPos.getOffset (); - - } - - return this.position; - - } - - public void setSummary (String s) - { - - this.setName (s); - - } - - public String getSummary () - { - - return this.getName (); - - } - -} diff --git a/src/com/quollwriter/data/DateUserConfigurableObjectTypeField.java b/src/com/quollwriter/data/DateUserConfigurableObjectTypeField.java deleted file mode 100644 index 50e2f6e3..00000000 --- a/src/com/quollwriter/data/DateUserConfigurableObjectTypeField.java +++ /dev/null @@ -1,103 +0,0 @@ -package com.quollwriter.data; - -import java.awt.Dimension; - -import java.util.Map; -import java.util.Set; -import java.util.LinkedHashSet; -import java.util.Date; - -import javax.swing.*; - -import com.toedter.calendar.*; - -import com.quollwriter.*; -import com.quollwriter.ui.*; -import com.quollwriter.ui.userobjects.*; - -public class DateUserConfigurableObjectTypeField extends UserConfigurableObjectTypeField -{ - - public static final String def = "def"; - public static final String max = "max"; - public static final String min = "min"; - - public DateUserConfigurableObjectTypeField () - { - - super (Type.date); - - } - - @Override - public boolean isSortable () - { - - return true; - - } - - @Override - public UserConfigurableObjectFieldViewEditHandler getViewEditHandler (UserConfigurableObject obj, - UserConfigurableObjectField field, - AbstractProjectViewer viewer) - { - - return new DateUserConfigurableObjectFieldViewEditHandler (this, - obj, - field, - viewer); - - } - - @Override - public UserConfigurableObjectTypeFieldConfigHandler getConfigHandler () - { - - return new DateUserConfigurableObjectTypeFieldConfigHandler (this); - - } - - public void setMaximum (Date d) - { - - this.setDefinitionValue (max, (d != null ? Environment.formatDate (d) : null)); - - } - - public Date getMaximum () - { - - return this.getDateDefinitionValue (max); - - } - - public void setMinimum (Date d) - { - - this.setDefinitionValue (min, (d != null ? Environment.formatDate (d) : null)); - - } - - public Date getMinimum () - { - - return this.getDateDefinitionValue (min); - - } - - public void setDefault (Date d) - { - - this.setDefinitionValue (def, (d != null ? Environment.formatDate (d) : null)); - - } - - public Date getDefault () - { - - return this.getDateDefinitionValue (def); - - } - -} diff --git a/src/com/quollwriter/data/FileUserConfigurableObjectTypeField.java b/src/com/quollwriter/data/FileUserConfigurableObjectTypeField.java deleted file mode 100644 index 856ce972..00000000 --- a/src/com/quollwriter/data/FileUserConfigurableObjectTypeField.java +++ /dev/null @@ -1,43 +0,0 @@ -package com.quollwriter.data; - -import java.util.Map; -import java.util.Set; -import java.util.LinkedHashSet; - -import javax.swing.*; - -import com.quollwriter.ui.*; -import com.quollwriter.ui.userobjects.*; - -public class FileUserConfigurableObjectTypeField extends UserConfigurableObjectTypeField -{ - - public FileUserConfigurableObjectTypeField () - { - - super (Type.file); - - } - - @Override - public UserConfigurableObjectFieldViewEditHandler getViewEditHandler (UserConfigurableObject obj, - UserConfigurableObjectField field, - AbstractProjectViewer viewer) - { - - return new FileUserConfigurableObjectFieldViewEditHandler (this, - obj, - field, - viewer); - - } - - @Override - public UserConfigurableObjectTypeFieldConfigHandler getConfigHandler () - { - - return new FileUserConfigurableObjectTypeFieldConfigHandler (this); - - } - -} diff --git a/src/com/quollwriter/data/ImageUserConfigurableObjectTypeField.java b/src/com/quollwriter/data/ImageUserConfigurableObjectTypeField.java deleted file mode 100644 index c0b62790..00000000 --- a/src/com/quollwriter/data/ImageUserConfigurableObjectTypeField.java +++ /dev/null @@ -1,50 +0,0 @@ -package com.quollwriter.data; - -import java.util.Map; -import java.util.Set; -import java.util.LinkedHashSet; - -import javax.swing.*; - -import com.quollwriter.ui.*; -import com.quollwriter.ui.userobjects.*; - -public class ImageUserConfigurableObjectTypeField extends UserConfigurableObjectTypeField -{ - - protected ImageUserConfigurableObjectTypeField (Type type) - { - - super (type); - - } - - public ImageUserConfigurableObjectTypeField () - { - - super (Type.image); - - } - - @Override - public UserConfigurableObjectFieldViewEditHandler getViewEditHandler (UserConfigurableObject obj, - UserConfigurableObjectField field, - AbstractProjectViewer viewer) - { - - return new ImageUserConfigurableObjectFieldViewEditHandler (this, - obj, - field, - viewer); - - } - - @Override - public UserConfigurableObjectTypeFieldConfigHandler getConfigHandler () - { - - return new ImageUserConfigurableObjectTypeFieldConfigHandler (this); - - } - -} diff --git a/src/com/quollwriter/data/MultiTextUserConfigurableObjectTypeField.java b/src/com/quollwriter/data/MultiTextUserConfigurableObjectTypeField.java deleted file mode 100644 index cea8b2ef..00000000 --- a/src/com/quollwriter/data/MultiTextUserConfigurableObjectTypeField.java +++ /dev/null @@ -1,72 +0,0 @@ -package com.quollwriter.data; - -import java.awt.Dimension; - -import java.util.Map; -import java.util.Set; -import java.util.LinkedHashSet; - -import com.quollwriter.ui.*; -import com.quollwriter.ui.userobjects.*; - -public class MultiTextUserConfigurableObjectTypeField extends UserConfigurableObjectTypeField -{ - - public MultiTextUserConfigurableObjectTypeField () - { - - super (Type.multitext); - - } - - protected MultiTextUserConfigurableObjectTypeField (Type type) - { - - super (type); - - } - - @Override - public UserConfigurableObjectFieldViewEditHandler getViewEditHandler (UserConfigurableObject obj, - UserConfigurableObjectField field, - AbstractProjectViewer viewer) - { - - return new MultiTextUserConfigurableObjectFieldViewEditHandler (this, - obj, - field, - viewer); - - } - - @Override - public UserConfigurableObjectTypeFieldConfigHandler getConfigHandler () - { - - return new MultiTextUserConfigurableObjectTypeFieldConfigHandler (this); - - } - - public void setDisplayAsBullets (boolean v) - { - - this.setDefinitionValue ("displayAsBullets", v); - - } - - public boolean isDisplayAsBullets () - { - - return this.getBooleanDefinitionValue ("displayAsBullets"); - - } - - @Override - public boolean isSearchable () - { - - return true; - - } - -} diff --git a/src/com/quollwriter/data/NamedObject.java b/src/com/quollwriter/data/NamedObject.java deleted file mode 100644 index f2a9e071..00000000 --- a/src/com/quollwriter/data/NamedObject.java +++ /dev/null @@ -1,841 +0,0 @@ -package com.quollwriter.data; - -import java.io.*; -import java.util.*; - -import com.gentlyweb.xml.*; - -import com.quollwriter.*; - -import com.quollwriter.data.comparators.*; - -import org.jdom.*; - - -public abstract class NamedObject extends DataObject -{ - - public static final String NAME = "name"; - public static final String LAST_MODIFIED = "lastModified"; - public static final String DESCRIPTION = "description"; - public static final String ALIASES = "aliases"; - public static final String TAG = "tag"; - - private String name = null; - private Date lastModified = null; - private StringWithMarkup description = null; - private Set links = new HashSet (); - private Set notes = new TreeSet (new ChapterItemSorter ()); - private String aliases = null; - private Set files = new LinkedHashSet (); - private Set tags = new LinkedHashSet (); - - public NamedObject(String objType, - String name) - { - - super (objType); - - this.name = name; - - } - - public NamedObject(String objType) - { - - super (objType); - - } - - public void merge (T other) - { - - String od = other.getDescriptionText (); - - String td = this.getDescriptionText (); - - if ((td == null) - && - (od != null) - ) - { - - this.setDescription (other.getDescription ()); - - } - - if ((td != null) - && - (od != null) - ) - { - - td = td.trim (); - od = od.trim (); - - if ((!td.equalsIgnoreCase (od)) - && - (!td.toLowerCase ().contains (od.toLowerCase ())) - ) - { - - String nd = td + "\n\n" + od; - - this.setDescription (new StringWithMarkup (nd, - this.getDescription ().getMarkup ())); - - } - - } - - Set taliases = new LinkedHashSet (this.getAliasesAsList ()); - - taliases.addAll (other.getAliasesAsList ()); - - if (taliases.size () > 0) - { - - StringBuilder b = new StringBuilder (); - - int i = 0; - - for (String a : taliases) - { - - b.append (a); - - if (i < taliases.size () - 1) - { - - b.append (","); - - } - - i++; - - } - - this.setAliases (b.toString ()); - - } - - } - - @Override - public void fillToStringProperties (Map props) - { - - super.fillToStringProperties (props); - - this.addToStringProperties (props, - "name", - this.name); - this.addToStringProperties (props, - "lastModified", - this.lastModified); - this.addToStringProperties (props, - "links", - this.links.size ()); - this.addToStringProperties (props, - "notes", - this.notes.size ()); - this.addToStringProperties (props, - "tags", - this.tags); - - } - - public synchronized void reindex () - { - - TreeSet nnotes = new TreeSet (new ChapterItemSorter ()); - - nnotes.addAll (this.notes); - - this.notes = nnotes; - - for (Note n : this.notes) - { - - n.reindex (); - - } - - } - - public boolean contains (String s) - { - - if (s == null) - { - - return false; - - } - - s = s.trim ().toLowerCase (); - - if (s.length () == 0) - { - - return false; - - } - - if (this.name.toLowerCase ().indexOf (s) != -1) - { - - return true; - - } - - if ((this.description != null) - && - (this.description.getText () != null) - ) - { - - if (this.description.getText ().toLowerCase ().indexOf (s) != -1) - { - - return true; - - } - - } - - if (this.aliases != null) - { - - if (this.aliases.toLowerCase ().indexOf (s) != -1) - { - - return true; - - } - - } - - return false; - - } - - public Note getNoteAt (int pos) - { - - for (Note n : this.notes) - { - - if (n.getPosition () == pos) - { - - return n; - - } - - } - - return null; - - } - - public Set getNotesAt (int pos) - { - - Set notes = new TreeSet (new ChapterItemSorter ()); - - for (Note n : this.notes) - { - - if (n.getPosition () == pos) - { - - notes.add (n); - - } - - } - - return notes; - - } - - public DataObject getObjectForReference (ObjectReference r) - { - - if (r.equals (this.getObjectReference ())) - { - - return this; - - } - - DataObject d = null; - - for (Note n : this.notes) - { - - d = n.getObjectForReference (r); - - if (d != null) - { - - break; - - } - - } - - return d; - - } - - public abstract Set getAllNamedChildObjects (); - - public Set getFiles () - { - - return this.files; - - } - - public void setFiles (Set files) - { - - this.files = files; - - } - - public void addFile (File f) - { - - if (this.files == null) - { - - this.files = new LinkedHashSet (); - - } - - this.files.add (f); - - } - - public void addNote (Note n) - { - - n.setObject (this); - - n.setParent (this); - - this.notes.add (n); - - } - - public void removeNote (Note n) - { - - this.notes.remove (n); - - } - - public Set getNotes () - { - - return this.notes; - - } - - public Set getAllNames () - { - - Set l = new HashSet (); - - l.add (this.name); - - l.addAll (this.getAliasesAsList ()); - - return l; - - } - - public List getAliasesAsList () - { - - List l = new ArrayList (); - - if (this.aliases != null) - { - - StringTokenizer t = new StringTokenizer (this.aliases, - ",;" + String.valueOf ('\n')); - - while (t.hasMoreTokens ()) - { - - l.add (t.nextToken ().trim ()); - - } - - } - - return l; - - } - - public String getAliases () - { - - return this.aliases; - - } - - public void setAliases (String a) - { - - String oldAliases = this.aliases; - - this.aliases = a; - - this.firePropertyChangedEvent (NamedObject.ALIASES, - oldAliases, - this.aliases); - - } - - public void clearLinks () - { - - this.links.clear (); - - } - - public void removeLink (Link l) - { - - this.links.remove (l); - - } - - public void addLink (Link l) - { - - this.links.add (l); - - } - - public Set getOtherObjectsInLinks () - { - - Set s = new TreeSet (NamedObjectSorter.getInstance ()); - - Iterator it = this.links.iterator (); - - while (it.hasNext ()) - { - - Link l = it.next (); - - s.add (l.getOtherObject (this)); - - } - - return s; - - } - - public void addLinkTo (NamedObject o) - { - - if (this == o) - { - - return; - - } - - this.addLink (new Link (this, - o)); - - } - - public Set getLinks () - { - - return this.links; - - } - - public void removeLinkFor (NamedObject n) - { - - Iterator iter = this.links.iterator (); - - while (iter.hasNext ()) - { - - Link l = iter.next (); - - if (l.getObject1 () == n) - { - - iter.remove (); - - return; - - } - - } - - } - - public void setLinks (Set l) - { - - this.links.addAll (l); - - } - - public Date getLastModified () - { - - if (this.lastModified == null) - { - - return this.getDateCreated (); - - } - - return this.lastModified; - - } - - public String getDescriptionText () - { - - if (this.description != null) - { - - return this.description.getText (); - - } - - return null; - - } - - public StringWithMarkup getDescription () - { - - return this.description; - - } - - public void setDescription (StringWithMarkup d) - { - - StringWithMarkup oldDesc = this.description; - - this.description = d; - - this.setLastModified (new Date ()); - - this.firePropertyChangedEvent (NamedObject.DESCRIPTION, - oldDesc, - this.description); - - } - - public void setName (String n) - { - - String oldName = this.name; - - this.name = n; - - this.setLastModified (new Date ()); - - this.firePropertyChangedEvent (NamedObject.NAME, - oldName, - this.name); - - } - - public String getName () - { - - return this.name; - - } - - public void setLastModified (Date d) - { - - Date oldDate = this.lastModified; - - this.lastModified = d; - - if (oldDate == null) - { - - oldDate = new Date (); - oldDate.setTime (0); - - } - - this.firePropertyChangedEvent (NamedObject.LAST_MODIFIED, - oldDate, - this.lastModified); - - } - - public abstract void getChanges (NamedObject old, - Element root); - - protected void addFieldChangeElement (Element changesEl, - String fieldName, - String oldValue, - String newValue) - { - - if (Environment.areDifferent (oldValue, - newValue)) - { - - Element fieldEl = new Element ("field"); - - changesEl.addContent (fieldEl); - - fieldEl.setAttribute ("name", - fieldName); - - Element oldEl = new Element ("old"); - Element newEl = new Element ("new"); - - oldEl.addContent ((oldValue != null) ? (oldValue + "") : (null + "")); - newEl.addContent ((newValue != null) ? (newValue + "") : (null + "")); - - fieldEl.addContent (oldEl); - fieldEl.addContent (newEl); - - } - - } - - protected void addFieldChangeElement (Element changesEl, - String fieldName, - StringWithMarkup oldValue, - StringWithMarkup newValue) - { - - String ot = (oldValue != null ? oldValue.getText () : null); - String nt = (newValue != null ? newValue.getText () : null); - - if (Environment.areDifferent (ot, - nt)) - { - - Element fieldEl = new Element ("field"); - - changesEl.addContent (fieldEl); - - fieldEl.setAttribute ("name", - fieldName); - - Element oldEl = new Element ("old"); - Element newEl = new Element ("new"); - - oldEl.addContent ((ot != null) ? (ot + "") : (null + "")); - newEl.addContent ((nt != null) ? (nt + "") : (null + "")); - - fieldEl.addContent (oldEl); - fieldEl.addContent (newEl); - - } - - } - - protected void addFieldChangeElement (Element changesEl, - String fieldName, - Date oldValue, - Date newValue) - { - - if (Environment.areDifferent (oldValue, - newValue)) - { - - Element fieldEl = new Element ("field"); - - changesEl.addContent (fieldEl); - - fieldEl.setAttribute ("name", - fieldName); - - Element oldEl = new Element ("old"); - Element newEl = new Element ("new"); - - oldEl.addContent ((oldValue != null) ? (oldValue.getTime () + "") : (null + "")); - newEl.addContent ((newValue != null) ? (newValue.getTime () + "") : (null + "")); - - fieldEl.addContent (oldEl); - fieldEl.addContent (newEl); - - } - - } - - public Element getChanges (NamedObject old) - { - - Element root = new Element ("changes"); - - this.addFieldChangeElement (root, - "name", - ((old != null) ? old.getName () : null), - this.name); - - this.addFieldChangeElement (root, - "aliases", - ((old != null) ? old.getAliases () : null), - this.aliases); - - this.addFieldChangeElement (root, - "description", - ((old != null) ? old.getDescription () : null), - this.description); - - this.getChanges (old, - root); - - if (root.getContent ().size () > 0) - { - - return root; - - } - - return null; - - } - - public void addTag (Tag t) - { - - if (t == null) - { - - return; - - } - - this.tags.add (t); - - this.updateTags (); - - this.firePropertyChangedEvent (NamedObject.TAG, - null, - t); - - } - - public void removeTag (Tag t) - { - - if (t == null) - { - - return; - - } - - this.tags.remove (t); - - this.updateTags (); - - this.firePropertyChangedEvent (NamedObject.TAG, - t, - null); - - } - - public boolean hasTag (Tag t) - { - - if (t == null) - { - - return false; - - } - - return this.tags.contains (t); - - } - - private void updateTags () - { - - Set tagKeys = new LinkedHashSet (); - - for (Tag t : this.tags) - { - - tagKeys.add (t.getKey ().toString ()); - - } - - try - { - - this.setProperty (Constants.TAGS_PROPERTY_NAME, - Utils.joinStrings (tagKeys, - ";")); - - } catch (Exception e) { - - Environment.logError ("Unable to updated tags to: " + - tagKeys + - " for: " + - this, - e); - - } - - } - - @Override - public void setPropertiesAsString (String s) - throws Exception - { - - super.setPropertiesAsString (s); - - Set tagKeys = new LinkedHashSet (Utils.splitString (this.getProperty (Constants.TAGS_PROPERTY_NAME), - ";")); - - for (String k : tagKeys) - { - - try - { - - Tag t = Environment.getTagByKey (Long.parseLong (k)); - - if (t != null) - { - - this.tags.add (t); - - } - - } catch (Exception e) { - - // Ignore. - - } - - } - - } - -} diff --git a/src/com/quollwriter/data/NumberUserConfigurableObjectTypeField.java b/src/com/quollwriter/data/NumberUserConfigurableObjectTypeField.java deleted file mode 100644 index ee8d0d9e..00000000 --- a/src/com/quollwriter/data/NumberUserConfigurableObjectTypeField.java +++ /dev/null @@ -1,91 +0,0 @@ -package com.quollwriter.data; - -import java.awt.Dimension; - -import java.util.Map; -import java.util.Set; -import java.util.LinkedHashSet; - -import java.math.*; - -import javax.swing.*; - -import com.quollwriter.*; -import com.quollwriter.ui.*; -import com.quollwriter.ui.userobjects.*; - -public class NumberUserConfigurableObjectTypeField extends UserConfigurableObjectTypeField -{ - - public static final String MAX = "max"; - public static final String MIN = "min"; - - public NumberUserConfigurableObjectTypeField () - { - - super (Type.number); - - } - - @Override - public boolean isSortable () - { - - return true; - - } - - @Override - public UserConfigurableObjectFieldViewEditHandler getViewEditHandler (UserConfigurableObject obj, - UserConfigurableObjectField field, - AbstractProjectViewer viewer) - { - - return new NumberUserConfigurableObjectFieldViewEditHandler (this, - obj, - field, - viewer); - - } - - @Override - public UserConfigurableObjectTypeFieldConfigHandler getConfigHandler () - { - - return new NumberUserConfigurableObjectTypeFieldConfigHandler (this); - - } - - public Double getMinimum () - throws GeneralException - { - - return this.getDoubleDefinitionValue (MIN); - - } - - public void setMinimum (Double v) - { - - this.setDefinitionValue (MIN, - (v != null ? Environment.formatNumber (v) : null)); - - } - - public Double getMaximum () - throws GeneralException - { - - return this.getDoubleDefinitionValue (MAX); - - } - - public void setMaximum (Double v) - { - - this.setDefinitionValue (MAX, - (v != null ? Environment.formatNumber (v) : null)); - - } - -} diff --git a/src/com/quollwriter/data/ObjectDescriptionUserConfigurableObjectTypeField.java b/src/com/quollwriter/data/ObjectDescriptionUserConfigurableObjectTypeField.java deleted file mode 100644 index aa2960e2..00000000 --- a/src/com/quollwriter/data/ObjectDescriptionUserConfigurableObjectTypeField.java +++ /dev/null @@ -1,72 +0,0 @@ -package com.quollwriter.data; - -import com.quollwriter.ui.*; -import com.quollwriter.ui.userobjects.*; - -/** - * Models a text user configurable object field. - */ -public class ObjectDescriptionUserConfigurableObjectTypeField extends MultiTextUserConfigurableObjectTypeField -{ - - public ObjectDescriptionUserConfigurableObjectTypeField () - { - - super (Type.objectdesc); - - this.setDefinitionValue ("isObjectDesc", true); - - } - - @Override - public boolean canDelete () - { - - return true; - - } - - @Override - public UserConfigurableObjectTypeFieldConfigHandler getConfigHandler () - { - - return new ObjectDescriptionUserConfigurableObjectTypeFieldConfigHandler (this); - - } - - @Override - public UserConfigurableObjectFieldViewEditHandler getViewEditHandler (UserConfigurableObject obj, - UserConfigurableObjectField field, - AbstractProjectViewer viewer) - { - - return new ObjectDescriptionUserConfigurableObjectFieldViewEditHandler (this, - obj, - field, - viewer); - - } - - @Override - public boolean isSearchable () - { - - return true; - - } - - @Override - public void setNameField (boolean v) - { - - } - - @Override - public boolean isNameField () - { - - return false; - - } - -} diff --git a/src/com/quollwriter/data/ObjectImageUserConfigurableObjectTypeField.java b/src/com/quollwriter/data/ObjectImageUserConfigurableObjectTypeField.java deleted file mode 100644 index 1f8be38c..00000000 --- a/src/com/quollwriter/data/ObjectImageUserConfigurableObjectTypeField.java +++ /dev/null @@ -1,50 +0,0 @@ -package com.quollwriter.data; - -import java.util.Map; -import java.util.Set; -import java.util.LinkedHashSet; - -import javax.swing.*; - -import com.quollwriter.ui.*; -import com.quollwriter.ui.userobjects.*; - -public class ObjectImageUserConfigurableObjectTypeField extends ImageUserConfigurableObjectTypeField -{ - - public ObjectImageUserConfigurableObjectTypeField () - { - - super (Type.objectimage); - - } - - @Override - public UserConfigurableObjectFieldViewEditHandler getViewEditHandler (UserConfigurableObject obj, - UserConfigurableObjectField field, - AbstractProjectViewer viewer) - { - - return new ObjectImageUserConfigurableObjectFieldViewEditHandler (this, - obj, - field, - viewer); - - } - - public boolean isObjectImage () - { - - return true; - - } - - @Override - public UserConfigurableObjectTypeFieldConfigHandler getConfigHandler () - { - - return new ObjectImageUserConfigurableObjectTypeFieldConfigHandler (this); - - } - -} diff --git a/src/com/quollwriter/data/ObjectNameUserConfigurableObjectTypeField.java b/src/com/quollwriter/data/ObjectNameUserConfigurableObjectTypeField.java deleted file mode 100644 index ffb3e3da..00000000 --- a/src/com/quollwriter/data/ObjectNameUserConfigurableObjectTypeField.java +++ /dev/null @@ -1,80 +0,0 @@ -package com.quollwriter.data; - -import com.quollwriter.ui.*; -import com.quollwriter.ui.userobjects.*; - -/** - * Models a text user configurable object field. - */ -public class ObjectNameUserConfigurableObjectTypeField extends UserConfigurableObjectTypeField -{ - - public ObjectNameUserConfigurableObjectTypeField () - { - - super (Type.objectname); - - } - - @Override - public boolean isSortable () - { - - return true; - - } - - @Override - public boolean canDelete () - { - - return false; - - } - - @Override - public UserConfigurableObjectTypeFieldConfigHandler getConfigHandler () - { - - return new ObjectNameUserConfigurableObjectTypeFieldConfigHandler (this); - - } - - @Override - public UserConfigurableObjectFieldViewEditHandler getViewEditHandler (UserConfigurableObject obj, - UserConfigurableObjectField field, - AbstractProjectViewer viewer) - { - - return new ObjectNameUserConfigurableObjectFieldViewEditHandler (this, - obj, - field, - viewer); - - } - - @Override - public boolean isSearchable () - { - - return true; - - } - - @Override - public void setNameField (boolean v) - { - - // Ignore. - - } - - @Override - public boolean isNameField () - { - - return true; - - } - -} diff --git a/src/com/quollwriter/data/OutlineItem.java b/src/com/quollwriter/data/OutlineItem.java deleted file mode 100644 index f68af515..00000000 --- a/src/com/quollwriter/data/OutlineItem.java +++ /dev/null @@ -1,114 +0,0 @@ -package com.quollwriter.data; - -import java.text.*; - -import com.quollwriter.*; -import com.quollwriter.text.*; - -public class OutlineItem extends ChapterItem -{ - - public static final String OBJECT_TYPE = "outlineitem"; - - // private Scene scene = null; - - public OutlineItem() - { - - super (OutlineItem.OBJECT_TYPE); - - } - - public OutlineItem(int at, - Chapter c) - { - - super (OutlineItem.OBJECT_TYPE, - at, - c); - - } - - public OutlineItem(int at, - Scene s) - { - - super (OutlineItem.OBJECT_TYPE, - at, - s.getChapter ()); - - this.scene = s; - - } - - public void getChanges (NamedObject old, - org.jdom.Element root) - { - - } - -/* - public Scene getScene () - { - - return this.scene; - - } -*/ - - public void setScene (Scene s) - { - - if (s == null) - { - - if (this.scene != null) - { - - this.scene.removeOutlineItem (this); - - } - - } - - super.setScene (s); - - this.setParent (s); - - } - - @Override - public void setDescription (StringWithMarkup d) - { - - // Legacy data check, can't control the order of calls that hibernate makes so ensure that it - // doesn't overwrite the description. - if ((this.getName () != null) && - (d == null)) - { - - return; - - } - - if (d != null) - { - - String t = d.getText (); - - TextIterator ti = new TextIterator (t); - - if (ti.getSentenceCount () > 0) - { - - this.setName (ti.getFirstSentence ().getText ()); - - } - - } - - super.setDescription (d); - - } - -} diff --git a/src/com/quollwriter/data/Project.java b/src/com/quollwriter/data/Project.java deleted file mode 100644 index 41932656..00000000 --- a/src/com/quollwriter/data/Project.java +++ /dev/null @@ -1,2160 +0,0 @@ -package com.quollwriter.data; - -import java.io.*; - -import java.util.*; - -import com.quollwriter.*; -import com.quollwriter.editors.*; -import com.quollwriter.data.editors.*; -import com.quollwriter.data.comparators.*; - -import com.quollwriter.events.*; - -import org.jdom.*; - -import com.gentlyweb.xml.*; -import com.gentlyweb.utils.*; - -public class Project extends NamedObject -{ - - public class XMLConstants - { - - public static final String projects = "projects"; - public static final String directory = "directory"; - public static final String name = "name"; - public static final String lastEdited = "lastEdited"; - public static final String encrypted = "encrypted"; - public static final String noCredentials = "noCredentials"; - public static final String type = "type"; - public static final String id = "id"; - public static final String forEditor = "forEditor"; - public static final String editDueDate = "editDueDate"; - - } - - public static final String LAST_EDITED = "lastEdited"; - public static final String PROJECT_DIRECTORY = "projectDirectory"; - public static final String BACKUP_DIRECTORY = "backupDirectory"; - - public static final String OBJECT_TYPE = "project"; - public static final String WORDCOUNTS_OBJECT_TYPE = "wordcounts"; - - // TODO: Change these to be an enum - public static final String NORMAL_PROJECT_TYPE = "normal"; - public static final String WARMUPS_PROJECT_TYPE = "warmups"; - public static final String EDITOR_PROJECT_TYPE = "editor"; - - public static final String BOOK_ADDED = "book_added"; - - private List books = new ArrayList (); - private int lastBookId = 0; - private File projectDirectory = null; - private File backupDirectory = null; - private Date lastEdited = null; - private boolean backup = false; - private boolean encrypted = false; - private String backupVersion = null; - /* - private List characters = new ArrayList (); - private List locations = new ArrayList (); - private List objects = new ArrayList (); - private List researchItems = new ArrayList (); - */ - private List ideaTypes = new ArrayList (); - private Map> assets = new HashMap (); - private String filePassword = null; - private boolean noCredentials = false; - private String type = Project.NORMAL_PROJECT_TYPE; - //private String editorsProjectId = null; - //private EditorProject editorProject = null; - - // TODO: Need a new object to encapsulate this stuff - //private EditorEditor forEditor = null; - private Set projectEditors = null; - private ProjectVersion projVer = null; - - public Project (Element pEl) - throws Exception - { - - this (); - - String name = JDOMUtils.getChildElementContent (pEl, - XMLConstants.name); - String type = JDOMUtils.getAttributeValue (pEl, - XMLConstants.type, - false); - - if (type.equals ("")) - { - - type = null; - - } - - String id = JDOMUtils.getAttributeValue (pEl, - XMLConstants.id, - false); - - if (!id.equals ("")) - { - - this.setId (id); - - } - - String directory = JDOMUtils.getChildElementContent (pEl, - XMLConstants.directory); - - boolean encrypted = JDOMUtils.getAttributeValueAsBoolean (pEl, - XMLConstants.encrypted, - false); - - boolean noCredentials = false; - - if (JDOMUtils.getAttribute (pEl, - XMLConstants.noCredentials, - false) != null) - { - - noCredentials = JDOMUtils.getAttributeValueAsBoolean (pEl, - XMLConstants.noCredentials); - - } - - String d = JDOMUtils.getAttributeValue (pEl, - XMLConstants.lastEdited, - false); - - File dir = new File (directory); - - this.setName (name); - - this.setProjectDirectory (dir); - this.setEncrypted (encrypted); - this.setNoCredentials (noCredentials); - - if (type != null) - { - - this.setType (type); - - if (this.isEditorProject ()) - { - - this.projVer = new ProjectVersion (); - - String dueDate = JDOMUtils.getAttributeValue (pEl, - XMLConstants.editDueDate, - false); - - if (!dueDate.equals ("")) - { - - // TODO: Fix this otherwise I will go to hell... - this.projVer.setDueDate (new Date (Long.parseLong (dueDate))); - - } - - String editorEmail = JDOMUtils.getChildElementContent (pEl, - XMLConstants.forEditor); - - if (editorEmail == null) - { - - throw new GeneralException ("Expected to find a child element: " + - XMLConstants.forEditor + - ", indicating who the project is being edited for."); - - } - - // Get the editor. - EditorEditor ed = EditorsEnvironment.getEditorByEmail (editorEmail); - - // If we are in debug mode then allow a null editor through. This is to allow - // testing of the send/receive cycle without having to resort to handling two - // different accounts or having per user projects.xml files. - if ((!Environment.isDebugModeEnabled ()) - && - (ed == null) - ) - { - - throw new GeneralException ("Expected to find editor with email: " + - editorEmail); - - } else { - - ed = new EditorEditor (); - ed.setKey (new Long (0)); - ed.setEmail (editorEmail); - - } - - this.setForEditor (editorEmail); - - //this.forEditor = ed; - - } - - } - - if (!d.equals ("")) - { - - try - { - - this.setLastEdited (new Date (Long.parseLong (d))); - - } catch (Exception e) - { - - // Ignore it. - - } - - } - - } - - public Project() - { - - super (Project.OBJECT_TYPE); - - } - - public Project(String name) - { - - super (Project.OBJECT_TYPE, - name); - - } - - public ProjectEditor getProjectEditor (EditorEditor ed) - { - - if (this.projectEditors == null) - { - - return null; - - } - - for (ProjectEditor pe : this.projectEditors) - { - - if (pe.getEditor () == ed) - { - - return pe; - - } - - } - - return null; - - } - - public void addProjectEditor (ProjectEditor pe) - { - - if (this.projectEditors == null) - { - - this.projectEditors = new LinkedHashSet (); - - } - - this.projectEditors.add (pe); - - } - - public void removeProjectEditor (ProjectEditor pe) - { - - if (this.projectEditors == null) - { - - return; - - } - - this.projectEditors.remove (pe); - - } - - public boolean isProjectEditor (EditorEditor ed) - { - - if (this.projectEditors == null) - { - - return false; - - } - - for (ProjectEditor pe : this.projectEditors) - { - - if (pe.getEditor () == ed) - { - - return true; - - } - - } - - return false; - - } - - public Set getProjectEditors () - { - - if (this.projectEditors == null) - { - - return null; - - } - - return new LinkedHashSet (this.projectEditors); - - } - - public void setProjectEditors (Collection eds) - { - - if (eds == null) - { - - return; - - } - - this.projectEditors = new LinkedHashSet (eds); - - } - - public void setForEditor (String editorEmail) //EditorEditor ed) - { - -/* - if ((this.forEditor != null) - && - (ed == null) - ) - { - - throw new IllegalArgumentException ("Cannot remove forEditor once it has been set."); - - } - - if ((this.forEditor != null) - && - (!this.forEditor.getEmail ().equals (ed.getEmail ())) - ) - { - - throw new IllegalArgumentException ("Cannot change the forEditor once it has been set."); - - } - - this.forEditor = ed; -*/ - try - { - - this.setProperty (Constants.FOR_EDITOR_EMAIL_PROPERTY_NAME, - editorEmail); - //this.forEditor.getEmail ()); - - } catch (Exception e) { - - // Not really the correct type of exception to throw but it shouldn't be - // checked or handled "properly" either since it should always happen, this - // is just the weird edge case when something terrible goes wrong. - throw new IllegalArgumentException ("Unable to set the for editor", - e); - - } - - } - - public String getEditResponseMessage () - { - - return this.getProperty (Constants.EDITOR_RESPONSE_MESSAGE_PROPERTY_NAME); - - } - - public void setEditResponseMessage (String m) - { - - try - { - - this.setProperty (Constants.EDITOR_RESPONSE_MESSAGE_PROPERTY_NAME, - m); - - } catch (Exception e) { - - Environment.logError ("Unable to set response message: " + - m, - e); - - } - - } - - public void setProjectVersion (ProjectVersion pv) - { - - this.projVer = pv; - - } - - public ProjectVersion getProjectVersion () - { - - return this.projVer; - - } - - public EditorEditor getForEditor () - { - - if (this.isEditorProject ()) - { - - // Get the editor email. - String edEmail = this.getProperty (Constants.FOR_EDITOR_EMAIL_PROPERTY_NAME); - - if (edEmail == null) - { - - // This is a strange situation, what to do? - return null; - - } - - return EditorsEnvironment.getEditorByEmail (edEmail); - - } - - return null; - - //return this.forEditor; - - } - - public boolean isEditorProject () - { - - return this.type.equals (Project.EDITOR_PROJECT_TYPE); - - } - - public boolean isWarmupsProject () - { - - return this.type.equals (Project.WARMUPS_PROJECT_TYPE); - - } - - public boolean isNormalProject () - { - - return this.type.equals (Project.NORMAL_PROJECT_TYPE); - - } - - public int getChapterCount () - { - - int c = 0; - - if (this.books == null) - { - - return c; - - } - - for (Book b : this.books) - { - - c += b.getChapters ().size (); - - } - - return c; - - } - - public ReadabilityIndices getAllProjectReadabilityIndices () - { - - ReadabilityIndices ri = new ReadabilityIndices (); - - if (this.books == null) - { - - return ri; - - } - - for (Book b : this.books) - { - - for (Chapter c : b.getChapters ()) - { - - ri.add (c.getChapterText ()); - } - - } - - return ri; - - } - - public int getEditedWordCount () - { - - if (this.books == null) - { - - return 0; - - } - - final StringBuilder buf = new StringBuilder (); - - int editComplete = 0; - - for (Book b : this.books) - { - - for (Chapter c : b.getChapters ()) - { - - if (c.getEditPosition () > 0) - { - - if (buf.length () > 0) - { - - buf.append (" "); - - } - - String t = c.getChapterText (); - - if (t == null) - { - - continue; - - } - - if (c.getEditPosition () <= t.length ()) - { - - buf.append (t.substring (0, - c.getEditPosition ())); - - } - - } - - } - - } - - if (buf.length () > 0) - { - - ChapterCounts allc = new ChapterCounts (buf.toString ()); - - return allc.wordCount; - - } - - return 0; - - } - - public int getWordCount () - { - - int c = 0; - - if (this.books == null) - { - - return c; - - } - - for (Book b : this.books) - { - - c += b.getChapterWordCount (); - - } - - return c; - - } - /* - public void setEditorProject (EditorProject p) - { - - this.editorProject = p; - - if (p != null) - { - - p.setProject (this); - - } - - } - - public EditorProject getEditorProject () - { - - return this.editorProject; - - } - */ - /* - public void setEditorsProjectId (String id) - { - - this.editorsProjectId = id; - - } - - public String getEditorsProjectId () - { - - return this.editorsProjectId; - - } - */ - - public String getType () - { - - return this.type; - - } - - public void setType (String t) - { - - this.type = t; - - } - - public void getChanges (NamedObject old, - Element root) - { - - } - - public NamedObject getObjectById (Class ofType, - String id) - { - - Set objs = this.getAllNamedChildObjects (ofType); - - for (NamedObject o : objs) - { - - if (o.getId ().equals (id)) - { - - return o; - - } - - } - - return null; - - } - - public static Set getObjectsContaining (String s, - Project p) - { - - Set ret = new TreeSet (NamedObjectSorter.getInstance ()); - - for (NamedObject n : p.getAllNamedChildObjects ()) - { - - if (n.contains (s)) - { - - ret.add (n); - - } - - } - - return ret; - - } - - public Set getAssetsContaining (String s) - { - - Set ret = new TreeSet (NamedObjectSorter.getInstance ()); - - for (NamedObject n : this.getAllNamedChildObjects (Asset.class)) - { - - if (n.contains (s)) - { - - ret.add ((Asset) n); - - } - - } - - return ret; - - } - - public Set getAssetsContaining (String s, - UserConfigurableObjectType limitTo) - { - - Set ret = new TreeSet (NamedObjectSorter.getInstance ()); - - if (limitTo != null) - { - - if (!limitTo.isAssetObjectType ()) - { - - return ret; - - } - - } - - for (NamedObject n : this.getAllNamedChildObjects (limitTo)) - { - - if (n.contains (s)) - { - - ret.add ((Asset) n); - - } - - } - - return ret; - - } - - public Set getNotesContaining (String s) - { - - Set ret = new TreeSet (NamedObjectSorter.getInstance ()); - - for (NamedObject n : this.getAllNamedChildObjects (Note.class)) - { - - if (n.contains (s)) - { - - ret.add ((Note) n); - - } - - } - - return ret; - - } - - public Set getOutlineItemsContaining (String s) - { - - Set ret = new TreeSet (NamedObjectSorter.getInstance ()); - - for (NamedObject n : this.getAllNamedChildObjects (OutlineItem.class)) - { - - if (n.contains (s)) - { - - ret.add ((OutlineItem) n); - - } - - } - - return ret; - - } - - public Set getScenesContaining (String s) - { - - Set ret = new TreeSet (NamedObjectSorter.getInstance ()); - - for (NamedObject n : this.getAllNamedChildObjects (Scene.class)) - { - - if (n.contains (s)) - { - - ret.add ((Scene) n); - - } - - } - - return ret; - - } - - public Set getAllObjectsWithTag (Tag tag) - { - - Set objs = this.getAllNamedChildObjects (); - - Set ret = new LinkedHashSet (); - - for (NamedObject n : objs) - { - - if (n.hasTag (tag)) - { - - ret.add (n); - - } - - } - - return ret; - - } - - public Set getAllNamedChildObjects (UserConfigurableObjectType withType) - { - - Set ret = this.getAllNamedChildObjects (); - - Iterator iter = ret.iterator (); - - while (iter.hasNext ()) - { - - NamedObject o = iter.next (); - - if (!(o instanceof UserConfigurableObject)) - { - - iter.remove (); - - continue; - - } - - UserConfigurableObject uo = (UserConfigurableObject) o; - - if (!uo.getUserConfigurableObjectType ().equals (withType)) - { - - iter.remove (); - - } - - } - - return ret; - - } - - public Set getAllNamedChildObjects (Class ofType) - { - - Set ret = this.getAllNamedChildObjects (); - - Iterator iter = ret.iterator (); - - while (iter.hasNext ()) - { - - if (!ofType.isAssignableFrom (iter.next ().getClass ())) - { - - iter.remove (); - - } - - } - - return ret; - - } - - public Set getAllNamedChildObjects () - { - - Set ret = new TreeSet (NamedObjectSorter.getInstance ()); - - for (Book b : this.books) - { - - ret.add (b); - - ret.addAll (b.getAllNamedChildObjects ()); - - } - - for (UserConfigurableObjectType t : this.assets.keySet ()) - { - - Set as = this.assets.get (t); - - for (Asset a : as) - { - - ret.add (a); - - ret.addAll (a.getAllNamedChildObjects ()); - - } - - } - - for (IdeaType it : this.ideaTypes) - { - - ret.add (it); - - ret.addAll (it.getAllNamedChildObjects ()); - - } - - return ret; - - } - - public boolean hasObject (DataObject d) - { - - if (d instanceof IdeaType) - { - - return this.getIdeaType (d.getKey ()) != null; - - } - - if (d instanceof Chapter) - { - - Chapter c = (Chapter) d; - - if (c.getBook () == null) - { - - return false; - - } - - return c.getBook ().getChapterByKey (d.getKey ()) != null; - - } - - if (d instanceof Asset) - { - - Asset a = (Asset) d; - - Set as = this.assets.get (a.getUserConfigurableObjectType ()); - - if (as != null) - { - - for (Asset _a : as) - { - - if (_a == a) - { - - return true; - - } - - } - - } - - return false; - - } - - return false; - - } - - public void removeObject (DataObject d) - { - - if (d instanceof IdeaType) - { - - this.getIdeaTypes ().remove (d); - - } - - if (d instanceof Asset) - { - - Asset a = (Asset) d; - - Set as = this.assets.get (a.getUserConfigurableObjectType ()); - - if (as != null) - { - - as.remove (a); - - } - - } - - } - - public boolean hasAsset (Asset a) - { - - return this.getAssetByName (a.getName (), - a.getUserConfigurableObjectType ()) != null; - - } - - public Set getAllNamedObjectsByName (String n) - { - - Set ret = new LinkedHashSet (); - - Set objs = this.getAllNamedChildObjects (); - - for (NamedObject o : objs) - { - - Set names = o.getAllNames (); - - for (String name : names) - { - - if (n.equalsIgnoreCase (name)) - { - - ret.add (o); - - } - - } - - } - - return ret; - - } - - public Set getAllAssetsByName (String n, - UserConfigurableObjectType type) - { - - Set assets = new LinkedHashSet (); - - if (type != null) - { - - Asset as = this.getAssetByName (n, - type); - - if (as != null) - { - - assets.add (as); - - } - - return assets; - - } - - for (UserConfigurableObjectType t : this.assets.keySet ()) - { - - Asset as = this.getAssetByName (n, - t); - - if (as != null) - { - - assets.add (as); - - } - - } - - return assets; - - } - - public Asset getAssetByName (String n, - UserConfigurableObjectType type) - { - - Set as = this.assets.get (type); - - if (as == null) - { - - return null; - - } - - for (Asset a : as) - { - - Set names = a.getAllNames (); - - for (String name : names) - { - - if (n.equalsIgnoreCase (name)) - { - - return a; - - } - - } - - } - - return null; - - } - - private Asset getAssetByName_Int (List assets, - String n) - { - - n = n.toLowerCase (); - - for (Asset a : assets) - { - - if (a.getName ().toLowerCase ().equals (n)) - { - - return a; - - } - - } - - return null; - - } - - private Set getAllAssetsByName_Int (List assets, - String n) - { - - Set matched = new LinkedHashSet (); - - n = n.toLowerCase (); - - for (Asset a : assets) - { - - if (a.getName ().equalsIgnoreCase (n)) - { - - matched.add (a); - - continue; - - } - - List aliases = a.getAliasesAsList (); - - if (aliases != null) - { - - for (String al : aliases) - { - - if (al.equalsIgnoreCase (n)) - { - - matched.add (a); - - continue; - - } - - } - - } - - } - - return matched; - - } - - public Set getAssetTypes () - { - - return this.assets.keySet (); - - } - - public Set getAssets (UserConfigurableObjectType type) - { - - return this.assets.get (type); - - } - - public Map> getAssets () - { - - return this.assets; - - } - -/* - public Set getAllCharactersByName (String n) - { - - return (Set) this.getAllAssetsByName_Int (this.characters, - n); - - } - - public Set getAllLocationsByName (String n) - { - - return (Set) this.getAllAssetsByName_Int (this.locations, - n); - - } - - public Set getAllQObjectsByName (String n) - { - - return (Set) this.getAllAssetsByName_Int (this.objects, - n); - - } - - public Set getAllResearchItemsByName (String n) - { - - return (Set) this.getAllAssetsByName_Int (this.researchItems, - n); - - } -*/ -/* - public QCharacter getCharacterByName (String n) - { - - return (QCharacter) this.getAssetByName_Int (this.characters, - n); - - } - - public Location getLocationByName (String n) - { - - return (Location) this.getAssetByName_Int (this.locations, - n); - - } - - public QObject getQObjectByName (String n) - { - - return (QObject) this.getAssetByName_Int (this.objects, - n); - - } - - public ResearchItem getResearchItemByName (String n) - { - - return (ResearchItem) this.getAssetByName_Int (this.researchItems, - n); - - } -*/ - public boolean isNoCredentials () - { - - return this.noCredentials; - - } - - public void setNoCredentials (boolean v) - { - - this.noCredentials = v; - - } - - public void setFilePassword (String p) - { - - this.filePassword = p; - - } - - public String getFilePassword () - { - - return this.filePassword; - - } - - public boolean isEncrypted () - { - - return this.encrypted; - - } - - public void setEncrypted (boolean v) - { - - this.encrypted = v; - - } - - public Date getLastEdited () - { - - return this.lastEdited; - - } - - public void setLastEdited (Date d) - { - - Date oldDate = this.lastEdited; - - this.lastEdited = d; - - this.firePropertyChangedEvent (Project.LAST_EDITED, - oldDate, - this.lastEdited); - - } - - public File getProjectDirectory () - { - - return this.projectDirectory; - - } - - public void setProjectDirectory (File dir) - { - - File oldDir = this.projectDirectory; - - this.projectDirectory = dir; - - this.firePropertyChangedEvent (Project.PROJECT_DIRECTORY, - oldDir, - this.projectDirectory); - - } - - public void saveToFilesDirectory (File file, - String fileName) - throws IOException - { - - if ((file == null) - || - (!file.exists ()) - || - (file.isDirectory ()) - ) - { - - return; - - } - - File dir = this.getFilesDirectory (); - - dir.mkdirs (); - Utils.createQuollWriterDirFile (dir); - - File f = new File (dir, - fileName); - - IOUtils.copyFile (file, - f, - 4096); - - } - - public void deleteFile (String fileName) - { - - this.getFile (fileName).delete (); - - } - - public File getFile (String fileName) - { - - return new File (this.getFilesDirectory (), - fileName); - - } - - public File getFilesDirectory () - { - - return new File (this.projectDirectory, - Constants.PROJECT_FILES_DIR_NAME); - - } - - public File getBackupDirectory () - { - - if (this.backupDirectory == null) - { - - this.backupDirectory = new File (this.projectDirectory, - "versions"); - - } - - return this.backupDirectory; - - } - - public void setBackupDirectory (File dir) - { - - File oldDir = this.backupDirectory; - - this.backupDirectory = dir; - - this.firePropertyChangedEvent (Project.BACKUP_DIRECTORY, - oldDir, - this.backupDirectory); - - } -/* - public List getCharacters () - { - - return this.characters; - - } - - public List getLocations () - { - - return this.locations; - - } - - public List getQObjects () - { - - return this.objects; - - } -*/ - public List getIdeaTypes () - { - - return this.ideaTypes; - - } - - public void addIdeaType (IdeaType it) - { - - if (this.ideaTypes.contains (it)) - { - - return; - - } - - this.ideaTypes.add (it); - - it.setProject (this); - - } - - public void addAsset (Asset a) - { - - Set as = this.assets.get (a.getUserConfigurableObjectType ()); - - if (as == null) - { - - as = new LinkedHashSet (); - - this.assets.put (a.getUserConfigurableObjectType (), - as); - - } - - a.setProject (this); - - as.add (a); - - } - - @Override - public void fillToStringProperties (Map props) - { - - super.fillToStringProperties (props); - - this.addToStringProperties (props, - "type", - this.type); - - this.addToStringProperties (props, - "projectDir", - (this.projectDirectory != null ? this.projectDirectory.getPath () : "Not set")); - this.addToStringProperties (props, - "backupDir", - (this.backupDirectory != null ? this.backupDirectory.getPath () : "Not set")); - this.addToStringProperties (props, - "filesDir", - (this.getFilesDirectory () != null ? this.getFilesDirectory ().getPath () : "Not set")); - - this.addToStringProperties (props, - "lastEdited", - this.lastEdited); - this.addToStringProperties (props, - "encrypted", - this.encrypted); - - for (UserConfigurableObjectType t : this.assets.keySet ()) - { - - Set as = this.assets.get (t); - - this.addToStringProperties (props, - t.getObjectTypeId (), - as.size ()); - - } - - this.addToStringProperties (props, - "ideaTypes", - this.ideaTypes.size ()); - - EditorEditor ed = this.getForEditor (); - - if (ed != null) - { - - this.addToStringProperties (props, - "forEditor", - ed.getEmail ()); - - } - - if (this.projectEditors != null) - { - - this.addToStringProperties (props, - "projectEditors", - this.projectEditors.size ()); - - } - - this.addToStringProperties (props, - "projectVersion", - this.projVer); - - } - - public int getBookIndex (Book b) - { - - return this.books.indexOf (b) + 1; - - } - - public List getBooks () - { - - return this.books; - - } - - public Chapter getChapterByKey (long k) - { - - for (Book b : this.books) - { - - Chapter c = b.getChapterByKey (k); - - if (c != null) - { - - return c; - - } - - } - - return null; - - } - - public Book getBook (int i) - { - - return (Book) this.books.get (i); - - } -/* - public QCharacter getCharacter (Long key) - { - - for (QCharacter c : this.characters) - { - - if (c.getKey ().equals (key)) - { - - return c; - - } - - } - - return null; - - } - */ -/* - public ResearchItem getResearchItem (Long key) - { - - for (ResearchItem r : this.researchItems) - { - - if (r.getKey ().equals (key)) - { - - return r; - - } - - } - - return null; - - } -*/ - public IdeaType getIdeaType (Long key) - { - - for (IdeaType i : this.ideaTypes) - { - - if (i.getKey () == key) - { - - return i; - - } - - } - - return null; - - } - /* - public QObject getQObject (Long key) - { - - for (QObject o : this.objects) - { - - if (o.getKey ().equals (key)) - { - - return o; - - } - - } - - return null; - - } - */ -/* - public Location getLocation (Long key) - { - - - for (Location l : this.locations) - { - - if (l.getKey ().equals (key)) - { - - return l; - - } - - } - - return null; - - } -*/ - public Book getBook (Long key) - { - - for (Book b : this.books) - { - - if (b.getKey ().equals (key)) - { - - return b; - - } - - } - - return null; - - } - - public DataObject getObjectForReference (ObjectReference r) - { - - if (r == null) - { - - return null; - - } - - DataObject d = super.getObjectForReference (r); - - if (d != null) - { - - return d; - - } - /* - if (r.getObjectType ().equals (Project.WORDCOUNTS_OBJECT_TYPE)) - { - - WordCount w = new WordCount (); - w.setKey (r.getKey ()); - w.setObjectType (Project.WORDCOUNTS_OBJECT_TYPE); - - return w; - - } - */ - - if (r.getObjectType ().equals (Chapter.INFORMATION_OBJECT_TYPE)) - { - - r = new ObjectReference (Chapter.OBJECT_TYPE, - r.getKey (), - null); - - } - - for (UserConfigurableObjectType t : this.assets.keySet ()) - { - - Set as = this.assets.get (t); - - for (Asset a : as) - { - - d = a.getObjectForReference (r); - - if (d != null) - { - - return d; - - } - - } - - } - /* - for (QCharacter c : this.characters) - { - - d = c.getObjectForReference (r); - - if (d != null) - { - - return d; - - } - - } - - for (Location l : this.locations) - { - - d = l.getObjectForReference (r); - - if (d != null) - { - - return d; - - } - - } - - for (QObject q : this.objects) - { - - d = q.getObjectForReference (r); - - if (d != null) - { - - return d; - - } - - } - - for (ResearchItem i : this.researchItems) - { - - d = i.getObjectForReference (r); - - if (d != null) - { - - return d; - - } - - } -*/ - for (Book b : this.books) - { - - d = b.getObjectForReference (r); - - if (d != null) - { - - return d; - - } - - } - - for (IdeaType it : this.ideaTypes) - { - - d = it.getObjectForReference (r); - - if (d != null) - { - - return d; - - } - - } - - return null; - - } - - public void addBook (Book b) - { - - if (this.books.contains (b)) - { - - return; - - } - - b.setProject (this); - - this.books.add (b); - - this.firePropertyChangedEvent (Project.BOOK_ADDED, - null, - b); - - } - - public int hashCode () - { - - int hash = 7; - hash = (31 * hash) + ((null == this.projectDirectory) ? 0 : this.projectDirectory.hashCode ()); - - return hash; - - } - - public boolean equals (Object o) - { - - if (o == null) - { - - return false; - - } - - if (!(o instanceof Project)) - { - - return false; - - } - - Project po = (Project) o; - - if (this.projectDirectory == null) - { - - return false; - - } - - return this.projectDirectory.equals (po.projectDirectory); - - } - - public Element getAsJDOMElement () - { - - Element pEl = new Element (Project.OBJECT_TYPE); - - Element nEl = new Element (Environment.XMLConstants.name); - pEl.addContent (nEl); - nEl.addContent (this.getName ()); - - if (this.getType () == null) - { - - this.setType (Project.NORMAL_PROJECT_TYPE); - - } - - pEl.setAttribute (XMLConstants.type, - this.getType ()); - - if (this.getId () != null) - { - - pEl.setAttribute (XMLConstants.id, - this.getId ()); - - } - - Element dEl = new Element (XMLConstants.directory); - pEl.addContent (dEl); - dEl.addContent (this.getProjectDirectory ().getPath ()); - - EditorEditor ed = this.getForEditor (); - - if (ed != null) - { - - Element fEl = new Element (XMLConstants.forEditor); - pEl.addContent (fEl); - fEl.addContent (ed.getEmail ()); - - } - - if ((this.isEditorProject ()) - && - (this.projVer != null) - ) - { - - Date d = this.projVer.getDueDate (); - - if (d != null) - { - - pEl.setAttribute (XMLConstants.editDueDate, - d.getTime () + ""); - - } - - } - - Date lastEdited = this.getLastEdited (); - - if (lastEdited != null) - { - - pEl.setAttribute (XMLConstants.lastEdited, - String.valueOf (lastEdited.getTime ())); - - } - - pEl.setAttribute (XMLConstants.encrypted, - Boolean.valueOf (this.isEncrypted ()).toString ()); - - if (this.isNoCredentials ()) - { - - pEl.setAttribute (XMLConstants.noCredentials, - Boolean.valueOf (this.isNoCredentials ()).toString ()); - - } -/* - if (this.editorsProjectId != null) - { - - pEl.setAttribute (XMLConstants.editorsProjectId, - this.editorsProjectId); - - } - */ - return pEl; - - } - - public String getLanguageCodeForSpellCheckLanguage () - { - - String lang = this.getProperty (Constants.SPELL_CHECK_LANGUAGE_PROPERTY_NAME); - - if (lang == null) - { - - lang = "en"; - - return lang; - - } - - if (lang.equals ("English")) - { - - lang = "en"; - - } - - if (lang.equals ("Czech")) - { - - lang = "cs"; - - } - - if (lang.equals ("Dutch")) - { - - lang = "nl"; - - } - - if (lang.equals ("French")) - { - - lang = "fr"; - - } - - if (lang.equals ("German")) - { - - lang = "de"; - - } - - if (lang.equals ("Italian")) - { - - lang = "it"; - - } - - if (lang.equals ("Polish")) - { - - lang = "pl"; - - } - - if (lang.equals ("Russian")) - { - - lang = "ru"; - - } - - if (lang.equals ("Spanish")) - { - - lang = "es"; - - } - - return lang; - - } - -} diff --git a/src/com/quollwriter/data/ProjectInfo.java b/src/com/quollwriter/data/ProjectInfo.java deleted file mode 100644 index 9dc06d1e..00000000 --- a/src/com/quollwriter/data/ProjectInfo.java +++ /dev/null @@ -1,516 +0,0 @@ -package com.quollwriter.data; - -import java.io.*; -import java.util.*; - -import org.jdom.*; - -import com.quollwriter.events.*; -import com.quollwriter.*; -import com.quollwriter.data.editors.*; - -public class ProjectInfo extends NamedObject implements PropertyChangedListener -{ - - public enum Statistic - { - - wordCount ("wordCount"), - chapterCount ("chapterCount"), - gunningFogIndex ("gunningFogIndex"), - fleschReadingEase ("fleschReadingEase"), - fleschKincaidGradeLevel ("fleschKincaidGradeLevel"), - editedWordCount ("editedWordCount"); - - private String type = null; - - Statistic (String type) - { - - this.type = type; - - } - - public String getType () - { - - return this.type; - - } - - } - - public static final String OBJECT_TYPE = "projectinfo"; - - private EditorEditor forEditor = null; - private File projectDirectory = null; - private Date lastEdited = null; - private boolean noCredentials = false; - private String type = Project.NORMAL_PROJECT_TYPE; - private String status = null; - private File icon = null; - private File backupDirectory = null; - private File filesDirectory = null; - private Map statistics = new HashMap (); - private boolean encrypted = false; - private Project project = null; - private String filePassword = null; - private boolean opening = false; - - public ProjectInfo () - { - - super (OBJECT_TYPE); - - } - - public ProjectInfo (Project from) - { - - this (); - - this.type = from.getType (); - - this.project = from; - - this.encrypted = from.isEncrypted (); - this.noCredentials = from.isNoCredentials (); - this.lastEdited = from.getLastEdited (); - this.setId (from.getId ()); - this.forEditor = from.getForEditor (); - this.filePassword = from.getFilePassword (); - - this.update (); - - this.project.addPropertyChangedListener (this); - - } - - public synchronized void setOpening (boolean v) - { - - this.opening = v; - - } - - public synchronized boolean isOpening () - { - - if (this.opening) - { - - if (Environment.getProjectViewer (this.project) != null) - { - - this.opening = false; - - } - - } - - return this.opening; - - } - - @Override - public void fillToStringProperties (Map props) - { - - super.fillToStringProperties (props); - - this.addToStringProperties (props, - "type", - this.type); - this.addToStringProperties (props, - "status", - this.status); - this.addToStringProperties (props, - "icon", - (this.icon != null ? this.icon.getPath () : "Not set")); - - this.addToStringProperties (props, - "projectDir", - (this.projectDirectory != null ? this.projectDirectory.getPath () : "Not set")); - this.addToStringProperties (props, - "backupDir", - (this.backupDirectory != null ? this.backupDirectory.getPath () : "Not set")); - this.addToStringProperties (props, - "filesDir", - (this.filesDirectory != null ? this.filesDirectory.getPath () : "Not set")); - this.addToStringProperties (props, - "lastEdited", - this.lastEdited); - this.addToStringProperties (props, - "encrypted", - this.encrypted); - this.addToStringProperties (props, - "noCredentials", - this.noCredentials); - - if (this.forEditor != null) - { - - this.addToStringProperties (props, - "forEditor", - this.forEditor.getEmail ()); - - } - - this.addToStringProperties (props, - "statistics", - this.statistics); - - } - - public Map getStatistics () - { - - return this.statistics; - - } - - public void setStatistics (Map stats) - { - - this.statistics = stats; - - } - - @Override - public void propertyChanged (PropertyChangedEvent ev) - { - - this.update (); - - try - { - - Environment.updateProjectInfo (this); - - } catch (Exception e) { - - Environment.logError ("Unable to update project info for project: " + - this.project, - e); - - } - - } - - public void setProject (Project p) - { - - if (!p.getId ().equals (this.getId ())) - { - - throw new IllegalArgumentException ("Project does not have same id as this project info."); - - } - - if (this.project != null) - { - - this.project.removePropertyChangedListener (this); - - } - - this.project = p; - - this.filePassword = p.getFilePassword (); - - this.update (); - - this.project.addPropertyChangedListener (this); - - } - - public String getFilePassword () - { - - return this.filePassword; - - } - - public void setFilePassword (String p) - { - - this.filePassword = p; - - } - - private void update () - { - - this.setProjectDirectory (this.project.getProjectDirectory ()); - this.setBackupDirectory (this.project.getBackupDirectory ()); - this.setFilesDirectory (this.project.getFilesDirectory ()); - this.setName (this.project.getName ()); - this.setLastEdited (this.project.getLastEdited ()); - - ReadabilityIndices ri = this.project.getAllProjectReadabilityIndices (); - - this.addStatistic (Statistic.chapterCount, - this.project.getChapterCount ()); - this.addStatistic (Statistic.wordCount, - ri.getWordCount ()); - - this.addStatistic (Statistic.gunningFogIndex, - ri.getGunningFogIndex ()); - this.addStatistic (Statistic.fleschReadingEase, - ri.getFleschReadingEase ()); - this.addStatistic (Statistic.fleschKincaidGradeLevel, - ri.getFleschKincaidGradeLevel ()); - this.addStatistic (Statistic.editedWordCount, - this.project.getEditedWordCount ()); - - } - - public void addStatistic (Statistic s, - Object value) - { - - this.statistics.put (s, - value); - - } - - private int getNumberStatistic (Statistic s) - { - - Object o = this.statistics.get (s); - - if (o == null) - { - - return 0; - - } - - if (!(o instanceof Number)) - { - - return 0; - - } - - return ((Number) o).intValue (); - - } - - public int getEditedWordCount () - { - - return this.getNumberStatistic (Statistic.editedWordCount); - - } - - public int getFleschKincaidGradeLevel () - { - - return this.getNumberStatistic (Statistic.fleschKincaidGradeLevel); - - } - - public int getFleschReadingEase () - { - - return this.getNumberStatistic (Statistic.fleschReadingEase); - - } - - public int getGunningFogIndex () - { - - return this.getNumberStatistic (Statistic.gunningFogIndex); - - } - - public int getChapterCount () - { - - return this.getNumberStatistic (Statistic.chapterCount); - - } - - public int getWordCount () - { - - return this.getNumberStatistic (Statistic.wordCount); - - } - - public Set getAllNamedChildObjects () - { - - return new TreeSet (); - - } - - public void getChanges (NamedObject old, - Element root) - { - - } - - public String getStatus () - { - - return this.status; - - } - - public void setStatus (String s) - { - - this.status = s; - - } - - public void setIcon (File ic) - { - - this.icon = ic; - - } - - public File getIcon () - { - - return this.icon; - - } - - public boolean isNoCredentials () - { - - return this.noCredentials; - - } - - public void setNoCredentials (boolean v) - { - - this.noCredentials = v; - - } - - public boolean isEncrypted () - { - - return this.encrypted; - - } - - public void setEncrypted (boolean v) - { - - this.encrypted = v; - - } - - public String getType () - { - - return this.type; - - } - - public void setType (String t) - { - - this.type = t; - - } - - public void setLastEdited (Date d) - { - - this.lastEdited = d; - - } - - public Date getLastEdited () - { - - return this.lastEdited; - - } - - public void setProjectDirectory (File f) - { - - this.projectDirectory = f; - - } - - public File getProjectDirectory () - { - - return this.projectDirectory; - - } - - public File getBackupDirectory () - { - - return this.backupDirectory; - - } - - public void setBackupDirectory (File f) - { - - this.backupDirectory = f; - - } - - public File getFilesDirectory () - { - - return this.filesDirectory; - - } - - public void setFilesDirectory (File f) - { - - this.filesDirectory = f; - - } - - public void setForEditor (EditorEditor ed) - { - - this.forEditor = ed; - - } - - public EditorEditor getForEditor () - { - - return this.forEditor; - - } - - public boolean isEditorProject () - { - - return this.type.equals (Project.EDITOR_PROJECT_TYPE); - - } - - public boolean isWarmupsProject () - { - - return this.type.equals (Project.WARMUPS_PROJECT_TYPE); - - } - - public boolean isNormalProject () - { - - return this.type.equals (Project.NORMAL_PROJECT_TYPE); - - } - -} \ No newline at end of file diff --git a/src/com/quollwriter/data/Prompt.java b/src/com/quollwriter/data/Prompt.java deleted file mode 100644 index b2de3099..00000000 --- a/src/com/quollwriter/data/Prompt.java +++ /dev/null @@ -1,237 +0,0 @@ -package com.quollwriter.data; - -import com.gentlyweb.xml.*; - -import org.jdom.*; - - -public class Prompt -{ - - public static final String USER_PROMPT_ID_PREFIX = "user-"; - - public class XMLConstants - { - - public static final String root = "prompt"; - public static final String id = "id"; - public static final String text = "text"; - public static final String author = "author"; - public static final String url = "url"; - public static final String storyName = "storyName"; - - } - - private String id = null; - private String text = null; - private String author = null; - private String url = null; - private String storyName = null; - - public Prompt(String text) - { - - this.text = text; - this.id = Prompt.USER_PROMPT_ID_PREFIX + System.currentTimeMillis (); - - } - - public Prompt(String id, - String author, - String storyName, - String url, - String text) - { - - this.id = id; - this.author = author; - this.url = url; - this.text = text; - this.storyName = storyName; - - } - - public Prompt(Element root) - throws JDOMException - { - - this.id = JDOMUtils.getAttributeValue (root, - XMLConstants.id, - false); - - if (this.id.equals ("")) - { - - this.id = null; - - } - - this.text = JDOMUtils.getChildElementContent (root, - XMLConstants.text); - this.author = JDOMUtils.getChildElementContent (root, - XMLConstants.author, - false); - - if (this.author.equals ("")) - { - - this.author = null; - - } - - this.storyName = JDOMUtils.getChildElementContent (root, - XMLConstants.storyName, - false); - - if (this.storyName.equals ("")) - { - - this.storyName = null; - - } - - this.url = JDOMUtils.getChildElementContent (root, - XMLConstants.url, - false); - - if (this.url.equals ("")) - { - - this.url = null; - - } - - } - - public String toString () - { - - return "prompt(id: " + this.id + ", author: " + author + ", " + url + ", storyName: " + this.storyName + ")"; - - } - - public boolean isUserPrompt () - { - - return Prompt.isUserPrompt (this.id); - - } - - public static boolean isUserPrompt (String id) - { - - return id.startsWith (Prompt.USER_PROMPT_ID_PREFIX); - - } - - public Element getAsElement () - { - - Element root = new Element (XMLConstants.root); - - if (this.id != null) - { - - root.setAttribute (XMLConstants.id, - this.id); - - } - - if (this.author != null) - { - - Element auth = new Element (XMLConstants.author); - root.addContent (auth); - auth.addContent (this.author); - - } - - if (this.storyName != null) - { - - Element st = new Element (XMLConstants.storyName); - root.addContent (st); - st.addContent (this.storyName); - - } - - if (this.url != null) - { - - Element url = new Element (XMLConstants.url); - root.addContent (url); - url.addContent (this.url); - - } - - Element text = new Element (XMLConstants.text); - root.addContent (text); - text.addContent (this.text); - - return root; - - } - - public void setAuthor (String a) - { - - this.author = a; - - } - - public void setURL (String u) - { - - this.url = u; - - } - - public void setStoryName (String n) - { - - this.storyName = n; - - } - - public String getURL () - { - - return this.url; - - } - - public String getAuthor () - { - - return this.author; - - } - - public String getStoryName () - { - - return this.storyName; - - } - - public void setText (String t) - { - - this.text = t; - - } - - public String getText () - { - - return this.text; - - } - - public String getId () - { - - return this.id; - - } -} diff --git a/src/com/quollwriter/data/PromptWebsite.java b/src/com/quollwriter/data/PromptWebsite.java deleted file mode 100644 index 24b538eb..00000000 --- a/src/com/quollwriter/data/PromptWebsite.java +++ /dev/null @@ -1,59 +0,0 @@ -package com.quollwriter.data; - -import com.gentlyweb.xml.*; - -import org.jdom.*; - - -public class PromptWebsite -{ - - public class XMLConstants - { - - public static final String root = "site"; - public static final String count = "count"; - public static final String name = "name"; - public static final String url = "url"; - - } - - private String count = null; - private String name = null; - private String url = null; - - public PromptWebsite(Element root) - throws JDOMException - { - - this.count = JDOMUtils.getAttributeValue (root, - XMLConstants.count); - this.name = JDOMUtils.getAttributeValue (root, - XMLConstants.name); - this.url = JDOMUtils.getChildElementContent (root, - XMLConstants.url); - - } - - public String getURL () - { - - return this.url; - - } - - public String getCount () - { - - return this.count; - - } - - public String getName () - { - - return this.name; - - } - -} diff --git a/src/com/quollwriter/data/Prompts.java b/src/com/quollwriter/data/Prompts.java deleted file mode 100644 index 76724304..00000000 --- a/src/com/quollwriter/data/Prompts.java +++ /dev/null @@ -1,391 +0,0 @@ -package com.quollwriter.data; - -import java.io.*; - -import java.util.*; - -import com.gentlyweb.utils.*; - -import com.gentlyweb.xml.*; - -import com.quollwriter.*; - -import org.jdom.*; - - -public class Prompts -{ - - private static Map excludes = new HashMap (); - private static List promptIds = new ArrayList (); - private static int pos = 0; - - public class XMLConstants - { - - public static final String root = "prompts"; - - } - - public static void init () - throws Exception - { - - // Get the exclude list. - File f = new File (Environment.getUserQuollWriterDir ().getPath () + "/" + Constants.PROMPTS_EXCLUDE_FILE); - - if (f.exists ()) - { - - BufferedReader b = new BufferedReader (new FileReader (f)); - - try - { - - String l = b.readLine (); - - while (l != null) - { - - Prompts.excludes.put (l.trim (), - ""); - - l = b.readLine (); - - } - - } finally - { - - b.close (); - - } - - } - - // Get the default prompts file. - BufferedReader b = new BufferedReader (new InputStreamReader (Environment.getResourceStream (Constants.DEFAULT_PROMPT_IDS_FILE))); - - try - { - - String l = null; - - while ((l = b.readLine ()) != null) - { - - String id = l.trim (); - - if (Prompts.excludes.containsKey (id)) - { - - continue; - - } - - Prompts.promptIds.add (id); - - } - - } finally - { - - b.close (); - - } - - // Load the user prompts. - f = new File (Environment.getUserQuollWriterDir ().getPath () + "/" + Constants.USER_PROMPTS_DIR); - - if ((f.exists ()) && - (f.isDirectory ())) - { - - File[] files = f.listFiles (); - - if (files != null) - { - - for (int i = 0; i < files.length; i++) - { - - if ((files[i].isFile ()) && - (files[i].getName ().endsWith (".txt"))) - { - - String id = files[i].getName ().substring (0, - files[i].getName ().length () - 4); - - if (Prompts.excludes.containsKey (id)) - { - - continue; - - } - - // This is one, use the name as the id. - Prompts.promptIds.add (id); - - } - - } - - } - - } - - } - - public static void shuffle () - { - - Collections.shuffle (Prompts.promptIds); - - } - - public static Prompt getPromptById (String id) - throws Exception - { - - if (id == null) - { - - return null; - - } - - Element root = null; - - if (Prompt.isUserPrompt (id)) - { - - File f = new File (Environment.getUserQuollWriterDir ().getPath () + "/" + Constants.USER_PROMPTS_DIR + id + ".txt"); - - if (f == null) - { - - return null; - - } - - root = JDOMUtils.getFileAsElement (f, - ".gz"); - - } else - { - - String xml = Environment.getResourceFileAsString (Constants.PROMPTS_DIR + id + ".txt"); - - if (xml == null) - { - - Environment.logError ("Unable to get prompt from resource file: " + - Constants.PROMPTS_DIR + id + ".txt"); - - return null; - - } - - root = JDOMUtils.getStringAsElement (xml); - - } - - Prompt p = new Prompt (root); - - return p; - - } - - public static Prompt addUserPrompt (String text) - throws Exception - { - - // Add a new one. - Prompt p = new Prompt (text); - - // Get the prompts file. - File f = new File (Environment.getUserQuollWriterDir ().getPath () + "/" + Constants.USER_PROMPTS_DIR + p.getId () + ".txt"); - - f.getParentFile ().mkdirs (); - - if (f.exists ()) - { - - throw new GeneralException ("A user prompt with id: " + - p.getId () + - " already exists at: " + - f); - - } - - JDOMUtils.writeElementToFile (p.getAsElement (), - f, - true); - - return p; - - } - - public static Prompt previous () - { - - try - { - - Prompts.pos--; - - if (Prompts.pos < 0) - { - - Prompts.pos = Prompts.promptIds.size () - 1; - - } - - return Prompts.current (); - - } catch (Exception e) - { - - return null; - - } - - } - - public static Prompt next () - { - - try - { - - Prompts.pos++; - - if (Prompts.pos >= Prompts.promptIds.size ()) - { - - Prompts.pos = 0; - - } - - return Prompts.current (); - - } catch (Exception e) - { - Environment.logError ("Unable to get prompt: " + Prompts.getCurrentId (), - e); - - return null; - - } - - } - - public static Prompt current () - throws Exception - { - - String id = Prompts.getCurrentId (); - - return Prompts.getPromptById (id); - - } - - public static String getCurrentId () - { - - return Prompts.promptIds.get (Prompts.pos); - - } - - public static void excludeCurrent () - { - - Prompts.excludes.put (Prompts.getCurrentId (), - ""); - - Prompts.promptIds.remove (Prompts.getCurrentId ()); - - // Write out the exclude list. - File f = new File (Environment.getUserQuollWriterDir ().getPath () + "/" + Constants.PROMPTS_EXCLUDE_FILE); - - try - { - - PrintWriter pw = new PrintWriter (new FileWriter (f)); - - Iterator iter = Prompts.excludes.keySet ().iterator (); - - while (iter.hasNext ()) - { - - String id = (String) iter.next (); - - pw.println (id); - - } - - pw.flush (); - pw.close (); - - } catch (Exception e) - { - - Environment.logError ("Unable to save prompts exclude file to: " + - f, - e); - - } - - } - - public static List getPromptWebsites () - { - - List ws = new ArrayList (); - - try - { - - String xml = Environment.getResourceFileAsString (Constants.PROMPT_WEBSITES_FILE); - - Element root = JDOMUtils.getStringAsElement (xml); - - List els = JDOMUtils.getChildElements (root, - PromptWebsite.XMLConstants.root, - false); - - for (int i = 0; i < els.size (); i++) - { - - Element el = (Element) els.get (i); - - try - { - - PromptWebsite w = new PromptWebsite (el); - - ws.add (w); - - } catch (Exception e) - { - - Environment.logError ("Unable to load prompt website: " + - JDOMUtils.getPath (el), - e); - - } - - } - - } catch (Exception e) - { - - Environment.logError ("Unable to load prompt websites", - e); - - } - - return ws; - - } -} diff --git a/src/com/quollwriter/data/ReadabilityIndices.java b/src/com/quollwriter/data/ReadabilityIndices.java deleted file mode 100644 index 54de840a..00000000 --- a/src/com/quollwriter/data/ReadabilityIndices.java +++ /dev/null @@ -1,153 +0,0 @@ -package com.quollwriter.data; - -import java.text.*; - -import java.util.*; - -import com.quollwriter.*; - -import com.quollwriter.text.*; - - -public class ReadabilityIndices -{ - - public float syllableCount = 0; - public float wordCount = 0; - public float sentenceCount = 0; - public float threeSyllableWordCount = 0; - - public void add (ReadabilityIndices ri) - { - - this.sentenceCount += ri.sentenceCount; - this.wordCount += ri.wordCount; - this.syllableCount += ri.syllableCount; - this.threeSyllableWordCount += ri.threeSyllableWordCount; - - } - - public void add (String str) - { - - if (str == null) - { - - return; - - } - - if (str.length () == 0) - { - - return; - - } - - TextIterator ti = new TextIterator (str); - this.wordCount += ti.getWordCount (); - this.syllableCount += ti.getSyllableCount (); - this.threeSyllableWordCount += ti.getThreeSyllableWordCount (); - this.sentenceCount += ti.getSentenceCount (); - -/* - SentenceIterator si = new SentenceIterator (str); - - String s = si.next (); - - while (s != null) - { - - this.sentenceCount++; - - List words = null; - - words = TextUtilities.getAsWords (s); - - words = TextUtilities.stripPunctuation (words); - - this.wordCount += words.size (); - - for (String w : words) - { - - int cc = TextUtilities.getSyllableCountForWord (w); - - if (cc > 2) - { - - this.threeSyllableWordCount++; - - } - - this.syllableCount += cc; - - } - - s = si.next (); - - } - - // Turn off the cache, it may have used quite a bit of memory. - // Shouldn't be needed anymore. - //Environment.setSynonymProviderUseCache (true); - */ - } - - public int getSentenceCount () - { - - return (int) this.sentenceCount; - - } - - public int getWordCount () - { - - return (int) this.wordCount; - - } - - public float getFleschKincaidGradeLevel () - { - - if (this.wordCount <= 0) - { - - return 0; - - } - - return (0.39f * (this.wordCount / this.sentenceCount)) + (11.8f * (this.syllableCount / this.wordCount)) - 15.59f; - - } - - public float getFleschReadingEase () - { - - if (this.wordCount <= 0) - { - - return 0; - - } - - return (206.835f - (1.015f * (this.wordCount / this.sentenceCount)) - (84.6f * (this.syllableCount / this.wordCount))); - - } - - public float getGunningFogIndex () - { - - if (this.wordCount <= 0) - { - - return 0; - - } - - return (0.4f * ((this.wordCount / this.sentenceCount) + ((this.threeSyllableWordCount / this.wordCount) * 100f))) - 0.5f; - - } - -} diff --git a/src/com/quollwriter/data/Scene.java b/src/com/quollwriter/data/Scene.java deleted file mode 100644 index 5d679ce1..00000000 --- a/src/com/quollwriter/data/Scene.java +++ /dev/null @@ -1,284 +0,0 @@ -package com.quollwriter.data; - -import java.text.*; - -import java.util.*; - -import com.quollwriter.data.comparators.*; - -import com.quollwriter.*; -import com.quollwriter.text.*; - -public class Scene extends ChapterItem -{ - - public static final String OBJECT_TYPE = "scene"; - - private Set outlineItems = new HashSet (); - - public Scene() - { - - super (Scene.OBJECT_TYPE); - - } - - public Scene(int at, - Chapter c) - { - - super (Scene.OBJECT_TYPE, - at, - c); - - } - - @Override - public void fillToStringProperties (Map props) - { - - super.fillToStringProperties (props); - - this.addToStringProperties (props, - "outlineItems", - this.outlineItems.size ()); - - } - - public Set getChapterItemsWithPositionGreaterThan (int pos) - { - - Set items = new TreeSet (new ChapterItemSorter ()); - - for (OutlineItem it : this.outlineItems) - { - - if (it.getPosition () > pos) - { - - items.add (it); - - } - - } - - return items; - - } - - public void getChanges (NamedObject old, - org.jdom.Element root) - { - - } - - public List getOutlineItemsAt (int pos) - { - - List its = new ArrayList (); - - for (OutlineItem it : this.getOutlineItems ()) - { - - if (it.getPosition () == pos) - { - - its.add (it); - - } - - } - - return its; - - } - - public OutlineItem getOutlineItemAt (int pos) - { - - for (OutlineItem it : this.outlineItems) - { - - if (it.getPosition () == pos) - { - - return it; - - } - - } - - return null; - - } - - public DataObject getObjectForReference (ObjectReference r) - { - - DataObject d = super.getObjectForReference (r); - - if (d != null) - { - - return d; - - } - - for (OutlineItem i : this.outlineItems) - { - - d = i.getObjectForReference (r); - - if (d != null) - { - - return d; - - } - - } - - return null; - - } - - public Set getOutlineItems () - { - - TreeSet t = new TreeSet (new ChapterItemSorter ()); - - t.addAll (this.outlineItems); - - return t; - - //return new TreeSet (this.outlineItems); - - } - - public void setChapter (Chapter c) - { - - // Handle our outline items first. - for (OutlineItem it : this.outlineItems) - { - - it.setChapter (c); - - } - - super.setChapter (c); - - this.setParent (c); - - } - - public void removeOutlineItem (OutlineItem i) - { - - this.outlineItems.remove (i); - - } - - public void addOutlineItem (OutlineItem i) - { - - if (this.outlineItems.contains (i)) - { - - return; - - } - - Scene s = i.getScene (); - - if (s != null) - { - - if (s != this) - { - - s.removeOutlineItem (i); - - } - - } else - { - - this.getChapter ().removeOutlineItem (i); - - } - - i.setScene (this); - - i.setChapter (this.getChapter ()); - - this.outlineItems.add (i); - - } - - public void setDescription (StringWithMarkup d) - { - - // Legacy data check, can't control the order of calls that hibernate makes so ensure that it - // doesn't overwrite the description. - if ((this.getName () != null) && - (d == null)) - { - - return; - - } - - if (d != null) - { - - String t = d.getText (); - - // Take the first sentence and use that as the "name". - Paragraph p = new Paragraph (t, - 0); - - if (p.getSentenceCount () > 0) - { - - this.setName (p.getFirstSentence ().getText ()); - - } - - } - - super.setDescription (d); - - } - - public void shiftPositionBy (int p) - { - - super.shiftPositionBy (p); - - for (OutlineItem i : this.getOutlineItems ()) - { - - i.shiftPositionBy (p); - - } - - } - - public int getLength () - { - - Scene next = this.getChapter ().getNextScene (this); - - if (next != this) - { - - return next.getPosition () - this.getPosition (); - - } - - return -1; - - } - -} diff --git a/src/com/quollwriter/data/SelectUserConfigurableObjectTypeField.java b/src/com/quollwriter/data/SelectUserConfigurableObjectTypeField.java deleted file mode 100644 index 9012abc6..00000000 --- a/src/com/quollwriter/data/SelectUserConfigurableObjectTypeField.java +++ /dev/null @@ -1,98 +0,0 @@ -package com.quollwriter.data; - -import java.awt.Dimension; - -import java.util.Map; -import java.util.Set; -import java.util.LinkedHashSet; -import java.util.StringTokenizer; -import java.util.List; -import java.util.ArrayList; -import java.util.Collection; - -import java.math.*; - -import javax.swing.*; - -import com.quollwriter.ui.*; -import com.quollwriter.ui.userobjects.*; - -public class SelectUserConfigurableObjectTypeField extends UserConfigurableObjectTypeField -{ - - public static final String ITEMS = "items"; - public static final String ALLOWMULTI = "allowmulti"; - - public SelectUserConfigurableObjectTypeField () - { - - super (Type.select); - - } - - @Override - public boolean isSortable () - { - - return true; - - } - - @Override - public UserConfigurableObjectFieldViewEditHandler getViewEditHandler (UserConfigurableObject obj, - UserConfigurableObjectField field, - AbstractProjectViewer viewer) - { - - return new SelectUserConfigurableObjectFieldViewEditHandler (this, - obj, - field, - viewer); - - } - - @Override - public UserConfigurableObjectTypeFieldConfigHandler getConfigHandler () - { - - return new SelectUserConfigurableObjectTypeFieldConfigHandler (this); - - } - - public void setItems (Collection its) - { - - this.setDefinitionValue (ITEMS, new ArrayList (its)); - - } - - public Collection getItems () - { - - return (Collection) this.getDefinitionValue (ITEMS); - - } - - @Override - public boolean isSearchable () - { - - return true; - - } - - public boolean isAllowMulti () - { - - return this.getBooleanDefinitionValue (ALLOWMULTI); - - } - - public void setAllowMulti (boolean v) - { - - this.setDefinitionValue (ALLOWMULTI, v); - - } - -} diff --git a/src/com/quollwriter/data/TextUserConfigurableObjectTypeField.java b/src/com/quollwriter/data/TextUserConfigurableObjectTypeField.java deleted file mode 100644 index 1356c903..00000000 --- a/src/com/quollwriter/data/TextUserConfigurableObjectTypeField.java +++ /dev/null @@ -1,56 +0,0 @@ -package com.quollwriter.data; - -import com.quollwriter.ui.*; -import com.quollwriter.ui.userobjects.*; - -/** - * Models a text user configurable object field. - */ -public class TextUserConfigurableObjectTypeField extends UserConfigurableObjectTypeField -{ - - public TextUserConfigurableObjectTypeField () - { - - super (Type.text); - - } - - @Override - public boolean isSortable () - { - - return true; - - } - - @Override - public UserConfigurableObjectTypeFieldConfigHandler getConfigHandler () - { - - return new TextUserConfigurableObjectTypeFieldConfigHandler (this); - - } - - @Override - public UserConfigurableObjectFieldViewEditHandler getViewEditHandler (UserConfigurableObject obj, - UserConfigurableObjectField field, - AbstractProjectViewer viewer) - { - - return new TextUserConfigurableObjectFieldViewEditHandler (this, - obj, - field, - viewer); - - } - - @Override - public boolean isSearchable () - { - - return true; - - } - -} diff --git a/src/com/quollwriter/data/UserConfigurableObject.java b/src/com/quollwriter/data/UserConfigurableObject.java deleted file mode 100644 index 6b406e72..00000000 --- a/src/com/quollwriter/data/UserConfigurableObject.java +++ /dev/null @@ -1,286 +0,0 @@ -package com.quollwriter.data; - -import java.util.*; - -import org.jdom.*; -import org.josql.*; - -import com.quollwriter.*; -import com.quollwriter.ui.*; -import com.quollwriter.ui.userobjects.*; - -public class UserConfigurableObject extends NamedObject -{ - - protected UserConfigurableObjectType userConfigObjType = null; - private Project proj = null; - protected Set fields = new LinkedHashSet (); - - public UserConfigurableObject (UserConfigurableObjectType objType) - { - - super (objType.getObjectTypeId ()); - - this.userConfigObjType = objType; - - } - - @Override - public void fillToStringProperties (Map props) - { - - super.fillToStringProperties (props); - - this.addToStringProperties (props, - "userConfigObjType", - this.userConfigObjType); - this.addToStringProperties (props, - "fields", - this.fields.size ()); - - } - - @Override - public Set getAllNames () - { - - Set l = new HashSet (); - - l.add (this.getName ()); - - // Find all name fields and add to the list. - for (UserConfigurableObjectField f : this.fields) - { - - l.addAll (f.getNames ()); - - } - - return l; - - } - - @Override - public Set getAllNamedChildObjects () - { - - return new LinkedHashSet (this.fields); - - } - - @Override - public void getChanges (NamedObject old, - Element root) - { - - } - - public ObjectNameUserConfigurableObjectFieldViewEditHandler getPrimaryNameViewEditHandler (com.quollwriter.ui.ProjectViewer viewer) - { - - return (ObjectNameUserConfigurableObjectFieldViewEditHandler) this.getPrimaryNameTypeField ().getViewEditHandler (this, - null, - viewer); - - } - - public ObjectDescriptionUserConfigurableObjectFieldViewEditHandler getObjectDescriptionViewEditHandler (com.quollwriter.ui.ProjectViewer viewer) - { - - if (this.getObjectDescriptionTypeField () == null) - { - - return null; - - } - - return (ObjectDescriptionUserConfigurableObjectFieldViewEditHandler) this.getObjectDescriptionTypeField ().getViewEditHandler (this, - null, - viewer); - - } - - public Object getValueForField (UserConfigurableObjectTypeField f) - { - - for (UserConfigurableObjectField field : this.fields) - { - - if (field.getUserConfigurableObjectTypeField () == f) - { - - return field.getUserConfigurableObjectTypeField ().getViewEditHandler (this, - field, - null).getFieldValue (); - - } - - } - - return null; - - } - - public void removeField (UserConfigurableObjectField f) - { - - if (this.userConfigObjType == null) - { - - throw new IllegalStateException ("No configurable object type set"); - - } - - if (f.isPrimaryNameField ()) - { - - throw new IllegalStateException ("Cannot remove primary name field."); - - } - - this.fields.remove (f); - - } - - public void addField (UserConfigurableObjectField f) - { - - if (this.userConfigObjType == null) - { - - throw new IllegalStateException ("No configurable object type set"); - - } - - f.setParent (this); - - this.fields.add (f); - - } - - public ObjectNameUserConfigurableObjectTypeField getPrimaryNameTypeField () - { - - if (this.userConfigObjType == null) - { - - throw new IllegalStateException ("No configurable object type set"); - - } - - return this.userConfigObjType.getPrimaryNameField (); - - } - - public ObjectDescriptionUserConfigurableObjectTypeField getObjectDescriptionTypeField () - { - - if (this.userConfigObjType == null) - { - - throw new IllegalStateException ("No configurable object type set"); - - } - - return this.userConfigObjType.getObjectDescriptionField (); - - } - - public ObjectImageUserConfigurableObjectTypeField getObjectImageTypeField () - { - - if (this.userConfigObjType == null) - { - - throw new IllegalStateException ("No configurable object type set"); - - } - - return this.userConfigObjType.getObjectImageField (); - - } - - public Set getFields () - { - - return this.fields; - - } - - public Project getProject () - { - - return this.proj; - - } - - public String getObjectTypeName () - { - - return this.userConfigObjType.getObjectTypeName (); - - } - - public String getObjectTypePluralName () - { - - return this.userConfigObjType.getObjectTypeNamePlural (); - - } - - public void setProject (Project p) - { - - this.proj = p; - - this.setParent (this.proj); - - } - - public UserConfigurableObjectType getUserConfigurableObjectType () - { - - return this.userConfigObjType; - - } - - public void setUserConfigurableObjectType (UserConfigurableObjectType t) - { - - this.userConfigObjType = t; - - } - - public Set getViewEditHandlers (com.quollwriter.ui.ProjectViewer viewer) - { - - Map typeFieldMap = new HashMap (); - - for (UserConfigurableObjectField f : this.fields) - { - - typeFieldMap.put (f.getUserConfigurableObjectTypeField (), - f); - - } - - Set handlers = new LinkedHashSet (); - - for (UserConfigurableObjectTypeField tf : this.userConfigObjType.getConfigurableFields ()) - { - - UserConfigurableObjectField f = typeFieldMap.get (tf); - - UserConfigurableObjectFieldViewEditHandler h = tf.getViewEditHandler (this, - f, - viewer); - - handlers.add (h); - - } - - return handlers; - - } - -} \ No newline at end of file diff --git a/src/com/quollwriter/data/UserConfigurableObjectField.java b/src/com/quollwriter/data/UserConfigurableObjectField.java deleted file mode 100644 index ad7294a6..00000000 --- a/src/com/quollwriter/data/UserConfigurableObjectField.java +++ /dev/null @@ -1,206 +0,0 @@ -package com.quollwriter.data; - -import java.util.*; - -import org.jdom.*; - -import com.quollwriter.*; - -public class UserConfigurableObjectField extends NamedObject -{ - - private UserConfigurableObjectTypeField field = null; - private Object value = null; - - public UserConfigurableObjectField (UserConfigurableObjectTypeField type) - { - - super (type.getUserConfigurableObjectType ().getObjectTypeId () + "objectfield"); - - this.field = type; - - } - - // TODO: Make this better...! - public Set getProjectFileNames () - { - - Set files = new LinkedHashSet (); - - if (this.value == null) - { - - return files; - - } - - if ((this.field instanceof ImageUserConfigurableObjectTypeField) - || - (this.field instanceof FileUserConfigurableObjectTypeField) - ) - { - - files.add (this.value.toString ()); - - } - - return files; - - } - - public UserConfigurableObject getParentObject () - { - - return (UserConfigurableObject) this.getParent (); - - } - - @Override - public void fillToStringProperties (Map props) - { - - super.fillToStringProperties (props); - - this.addToStringProperties (props, - "value", - this.value); - - if (this.value != null) - { - - this.addToStringProperties (props, - "valueClass", - this.value.getClass ().getName ()); - - } - - this.addToStringProperties (props, - "typeField", - this.field); - - } - - public Set getAllNamedChildObjects () - { - - return null; - - } - - public boolean isPrimaryNameField () - { - - return (this.field instanceof ObjectNameUserConfigurableObjectTypeField); - - } - - public boolean isNameField () - { - - return (this.field.isNameField () || this.isPrimaryNameField ()); - - } - - public boolean isLegacyField () - { - - return this.field.isLegacyField (); - - } - - public String getLegacyFieldId () - { - - return this.field.getLegacyFieldId (); - - } - - public UserConfigurableObjectTypeField getUserConfigurableObjectTypeField () - { - - return this.field; - - } - - public void getChanges (NamedObject old, - Element root) - { - - } - - public Set getNames () - { - - Set ret = new LinkedHashSet (); - - if ((this.isNameField ()) - && - (this.value != null) - ) - { - - try - { - - return this.field.getViewEditHandler (this.getParentObject (), - this, - null).getNamesFromFieldValue (); - - } catch (Exception e) { - - Environment.logError ("Unable to get names for field: " + - this.value, - e); - - } - - } - - return ret; - - } - - public String getValueAsString () - { - - if (this.value == null) - { - - return null; - - } - - try - { - - return this.field.getViewEditHandler (this.getParentObject (), - this, - null).valueToString (this.value); - - } catch (Exception e) { - - Environment.logError ("Unable to get value as string: " + - this.value, - e); - - return this.value.toString (); - - } - - } - - public void setValue (Object v) - { - - this.value = v; - - } - - public Object getValue () - { - - return this.value; - - } - -} \ No newline at end of file diff --git a/src/com/quollwriter/data/UserConfigurableObjectType.java b/src/com/quollwriter/data/UserConfigurableObjectType.java deleted file mode 100644 index 629d9ad6..00000000 --- a/src/com/quollwriter/data/UserConfigurableObjectType.java +++ /dev/null @@ -1,531 +0,0 @@ -package com.quollwriter.data; - -import java.util.*; - -import javax.swing.*; - -import org.jdom.*; - -import com.quollwriter.*; - -import static com.quollwriter.LanguageStrings.*; -import static com.quollwriter.Environment.getUIString; - -public class UserConfigurableObjectType extends NamedObject -{ - - public static final String ICON16 = "icon16"; - public static final String ICON24 = "icon24"; - public static final String OBJECT_TYPE_NAME_PLURAL = "objectTypeNamePlural"; - public static final String OBJECT_TYPE_NAME = "objectTypeName"; - public static final String OBJECT_TYPE = "userconfigobjtype"; - - private String objectTypeNamePlural = null; - private ImageIcon icon24x24 = null; - private ImageIcon icon16x16 = null; - private Set fields = new LinkedHashSet (); - private String layout = null; - private String userObjectType = null; - private boolean isAsset = false; - private KeyStroke createShortcutKeyStroke = null; - private boolean pluralNameSet = false; - private boolean singularNameSet = false; - - public UserConfigurableObjectType () - { - - super (OBJECT_TYPE); - - } - - @Override - public void fillToStringProperties (Map props) - { - - super.fillToStringProperties (props); - - this.addToStringProperties (props, - "objectTypeId", - this.getObjectTypeId ()); - this.addToStringProperties (props, - "objectTypeName", - this.getName ()); - this.addToStringProperties (props, - "objectTypeNamePlural", - this.getObjectTypeNamePlural ()); - this.addToStringProperties (props, - "isAsset", - this.isAssetObjectType ()); - this.addToStringProperties (props, - "layout", - this.getLayout ()); - this.addToStringProperties (props, - "createShortcutKey", - this.createShortcutKeyStroke); - this.addToStringProperties (props, - "fields", - this.fields.size ()); - - } - - public Set getSortableFields () - { - - Set sfs = new LinkedHashSet (); - - for (UserConfigurableObjectTypeField f : this.fields) - { - - if (f.isSortable ()) - { - - sfs.add (f); - - } - - } - - return sfs; - - } - - public void setCreateShortcutKeyStroke (KeyStroke k) - { - - this.createShortcutKeyStroke = k; - - } - - public KeyStroke getCreateShortcutKeyStroke () - { - - return this.createShortcutKeyStroke; - - } - - public boolean isLegacyObjectType () - { - - return this.getUserObjectType () != null; - - } - - public String getUserObjectType () - { - - return this.userObjectType; - - } - - public void setUserObjectType (String t) - { - - this.userObjectType = t; - - } - - public Set getAllNamedChildObjects () - { - - return new LinkedHashSet (this.fields); - - } - - public void getChanges (NamedObject old, - Element root) - { - - } - - public String getLayout () - { - - return this.layout; - - } - - public void setLayout (String l) - { - - this.layout = l; - - } - - public Set getConfigurableFields () - { - - // Order the fields. - TreeMap s = new TreeMap (); - - for (UserConfigurableObjectTypeField f : this.fields) - { - - if (f.getOrder () == -1) - { - - throw new IllegalStateException ("Field must have an order value: " + - f); - - } - - if (s.containsKey (f.getOrder ())) - { - - throw new IllegalStateException ("Already have a field with order: " + - f.getOrder () + - ", " + - s.get (f.getOrder ())); - - } - - s.put (f.getOrder (), - f); - - } - - return new LinkedHashSet (s.values ()); - - } - - public void addConfigurableField (UserConfigurableObjectTypeField f) - { - - this.fields.add (f); - - f.setUserConfigurableObjectType (this); - - if (f.getOrder () == -1) - { - - f.setOrder (this.fields.size () - 1); - - } - - } - - public void removeConfigurableField (UserConfigurableObjectTypeField f) - { - - if (f instanceof ObjectNameUserConfigurableObjectTypeField) - { - - throw new IllegalArgumentException ("Cant remove the object name field."); - - } - - this.fields.remove (f); - - f.setUserConfigurableObjectType (null); - - int i = 0; - - for (UserConfigurableObjectTypeField _f : this.fields) - { - - _f.setOrder (i); - - i++; - - } - - } -/* - public void reorderFields () - { - - TreeMap s = new TreeMap (); - - for (UserConfigurableObjectTypeField f : this.fields) - { - - if (f.getOrder () == -1) - { - - throw new IllegalStateException ("Field must have an order value: " + - f); - - } - - s.put (f.getOrder (), - f); - - } - - this.fields = new LinkedHashSet (s.values ()); - - } -*/ - public UserConfigurableObjectTypeField getLegacyField (String id) - { - - for (UserConfigurableObjectTypeField f : this.fields) - { - - if ((f.getLegacyFieldId () != null) - && - (f.getLegacyFieldId ().equals (id)) - ) - { - - return f; - - } - - } - - return null; - - } - - /** - * Return how many non object name/object description fields there are. - * - * @return The count. - */ - public int getNonCoreFieldCount () - { - - int c = 0; - - for (UserConfigurableObjectTypeField f : this.fields) - { - - // TODO: Need a better way! - if (f instanceof ObjectNameUserConfigurableObjectTypeField) - { - - continue; - - } - - if (f instanceof ObjectDescriptionUserConfigurableObjectTypeField) - { - - continue; - - } - - c++; - - } - - return c; - - } - - public ObjectNameUserConfigurableObjectTypeField getPrimaryNameField () - { - - for (UserConfigurableObjectTypeField f : this.fields) - { - - // TODO: Need a better way! - if (f instanceof ObjectNameUserConfigurableObjectTypeField) - { - - return (ObjectNameUserConfigurableObjectTypeField) f; - - } - - } - - return null; - - } - - public ObjectDescriptionUserConfigurableObjectTypeField getObjectDescriptionField () - { - - for (UserConfigurableObjectTypeField f : this.fields) - { - - // TODO: Need a better way! - if (f instanceof ObjectDescriptionUserConfigurableObjectTypeField) - { - - return (ObjectDescriptionUserConfigurableObjectTypeField) f; - - } - - } - - return null; - - } - - public ObjectImageUserConfigurableObjectTypeField getObjectImageField () - { - - for (UserConfigurableObjectTypeField f : this.fields) - { - - // TODO: Need a better way! - if (f instanceof ObjectImageUserConfigurableObjectTypeField) - { - - return (ObjectImageUserConfigurableObjectTypeField) f; - - } - - } - - return null; - - } - - public void setIcon24x24 (ImageIcon ic) - { - - ImageIcon oldIc = this.icon24x24; - - this.icon24x24 = ic; - - this.firePropertyChangedEvent (ICON24, - oldIc, - ic); - - } - - public ImageIcon getIcon24x24 () - { - - return this.icon24x24; - - } - - public void setIcon16x16 (ImageIcon ic) - { - - ImageIcon oldIc = this.icon16x16; - - this.icon16x16 = ic; - - this.firePropertyChangedEvent (ICON16, - oldIc, - ic); - - } - - public ImageIcon getIcon16x16 () - { - - return this.icon16x16; - - } - - public void setObjectTypeName (String n) - { - - String oldName = this.getName (); - - this.setName (n); - - this.firePropertyChangedEvent (OBJECT_TYPE_NAME, - oldName, - n); - - this.singularNameSet = (n != null); - - } - - public String getObjectTypeName () - { - - if (this.singularNameSet) - { - - return super.getName (); - - } - - return Environment.getUIString (objectnames,singular,this.userObjectType); - - //return this.getName (); - - } - - public String getActualObjectTypeName () - { - - return this.getName (); - - } - - public String getObjectTypeNamePlural () - { - - if (this.pluralNameSet) - { - - return this.objectTypeNamePlural; - - } - - return Environment.getUIString (objectnames,plural,this.userObjectType); - - //return this.objectTypeNamePlural; - - } - - public String getActualObjectTypeNamePlural () - { - - return this.objectTypeNamePlural; - - } - - public void setObjectTypeNamePlural (String n) - { - - String oldName = this.objectTypeNamePlural; - - this.objectTypeNamePlural = n; - - this.firePropertyChangedEvent (OBJECT_TYPE_NAME_PLURAL, - oldName, - n); - - this.pluralNameSet = (n != null); - - } - - public String getObjectTypeId () - { - - if (this.getUserObjectType () != null) - { - - return this.getUserObjectType (); - - } else { - - if (this.isAssetObjectType ()) - { - - return "asset:" + this.getKey (); - - } else { - - return this.getObjectReference ().asString (); - - } - - } - - } - - public void setAssetObjectType (boolean v) - { - - this.isAsset = v; - - } - - public boolean isAssetObjectType () - { - - return this.isAsset; - - } - -} diff --git a/src/com/quollwriter/data/UserConfigurableObjectTypeField.java b/src/com/quollwriter/data/UserConfigurableObjectTypeField.java deleted file mode 100644 index 1602f598..00000000 --- a/src/com/quollwriter/data/UserConfigurableObjectTypeField.java +++ /dev/null @@ -1,511 +0,0 @@ -package com.quollwriter.data; - -import java.util.*; - -import org.jdom.*; - -import com.quollwriter.*; -import com.quollwriter.ui.*; -import com.quollwriter.ui.userobjects.*; - -import static com.quollwriter.LanguageStrings.*; -import static com.quollwriter.Environment.getUIString; - -public abstract class UserConfigurableObjectTypeField extends NamedObject -{ - - public enum Type - { - - text ("text"), - multitext ("multitext"), - image ("image"), - select ("select"), - date ("date"), - number ("number"), - file ("file"), - webpage ("webpage"), - objectname ("objectname"), - objectdesc ("objectdesc"), - objectimage ("objectimage"); - - private String type = null; - - Type (String type) - { - - this.type = type; - - } - - public String getType () - { - - return this.type; - - } - - public static UserConfigurableObjectTypeField getNewFieldForType (Type t) - { - - switch (t) - { - case text : return new TextUserConfigurableObjectTypeField (); - case multitext : return new MultiTextUserConfigurableObjectTypeField (); - case select : return new SelectUserConfigurableObjectTypeField (); - case date : return new DateUserConfigurableObjectTypeField (); - case number : return new NumberUserConfigurableObjectTypeField (); - case webpage : return new WebpageUserConfigurableObjectTypeField (); - case file : return new FileUserConfigurableObjectTypeField (); - case image : return new ImageUserConfigurableObjectTypeField (); - case objectname : return new ObjectNameUserConfigurableObjectTypeField (); - case objectdesc : return new ObjectDescriptionUserConfigurableObjectTypeField (); - case objectimage : return new ObjectImageUserConfigurableObjectTypeField (); - default : return null; - - } - - } - - public String getName () - { - - java.util.List prefix = new ArrayList (); - prefix.add (LanguageStrings.form); - prefix.add (LanguageStrings.types); - - return Environment.getUIString (prefix, - this.type); - - } - - } - - public static final String OBJECT_TYPE = "userconfigobjfield"; - - private String formName = null; - private Type type = null; - private UserConfigurableObjectType userConfigType = null; - private Map definition = new HashMap (); - private String defValue = null; - private int order = -1; - - protected UserConfigurableObjectTypeField (Type type) - { - - super (OBJECT_TYPE); - - this.type = type; - - } - - @Override - public void fillToStringProperties (Map props) - { - - super.fillToStringProperties (props); - - this.addToStringProperties (props, - "formName", - this.formName); - this.addToStringProperties (props, - "type", - this.type.getName ()); - this.addToStringProperties (props, - "default", - this.defValue); - this.addToStringProperties (props, - "order", - this.order); - this.addToStringProperties (props, - "definition", - this.definition); - - } - - /** - * The view/edit handler is used for viewing/editing the data of a field of this type. - * - * @return The view/edit handler for this type of field. - */ - // TODO: Check to see if this needs to be generic. - // TODO: Have this be configurable and use class loading... - public abstract UserConfigurableObjectFieldViewEditHandler getViewEditHandler (UserConfigurableObject obj, - UserConfigurableObjectField field, - AbstractProjectViewer viewer); - - /** - * The config handler is used for editing/configuration of this field. - * - * Implementing classes should return a suitable sub-type that can handle this field. - * - * @return The config handler for this field. - */ - public abstract UserConfigurableObjectTypeFieldConfigHandler getConfigHandler (); - - public boolean isSortable () - { - - return false; - - } - - public boolean canEdit () - { - - return true; - - } - - public boolean canDelete () - { - - return true; - - } - - public void setDefinitionValue (String id, - Object v) - { - - this.definition.put (id, - v); - - } - - public void setDefinitionValue (String id, - Date v) - { - - this.definition.put (id, - Environment.formatDate (v)); - - } - - public void setDefinitionValue (String id, - Double v) - { - - this.definition.put (id, - (v != null ? Environment.formatNumber (v) : null)); - - } - - public Double getDoubleDefinitionValue (String id) - throws GeneralException - { - - Object o = this.getDefinitionValue (id); - - if (o == null) - { - - return null; - - } - - return Environment.parseToDouble (o.toString ()); - - } - - public Date getDateDefinitionValue (String id) - { - - Object v = this.getDefinitionValue (id); - - if (v == null) - { - - return null; - - } - - return Environment.parseDate (v.toString ()); - - } - - public boolean getBooleanDefinitionValue (String id) - { - - Boolean b = (Boolean) this.getDefinitionValue (id); - - if (b == null) - { - - return false; - - } - - return b; - - } - - public Object getDefinitionValue (String id) - { - - return this.definition.get (id); - - } - - public void removeDefinitionValue (String id) - { - - this.definition.remove (id); - - } - - public boolean isLegacyField () - { - - return this.getLegacyFieldId () != null; - - } - - public boolean isSearchable () - { - - return this.getBooleanDefinitionValue ("searchable"); - - } - - public void setSearchable (boolean v) - { - - this.setDefinitionValue ("searchable", true); - - } - - public String getLegacyFieldFormName () - { - - UserConfigurableObjectType ot = this.getUserConfigurableObjectType (); - - String ut = ot.getUserObjectType (); - - String id = this.getLegacyFieldId (); - - if (ut.equals (Chapter.OBJECT_TYPE)) - { - - if (id.equals (LegacyUserConfigurableObject.DESCRIPTION_LEGACY_FIELD_ID)) - { - - return getUIString (chapters,fields,description); - - } - - if (id.equals (Chapter.PLAN_LEGACY_FIELD_ID)) - { - - return getUIString (chapters,fields,plan); - - } - - if (id.equals (Chapter.GOALS_LEGACY_FIELD_ID)) - { - - return getUIString (chapters,fields,goals); - - } - - } - - if (id.equals (LegacyUserConfigurableObject.NAME_LEGACY_FIELD_ID)) - { - - return getUIString (assets,legacyfields,name); - - } - - if (id.equals (LegacyUserConfigurableObject.ALIASES_LEGACY_FIELD_ID)) - { - - return getUIString (assets,legacyfields,aliases); - - } - - if (id.equals (LegacyUserConfigurableObject.DESCRIPTION_LEGACY_FIELD_ID)) - { - - return getUIString (assets,legacyfields,description); - - } - - if (id.equals (QObject.TYPE_LEGACY_FIELD_ID)) - { - - return getUIString (assets,legacyfields,LanguageStrings.type); - - } - - if (id.equals (ResearchItem.WEB_PAGE_LEGACY_FIELD_ID)) - { - - return getUIString (assets,legacyfields,webpage); - - } - - throw new IllegalArgumentException ("Unsupported field id: " + id); - - } - - public void setLegacyFieldId (String i) - { - - this.setDefinitionValue ("legacyFieldId", i); - - } - - public String getLegacyFieldId () - { - - return (String) this.getDefinitionValue ("legacyFieldId"); - - } - - public void setOrder (int i) - { - - int c = this.order; - - this.order = i; - /* - if ((this.userConfigType != null) - && - (i != c) - ) - { - - this.userConfigType.reorderFields (); - - } - */ - } - - public int getOrder () - { - - return this.order; - - } - - public Map getDefinition () - { - - return this.definition; - - } - - public void setDefinition (Map m) - { - - this.definition = m; - - } - - public String getDefaultValue () - { - - return (String) this.getDefinitionValue ("default"); - - } - - public void setDefaultValue (String v) - { - - this.setDefinitionValue ("default", v); - - } - - public void setUserConfigurableObjectType (UserConfigurableObjectType t) - { - - this.userConfigType = t; - - this.setParent (t); - - } - - public UserConfigurableObjectType getUserConfigurableObjectType () - { - - return this.userConfigType; - - } - - public Set getAllNamedChildObjects () - { - - return null; - - } - - public void getChanges (NamedObject old, - Element root) - { - - } - - public boolean isNameField () - { - - Object o = this.getDefinitionValue ("nameField"); - - if (o == null) - { - - return false; - - } - - return (Boolean) o; - - } - - public void setNameField (boolean v) - { - - this.setDefinitionValue ("nameField", v); - - } - - public DataObject getObjectForReference (ObjectReference ref) - { - - return null; - - } - - public void setFormName (String n) - { - - super.setName (n); - - } - - public String getFormName () - { - - String n = this.getName (); - - if (n != null) - { - - return n; - - } - - return this.getLegacyFieldFormName (); - - //return this.getName (); - - } - - public Type getType () - { - - return this.type; - - } - -} diff --git a/src/com/quollwriter/data/UserSession.java b/src/com/quollwriter/data/UserSession.java deleted file mode 100644 index 2380a95a..00000000 --- a/src/com/quollwriter/data/UserSession.java +++ /dev/null @@ -1,308 +0,0 @@ -package com.quollwriter.data; - -import java.util.*; - -import com.quollwriter.*; -import com.quollwriter.ui.*; - -/** - * Holds state information about the user session. - */ -public class UserSession extends Session -{ - - public boolean sessionTargetReachedPopupShown = false; - public boolean dailyTargetReachedPopupShown = false; - private int lastSnapshotSessionWordCount = 0; - private Date lastSnapshotSessionEnd = null; - private int currentSessionWordCount = 0; - private Date dailyTargetReachedPopupShownDate = null; - private Date weeklyTargetReachedPopupShownDate = null; - private Date monthlyTargetReachedPopupShownDate = null; - - public UserSession () - { - - this.init (); - - } - - public UserSession (Date start, - Date end, - int wc) - { - - super (start, - end, - wc); - - this.init (); - - } - - private void init () - { - - String dv = UserProperties.get (Constants.TARGET_DAILY_TARGET_REACHED_POPUP_SHOWN_DATE); - - Date currDate = Utils.zeroTimeFields (new Date ()); - - if (dv != null) - { - - try - { - - this.dailyTargetReachedPopupShownDate = Utils.zeroTimeFields (new Date (Long.parseLong (dv))); - - this.dailyTargetReachedPopupShown = (currDate == this.dailyTargetReachedPopupShownDate); - - } catch (Exception e) { - - Environment.logError ("Unable to parse daily target reached popup shown date", - e); - - } - - } - - dv = UserProperties.get (Constants.TARGET_WEEKLY_TARGET_REACHED_POPUP_SHOWN_DATE); - - if (dv != null) - { - - try - { - - this.weeklyTargetReachedPopupShownDate = new Date (Long.parseLong (dv)); - - } catch (Exception e) { - - Environment.logError ("Unable to parse weekly target reached popup shown date", - e); - - } - - } - - dv = UserProperties.get (Constants.TARGET_MONTHLY_TARGET_REACHED_POPUP_SHOWN_DATE); - - if (dv != null) - { - - try - { - - this.monthlyTargetReachedPopupShownDate = new Date (Long.parseLong (dv)); - - } catch (Exception e) { - - Environment.logError ("Unable to parse monthly target reached popup shown date", - e); - - } - - } - - } - - public void shownDailyTargetReachedPopup () - { - - Date d = Utils.zeroTimeFields (new Date ()); - - this.dailyTargetReachedPopupShownDate = d; - this.dailyTargetReachedPopupShown = true; - - // Set a user property. - UserProperties.set (Constants.TARGET_DAILY_TARGET_REACHED_POPUP_SHOWN_DATE, - String.valueOf (d.getTime ())); - - } - - public boolean shouldShowDailyTargetReachedPopup () - { - - if ((this.dailyTargetReachedPopupShownDate != null) - && - (this.dailyTargetReachedPopupShown) - ) - { - - Date d = Utils.zeroTimeFields (new Date ()); - - return d.after (this.dailyTargetReachedPopupShownDate); - - } - - return true; - - } - - private Date getWeekDate () - { - - GregorianCalendar gc = new GregorianCalendar (); - - gc.set (Calendar.DAY_OF_WEEK, - gc.getFirstDayOfWeek ()); - - Date d = Utils.zeroTimeFields (gc.getTime ()); - - return d; - - } - - public void shownWeeklyTargetReachedPopup () - { - - Date d = this.getWeekDate (); - - this.weeklyTargetReachedPopupShownDate = d; - - // Set a user property. - UserProperties.set (Constants.TARGET_WEEKLY_TARGET_REACHED_POPUP_SHOWN_DATE, - String.valueOf (d.getTime ())); - - } - - public boolean shouldShowWeeklyTargetReachedPopup () - { - - if (this.weeklyTargetReachedPopupShownDate != null) - { - - Date d = this.getWeekDate (); - - return d.after (this.weeklyTargetReachedPopupShownDate); - - } - - return true; - - } - - private Date getMonthDate () - { - - GregorianCalendar gc = new GregorianCalendar (); - - gc.set (Calendar.DAY_OF_MONTH, - 1); - - Date d = Utils.zeroTimeFields (gc.getTime ()); - - return d; - - } - - public void shownMonthlyTargetReachedPopup () - { - - Date d = this.getMonthDate (); - - this.monthlyTargetReachedPopupShownDate = d; - - // Set a user property. - UserProperties.set (Constants.TARGET_MONTHLY_TARGET_REACHED_POPUP_SHOWN_DATE, - String.valueOf (d.getTime ())); - - } - - public boolean shouldShowMonthlyTargetReachedPopup () - { - - if (this.monthlyTargetReachedPopupShownDate != null) - { - - Date d = this.getMonthDate (); - - return d.after (this.monthlyTargetReachedPopupShownDate); - - } - - return true; - - } - - public void shownSessionTargetReachedPopup () - { - - this.sessionTargetReachedPopupShown = true; - - } - - public boolean shouldShowSessionTargetReachedPopup () - { - - return !this.sessionTargetReachedPopupShown; - - } - - public String toString () - { - - return super.toString () + ", lastCurrent: " + this.currentSessionWordCount + ", current: " + this.getCurrentSessionWordCount (); - - } - - @Override - public int getWordCount () - { - - return this.getCurrentSessionWordCount (); - - } - - public void updateCurrentSessionWordCount (int wordCount) - { - - this.currentSessionWordCount += wordCount; - - } - - public int getCurrentSessionWordCount () - { - - Map pvs = Environment.getOpenProjects (); - - int c = this.currentSessionWordCount; - - for (AbstractProjectViewer pv : pvs.values ()) - { - - // Don't include editor projects. - if (pv.getProject ().isEditorProject ()) - { - - continue; - - } - - c += pv.getSessionWordCount (); - - } - - return c; - - } - - public UserSession createSnapshot () - { - - int wc = this.getCurrentSessionWordCount () - this.lastSnapshotSessionWordCount; - - Date end = new Date (); - - UserSession s = new UserSession ((this.lastSnapshotSessionEnd != null ? this.lastSnapshotSessionEnd : this.getStart ()), - end, - wc); - - this.lastSnapshotSessionEnd = end; - this.lastSnapshotSessionWordCount = wc; - - return s; - - } - -} diff --git a/src/com/quollwriter/data/WebpageUserConfigurableObjectTypeField.java b/src/com/quollwriter/data/WebpageUserConfigurableObjectTypeField.java deleted file mode 100644 index c500b5db..00000000 --- a/src/com/quollwriter/data/WebpageUserConfigurableObjectTypeField.java +++ /dev/null @@ -1,53 +0,0 @@ -package com.quollwriter.data; - -import com.quollwriter.ui.*; -import com.quollwriter.ui.userobjects.*; - -public class WebpageUserConfigurableObjectTypeField extends UserConfigurableObjectTypeField -{ - - public WebpageUserConfigurableObjectTypeField () - { - - super (Type.webpage); - - } - - @Override - public boolean isSortable () - { - - return true; - - } - - @Override - public UserConfigurableObjectFieldViewEditHandler getViewEditHandler (UserConfigurableObject obj, - UserConfigurableObjectField field, - AbstractProjectViewer viewer) - { - - return new WebpageUserConfigurableObjectFieldViewEditHandler (this, - obj, - field, - viewer); - - } - - @Override - public UserConfigurableObjectTypeFieldConfigHandler getConfigHandler () - { - - return new WebpageUserConfigurableObjectTypeFieldConfigHandler (this); - - } - - @Override - public boolean isSearchable () - { - - return true; - - } - -} diff --git a/src/com/quollwriter/data/comparators/ChapterItemSorter.java b/src/com/quollwriter/data/comparators/ChapterItemSorter.java deleted file mode 100644 index ba95d290..00000000 --- a/src/com/quollwriter/data/comparators/ChapterItemSorter.java +++ /dev/null @@ -1,108 +0,0 @@ -package com.quollwriter.data.comparators; - -import java.util.*; - -import com.quollwriter.data.*; - -public class ChapterItemSorter implements Comparator -{ - - @Override - public int compare (ChapterItem o1, - ChapterItem o2) - { -/* - if (o1.getKey () == null) - { - - return 1; - - } - - if (o2.getKey () == null) - { - - return 1; - - } - */ - - // The sorter may be used for contains checks in Sets and Maps so need an equality test here. - if (o1.getKey () == o2.getKey ()) - { - - return 0; - - } - - if (o1.getPosition () == o2.getPosition ()) - { - - if ((o1.getKey () == null) - || - (o1.getName () == null) - ) - { - - return 1; - - } - - if ((o2.getKey () == null) - || - (o2.getName () == null) - ) - { - - return 1; - - } - - if ((o1 instanceof Scene) - && - (o2 instanceof OutlineItem) - ) - { - - return -1; - - } - - if ((o2 instanceof Scene) - && - (o1 instanceof OutlineItem) - ) - { - - return 1; - - } - - int nc = o1.getName ().compareTo (o2.getName ()); - - if (nc == 0) - { - - // Return the one created first. - return o1.getDateCreated ().compareTo (o2.getDateCreated ()); - - } - - return nc; - - //return (int) (o1.getKey () - o2.getKey ()); - - } - - return o1.getPosition () - o2.getPosition (); - - } - - public boolean equals (Object o) - { - - return this == o; - - } - -} diff --git a/src/com/quollwriter/data/editors/AbstractEditorObject.java b/src/com/quollwriter/data/editors/AbstractEditorObject.java deleted file mode 100644 index 0471ac8f..00000000 --- a/src/com/quollwriter/data/editors/AbstractEditorObject.java +++ /dev/null @@ -1,112 +0,0 @@ -package com.quollwriter.data.editors; - -import java.util.*; - -import org.jdom.*; - -import com.gentlyweb.xml.*; - -import com.quollwriter.data.*; - -public abstract class AbstractEditorObject extends NamedObject -{ - - public class XMLConstants - { - - public static final String id = "id"; - public static final String name = "name"; - public static final String lastModified = "lastModified"; - - } - - //private String id = null; - - public AbstractEditorObject (String objType) - { - - super (objType); - - } - - public AbstractEditorObject (String objType, - String name) - { - - super (objType, - name); - - } - - public AbstractEditorObject (Element root, - String objType) - throws Exception - { - - super (objType); - - this.setName (JDOMUtils.getChildElementContent (root, - XMLConstants.name, - true)); - - try - { - - this.setLastModified (new Date (Long.parseLong (JDOMUtils.getAttributeValue (root, - XMLConstants.lastModified)))); - - } catch (Exception e) { - - } - - } - - @Override - public void fillToStringProperties (Map props) - { - - super.fillToStringProperties (props); -/* - this.addToStringProperties (props, - "id", - this.id); - */ - } - - public void getChanges (NamedObject old, - Element root) - { - - } - - public Set getAllNamedChildObjects (Class ofType) - { - - return null; - - } - - public Set getAllNamedChildObjects () - { - - return null; - - } - - public void fillJDOMElement (Element root) - { - - Element name = new Element (XMLConstants.name); - name.addContent (this.getName ()); - Element id = new Element (XMLConstants.id); - id.addContent (this.getId ()); - - root.addContent (id); - root.addContent (name); - - root.setAttribute (XMLConstants.lastModified, - "" + this.getLastModified ().getTime ()); - - } - -} \ No newline at end of file diff --git a/src/com/quollwriter/data/editors/EditorAccount.java b/src/com/quollwriter/data/editors/EditorAccount.java deleted file mode 100644 index e7692bae..00000000 --- a/src/com/quollwriter/data/editors/EditorAccount.java +++ /dev/null @@ -1,254 +0,0 @@ -package com.quollwriter.data.editors; - -import java.awt.*; -import java.awt.image.*; -import java.io.*; -import javax.imageio.*; -import java.util.Date; -import java.util.Map; -import java.util.LinkedHashMap; - -import org.bouncycastle.openpgp.*; - -import com.quollwriter.*; - -public class EditorAccount -{ - - private String email = null; - private String pwd = null; - private String name = null; - private BufferedImage avatar = null; - private Date lastLogin = null; - - private EditorAuthor author = null; - private EditorEditor editor = null; - - private String webServiceSessionId = null; - - private PGPPublicKey publicKey = null; - private PGPPrivateKey privateKey = null; - - private String messagingUsername = null; - private String serviceName = null; - - public EditorAccount () - { - - - } - - @Override - public String toString () - { - - Map props = new LinkedHashMap (); - - props.put ("email", - this.email); - props.put ("name", - this.name); - props.put ("messagingUsername", - this.messagingUsername); - props.put ("serviceName", - this.serviceName); - - props.put ("hasPassword", - this.pwd != null); - - props.put ("lastLogin", - this.lastLogin); - - return Environment.formatObjectToStringProperties (props); - - } - - public String getServiceName () - { - - return this.serviceName; - - } - - public void setServiceName (String n) - { - - this.serviceName = n; - - } - - public String getMessagingUsername () - { - - return this.messagingUsername; - - } - - public void setMessagingUsername (String u) - { - - this.messagingUsername = u; - - } - - public void setPublicKey (PGPPublicKey k) - { - - this.publicKey = k; - - } - - public void setPrivateKey (PGPPrivateKey k) - { - - this.privateKey = k; - - } - - public PGPPublicKey getPublicKey () - { - - return this.publicKey; - - } - - public PGPPrivateKey getPrivateKey () - { - - return this.privateKey; - - } - - public Date getLastLogin () - { - - return this.lastLogin; - - } - - public void setLastLogin (Date d) - { - - this.lastLogin = d; - - } - - public void setWebServiceSessionId (String id) - { - - this.webServiceSessionId = id; - - } - - public String getWebServiceSessionId () - { - - return this.webServiceSessionId; - - } - - public String getAvatarBase64Encoded () - throws Exception - { - - if (this.avatar == null) - { - - return null; - - } - - ByteArrayOutputStream bout = new ByteArrayOutputStream (); - ImageIO.write (this.avatar, - "", - bout); - - return Base64.encodeBytes (bout.toByteArray ()); - - } - - public void setAvatar (BufferedImage im) - { - - this.avatar = im; - - } - - public BufferedImage getAvatar () - { - - return this.avatar; - - } - - public void setName (String n) - { - - this.name = n; - - } - - public String getName () - { - - return this.name; - - } - - public void setEditor (EditorEditor e) - { - - this.editor = e; - - } - - public EditorEditor getEditor () - { - - return this.editor; - - } - - public EditorAuthor getAuthor () - { - - return this.author; - - } - - public void setAuthor (EditorAuthor a) - { - - this.author = a; - - } - - public void setPassword (String p) - { - - this.pwd = p; - - } - - public String getPassword () - { - - return this.pwd; - - } - - public String getEmail () - { - - return this.email; - - } - - public void setEmail (String em) - { - - this.email = em; - - } - -} \ No newline at end of file diff --git a/src/com/quollwriter/data/editors/EditorAuthor.java b/src/com/quollwriter/data/editors/EditorAuthor.java deleted file mode 100644 index 02c4c235..00000000 --- a/src/com/quollwriter/data/editors/EditorAuthor.java +++ /dev/null @@ -1,115 +0,0 @@ -package com.quollwriter.data.editors; - -import java.io.*; - -import org.jdom.*; - -import javax.activation.*; - -import com.gentlyweb.xml.*; - -import com.quollwriter.*; - -public class EditorAuthor extends AbstractEditorObject -{ - - public static final String OBJECT_TYPE = "editorauthor"; - - public class XMLConstants - { - - public static final String root = "author"; - public static final String about = "about"; - - } - - private String about = null; - private DataSource avatar = null; - private String avatarImageFileType = null; - - public EditorAuthor () - { - - super (OBJECT_TYPE); - - } - - public EditorAuthor (Element root) - throws Exception - { - - super (root, - OBJECT_TYPE); - - this.about = JDOMUtils.getChildElementContent (root, - XMLConstants.about, - true); - - } - - public Element getAsJDOMElement () - { - - Element root = new Element (XMLConstants.root); - - this.fillJDOMElement (root); - - Element about = new Element (XMLConstants.about); - about.addContent (this.about); - - root.addContent (about); - - return root; - - } - - public void setAvatarImageFileType (String t) - { - - this.avatarImageFileType = t; - - } - - public String getAvatarImageFileType () - { - - return this.avatarImageFileType; - - } - - public DataSource getAvatar () - { - - return this.avatar; - - } - - public void setAvatar (DataSource ds) - { - - this.avatar = ds; - - } - /* - public File getAvatarImage () - { - - return Environment.getEditorsAuthorAvatarImageFile (); - - } - */ - public String getAbout () - { - - return this.about; - - } - - public void setAbout (String a) - { - - this.about = a; - - } - -} \ No newline at end of file diff --git a/src/com/quollwriter/data/editors/EditorEditor.java b/src/com/quollwriter/data/editors/EditorEditor.java deleted file mode 100644 index 6567ac99..00000000 --- a/src/com/quollwriter/data/editors/EditorEditor.java +++ /dev/null @@ -1,879 +0,0 @@ -package com.quollwriter.data.editors; - -import java.io.*; -import java.util.*; -import java.awt.image.*; - -import javax.activation.*; - -import org.jdom.*; - -import com.gentlyweb.xml.*; - -import org.bouncycastle.openpgp.*; -import org.bouncycastle.bcpg.*; - -import com.quollwriter.*; -import com.quollwriter.data.*; -import com.quollwriter.editors.messages.*; - -import static com.quollwriter.LanguageStrings.*; -import static com.quollwriter.Environment.getUIString; - -public class EditorEditor extends AbstractEditorObject -{ - - public enum OnlineStatus - { - - online ("online"), - busy ("busy"), - offline ("offline"), - away ("away"), - snooze ("snooze"); - - private String type = null; - - OnlineStatus (String type) - { - - this.type = type; - - } - - public String getType () - { - - return this.type; - - } - - public String getName () - { - - java.util.List prefix = Arrays.asList (editors,statuses); - - switch (this) - { - case online : return getUIString (prefix, LanguageStrings.online);//"Online"; - case offline : return getUIString (prefix, LanguageStrings.offline);//"Offline"; - case busy : return getUIString (prefix, LanguageStrings.busy);//"Busy"; - case away : return getUIString (prefix, LanguageStrings.away);//"Away"; - case snooze : return getUIString (prefix, LanguageStrings.snooze);//"Snooze"; - default : return "Unknown"; - - } - - } - - } - - public enum EditorStatus - { - - current ("current"), - previous ("previous"), - pending ("pending"), - pending_inviteaccepted ("pending_inviteaccepted"), - rejected ("rejected"); - - private String type = null; - - EditorStatus (String type) - { - - this.type = type; - - } - - public String getType () - { - - return this.type; - - } - - } - - public static final String OBJECT_TYPE = "editor"; - - public class XMLConstants - { - - public static final String root = "editor"; - public static final String about = "about"; - public static final String genres = "genres"; - public static final String wordCountLengths = "wordCountLengths"; - - } - - private String email = null; - private String about = null; - private Set wcLengths = null; - private Set genres = null; - private OnlineStatus status = null; - private EditorStatus editorStatus = EditorStatus.pending; - private Set messages = null; - //private DataSource avatar = null; - private BufferedImage avatar = null; - private String avatarImageFileType = null; - private boolean invitedByMe = false; - private PGPPublicKey theirPublicKey = null; - private boolean messagesLoaded = false; - private String myNameForEditor = null; - private BufferedImage myAvatarForEditor = null; - private String serviceName = null; - private String messagingUsername = null; - - public EditorEditor () - { - - super (OBJECT_TYPE); - - } - - public EditorEditor (String name, - String shortName, - BufferedImage avatar, - OnlineStatus status, - EditorStatus editorStatus) - { - - super (OBJECT_TYPE, - name); - - this.avatar = avatar; - this.status = status; - this.editorStatus = editorStatus; - - } - - public EditorEditor (Element root) - throws Exception - { - - super (root, - OBJECT_TYPE); - - this.about = JDOMUtils.getChildElementContent (root, - XMLConstants.about, - true); - - String genres = JDOMUtils.getAttributeValue (root, - XMLConstants.genres, - false); - - if (!genres.equals ("")) - { - - this.genres = new TreeSet (); - - StringTokenizer t = new StringTokenizer (genres, - ","); - - while (t.hasMoreTokens ()) - { - - this.genres.add (t.nextToken ().trim ()); - - } - - } - - String wcls = JDOMUtils.getAttributeValue (root, - XMLConstants.wordCountLengths, - false); - - if (!wcls.equals ("")) - { - - this.wcLengths = new TreeSet (); - - StringTokenizer t = new StringTokenizer (wcls, - ","); - - while (t.hasMoreTokens ()) - { - - this.wcLengths.add (EditorProject.WordCountLength.getWordCountLengthByType (t.nextToken ().trim ())); - - } - - } - - } - - @Override - public void fillToStringProperties (Map props) - { - - super.fillToStringProperties (props); - - this.addToStringProperties (props, - "email", - this.email); - this.addToStringProperties (props, - "onlineStatus", - (this.status != null ? this.status.getType () : "unknown")); - this.addToStringProperties (props, - "editorStatus", - this.editorStatus.getType ()); - this.addToStringProperties (props, - "serviceName", - this.serviceName); - this.addToStringProperties (props, - "messagingUsername", - this.messagingUsername); - this.addToStringProperties (props, - "hasPublicKey", - (this.theirPublicKey != null)); - this.addToStringProperties (props, - "invitedByMe", - this.invitedByMe); - this.addToStringProperties (props, - "messages", - (this.messages != null ? this.messages.size () : 0)); - this.addToStringProperties (props, - "myNameForEditor", - this.myNameForEditor); - this.addToStringProperties (props, - "hasMyAvatarForEditor", - (this.myAvatarForEditor != null)); - - } - - public String getMessagingUsername () - { - - return this.messagingUsername; - - } - - public void setMessagingUsername (String u) - { - - this.messagingUsername = u; - - } - - public String getServiceName () - { - - return this.serviceName; - - } - - public void setServiceName (String n) - { - - this.serviceName = n; - - } - - public String getMyNameForEditor () - { - - return this.myNameForEditor; - - } - - public void setMyNameForEditor (String n) - { - - this.myNameForEditor = n; - - } - /* - public void setMyPrivateKey (PGPPrivateKey k) - { - - this.myPrivateKey = k; - - } - */ - public BufferedImage getMainAvatar () - { - - if (this.myAvatarForEditor != null) - { - - return this.myAvatarForEditor; - - } - - return this.avatar; - - } - - public String getMainName () - { - - if (this.myNameForEditor != null) - { - - return this.myNameForEditor; - - } - - String n = super.getName (); - - if (n != null) - { - - return n; - - } - - return this.email; - - } - - public PGPPublicKey getTheirPublicKey () - { - - return this.theirPublicKey; - - } - - public void setTheirPublicKey (PGPPublicKey k) - { - - this.theirPublicKey = k; - - } - - public boolean isInvitedByMe () - { - - return this.invitedByMe; - - } - - public void setInvitedByMe (boolean v) - { - - this.invitedByMe = v; - - } - - public String getEmail () - { - - return this.email; - - } - - public void setEmail (String em) - { - - this.email = em; - - } - - public void setAvatarImageFileType (String t) - { - - this.avatarImageFileType = t; - - } - - public String getAvatarImageFileType () - { - - return this.avatarImageFileType; - - } - - public String getShortName () - { - - if (this.getMyNameForEditor () != null) - { - - return this.getMyNameForEditor (); - - } - - return this.getMainName (); - - } - - public void setEditorStatus (EditorStatus s) - { - - this.editorStatus = s; - - } - - public EditorStatus getEditorStatus () - { - - return this.editorStatus; - - } - - /** - * Do we have an editor-info message sent by the editor? - * We can't assume that the messages have been loaded here. - * - * @return true If the info has been sent/recevied. - */ - public boolean hasSentInfo () - { - - if (this.messages == null) - { - - // This is kind of a false positive since we aren't querying the live db. - return false; - - } - - for (EditorMessage m : this.messages) - { - - if ((m instanceof EditorInfoMessage) - && - (!m.isSentByMe ()) - ) - { - - // It doesn't matter how many times it has been sent. - return true; - - } - - } - - return false; - - } - - public void setOnlineStatus (OnlineStatus status) - { - - this.status = status; - - } - - public OnlineStatus getOnlineStatus () - { - - return this.status; - - } - - public boolean messagesLoaded () - { - - return this.messagesLoaded; - - } - - public void removeMessage (EditorMessage m) - { - - if (this.messages == null) - { - - return; - - } - - this.messages.remove (m); - - } - - public void setMessages (Set messages) - { - - this.messages = messages; - - this.messagesLoaded = (messages != null); - - } - - public void addMessage (EditorMessage m) - { - - if (this.messagesLoaded) - { - - this.messages.add (m); - - } - - } - - /** - * Get all the messages for the specified accept types (message types). - * - * @param acceptTypes The types of messages we are looking for. - * @param projId Limit to the specified project, if provided. - * @return The matched messages in date created order, or null if no messages match. - */ - public SortedSet getMessages (String projId, - String... acceptTypes) - { - - Set mess = this.getMessages (new DefaultEditorMessageFilter (projId, - acceptTypes)); - - if (mess == null) - { - - return null; - - } - - SortedSet ss = new TreeSet (new Comparator () - { - - @Override - public int compare (EditorMessage m1, - EditorMessage m2) - { - - return m1.getWhen ().compareTo (m2.getWhen ()); - - } - - @Override - public boolean equals (Object o) - { - - return super.equals (o); - - } - - }); - - ss.addAll (mess); - - return ss; - - - } - - public Set getMessages (EditorMessageFilter filter) - { - - Set ret = new LinkedHashSet (); - - if ((this.messages == null) - || - (!this.messagesLoaded) - ) - { - - return ret; - - } - - for (EditorMessage m : this.messages) - { - - if (filter.accept (m)) - { - - ret.add (m); - - } - - } - - return ret; - - } - - public EditorMessage getMessage (String type, - Project forProject) - { - - if ((this.messages == null) - || - (!this.messagesLoaded) - || - (forProject == null) - ) - { - - return null; - - } - - return this.getMessage (type, - forProject.getId ()); - - } - - public EditorMessage getMessage (String type, - String forProjectId) - { - - if ((this.messages == null) - || - (!this.messagesLoaded) - ) - { - - return null; - - } - - for (EditorMessage m : this.messages) - { - - if (m.getMessageType ().equals (type)) - { - - if (m.getForProjectId ().equals (forProjectId)) - { - - return m; - - } - - } - - } - - return null; - - } - - public Set getMessages () - { - - return this.messages; - - } - - public void setWordCountLengths (Set wcs) - { - - this.wcLengths = wcs; - - } - - public Set getWordCountLengths () - { - - return this.wcLengths; - - } - - public Set getGenres () - { - - return this.genres; - - } - - public void setGenres (Set s) - { - - this.genres = s; - - } - - public Element getAsJDOMElement () - { - - Element root = new Element (XMLConstants.root); - - this.fillJDOMElement (root); - - Element about = new Element (XMLConstants.about); - about.addContent (this.about); - - root.addContent (about); - - if (this.genres != null) - { - - String gs = Utils.toString (this.genres, - ","); - - if (gs.length () > 0) - { - - root.setAttribute (XMLConstants.genres, - gs); - - } - - } - - if (this.wcLengths != null) - { - - String wcs = Utils.toString (this.wcLengths, - ","); - - if (wcs.length () > 0) - { - - root.setAttribute (XMLConstants.wordCountLengths, - wcs); - - } - - } - - return root; - - } -/* - public String getAvatarImageFileType () - { - - return this.avatarImageFileType; - - } - */ - - public boolean isPending () - { - - if (this.editorStatus == null) - { - - return false; - - } - - return this.editorStatus == EditorStatus.pending; - - } - - public boolean isPrevious () - { - - if (this.editorStatus == null) - { - - return false; - - } - - return this.editorStatus == EditorStatus.previous; - - } - - public boolean isRejected () - { - - if (this.editorStatus == null) - { - - return false; - - } - - return this.editorStatus == EditorStatus.rejected; - - } - - public boolean isCurrent () - { - - if (this.editorStatus == null) - { - - return false; - - } - - return this.editorStatus == EditorStatus.current; - - } - - public boolean isOffline () - { - - if (this.status == null) - { - - return true; - - } - - return this.status == OnlineStatus.offline; - - } - -/* - public DataSource getAvatar () - { - - return this.avatar; - - } - - public void setAvatar (DataSource ds) - { - - this.avatar = ds; - - } - */ - - public BufferedImage getDisplayAvatar () - { - - return (this.myAvatarForEditor != null ? this.myAvatarForEditor : this.avatar); - - } - - public void setAvatar (BufferedImage im) - { - - this.avatar = im; - - } - - public BufferedImage getAvatar () - { - - return this.avatar; - - } - - public void setMyAvatarForEditor (BufferedImage im) - { - - this.myAvatarForEditor = im; - - } - - public BufferedImage getMyAvatarForEditor () - { - - return this.myAvatarForEditor; - - } - - /* - public File getAvatarImage () - { - - return Environment.getEditorsEditorAvatarImageFile (); - - } - */ - public String getAbout () - { - - return this.about; - - } - - public void setAbout (String a) - { - - this.about = a; - - } - -} diff --git a/src/com/quollwriter/data/editors/ProjectEditor.java b/src/com/quollwriter/data/editors/ProjectEditor.java deleted file mode 100644 index caccc5f7..00000000 --- a/src/com/quollwriter/data/editors/ProjectEditor.java +++ /dev/null @@ -1,244 +0,0 @@ -package com.quollwriter.data.editors; - -import java.util.*; - -import com.quollwriter.data.*; - -/** - * Models an editor for a project. - */ -public class ProjectEditor extends DataObject implements Comparable -{ - - public static final String OBJECT_TYPE = "projecteditor"; - - public enum Status - { - - invited ("invited"), - accepted ("accepted"); - - private String type = null; - - Status (String type) - { - - this.type = type; - - } - - public String getType () - { - - return this.type; - - } - - } - - protected EditorEditor editor = null; - private String forProjectId = null; - private String forProjectName = null; - private Status status = null; - private String statusMessage = null; - private boolean current = false; - private Date from = null; - private Date to = null; - - public ProjectEditor () - { - - super (OBJECT_TYPE); - - } - - public ProjectEditor (Project proj, - EditorEditor editor) - { - - super (OBJECT_TYPE); - - this.forProjectId = proj.getId (); - this.forProjectName = proj.getName (); - this.editor = editor; - - } - - @Override - public void fillToStringProperties (Map props) - { - - super.fillToStringProperties (props); - - this.addToStringProperties (props, - "forProjectId", - this.forProjectId); - this.addToStringProperties (props, - "forProjectName", - this.forProjectName); - this.addToStringProperties (props, - "editor", - this.editor); - this.addToStringProperties (props, - "current", - this.current); - this.addToStringProperties (props, - "statusMessage", - this.statusMessage); - this.addToStringProperties (props, - "from", - this.from); - this.addToStringProperties (props, - "to", - this.to); - - } - - public int compareTo (ProjectEditor pe) - { - - return this.editor.getMainName ().compareTo (pe.editor.getMainName ()); - - } - - public boolean isPrevious () - { - - return this.to != null; - - } - - public boolean isInvited () - { - - if (this.status == null) - { - - return true; - - } - - return this.status == Status.invited; - - } - - public Status getStatus () - { - - return this.status; - - } - - public void setStatus (Status s) - { - - this.status = s; - - } - - public void setForProjectName (String n) - { - - this.forProjectName = n; - - } - - public String getForProjectName () - { - - return this.forProjectName; - - } - - public DataObject getObjectForReference (ObjectReference r) - { - - return null; - - } - - public void setForProjectId (String id) - { - - this.forProjectId = id; - - } - - public String getForProjectId () - { - - return this.forProjectId; - - } - - public void setCurrent (boolean v) - { - - this.current = v; - - } - - public boolean isCurrent () - { - - return this.current; - - } - - public void setEditorTo (Date d) - { - - this.to = d; - - } - - public Date getEditorTo () - { - - return this.to; - - } - - public void setEditorFrom (Date d) - { - - this.from = d; - - } - - public Date getEditorFrom () - { - - return this.from; - - } - - public void setStatusMessage (String s) - { - - this.statusMessage = s; - - } - - public String getStatusMessage () - { - - return this.statusMessage; - - } - - public void setEditor (EditorEditor ed) - { - - this.editor = ed; - - } - - public EditorEditor getEditor () - { - - return this.editor; - - } - -} \ No newline at end of file diff --git a/src/com/quollwriter/db/LinkDataHandler.java b/src/com/quollwriter/db/LinkDataHandler.java deleted file mode 100644 index 4bf0ca41..00000000 --- a/src/com/quollwriter/db/LinkDataHandler.java +++ /dev/null @@ -1,94 +0,0 @@ -package com.quollwriter.db; - -import java.sql.*; - -import java.util.*; - -import com.quollwriter.*; - -import com.quollwriter.data.*; - - -public class LinkDataHandler implements DataHandler -{ - - private ObjectManager objectManager = null; - - public LinkDataHandler(ObjectManager om) - { - - this.objectManager = om; - - } - - @Override - public List getObjects (NamedObject parent, - Connection conn, - boolean loadChildObjects) - throws GeneralException - { - - throw new UnsupportedOperationException ("Not supported"); - - } - - @Override - public Link getObjectByKey (long key, - NamedObject parent, - Connection conn, - boolean loadChildObjects) - throws GeneralException - { - - throw new UnsupportedOperationException ("Not supported"); - - } - - @Override - public void createObject (Link l, - Connection conn) - throws GeneralException - { - - // Check to see if it already exists. ??? - - List params = new ArrayList (); - params.add (l.getKey ()); - params.add (l.getObject1 ().getKey ()); - params.add (l.getObject1 ().getObjectType ()); - params.add (l.getObject2 ().getKey ()); - params.add (l.getObject2 ().getObjectType ()); - - this.objectManager.executeStatement ("INSERT INTO link (dbkey, object1dbkey, object1objtype, object2dbkey, object2objtype) VALUES (?, ?, ?, ?, ?)", - params, - conn); - - } - - @Override - public void deleteObject (Link d, - boolean deleteChildObjects, - Connection conn) - throws GeneralException - { - - List params = new ArrayList (); - params.add (d.getKey ()); - - this.objectManager.executeStatement ("DELETE FROM link WHERE dbkey = ?", - params, - conn); - - } - - @Override - public void updateObject (Link l, - Connection conn) - throws GeneralException - { - - throw new UnsupportedOperationException ("Not supported"); - - } - -} diff --git a/src/com/quollwriter/db/ProjectEditorDataHandler.java b/src/com/quollwriter/db/ProjectEditorDataHandler.java deleted file mode 100644 index bc3744b1..00000000 --- a/src/com/quollwriter/db/ProjectEditorDataHandler.java +++ /dev/null @@ -1,295 +0,0 @@ -package com.quollwriter.db; - -import java.sql.*; -import java.io.*; -import java.util.*; - -import java.math.*; -import javax.crypto.*; -import java.security.*; - -import org.bouncycastle.bcpg.*; -import org.bouncycastle.openpgp.*; -import org.bouncycastle.crypto.generators.*; -import org.bouncycastle.crypto.params.*; -import org.bouncycastle.openpgp.operator.bc.*; - -import com.quollwriter.*; - -import com.quollwriter.data.*; -import com.quollwriter.data.editors.*; -import com.quollwriter.editors.*; -import com.quollwriter.editors.messages.*; - -public class ProjectEditorDataHandler implements DataHandler -{ - - private static final String STD_SELECT_PREFIX = "SELECT dbkey, editordbkey, forprojectid, forprojectname, status, statusmessage, current, editorfrom, editorto FROM projecteditor_v"; - - private ObjectManager objectManager = null; - - /** - * A cache, since the same projEditor can be viewed in multiple places and updated in multiple places - * we need a single object for the editor so that we have one object -> multiple viewers. - */ - private Map cache = new HashMap (); - - public ProjectEditorDataHandler (ObjectManager om) - { - - this.objectManager = om; - - } - - @Override - public void createObject (ProjectEditor pe, - Connection conn) - throws GeneralException - { - - if (pe.getForProjectId () == null) - { - - throw new GeneralException ("No for project id specified."); - - } - - if (pe.getEditor () == null) - { - - throw new GeneralException ("No editor is specified."); - - } - - List params = new ArrayList (); - params.add (pe.getKey ()); - params.add (pe.getEditor ().getKey ()); - params.add (pe.getForProjectId ()); - params.add (pe.getForProjectName ()); - params.add (pe.getStatus ().getType ()); - params.add (pe.getStatusMessage ()); - params.add (pe.isCurrent ()); - params.add ((pe.getEditorFrom () != null ? pe.getEditorFrom () : new java.util.Date ())); - params.add (pe.getEditorTo ()); - - this.objectManager.executeStatement ("INSERT INTO projecteditor " + - "(dbkey, " + - " editordbkey, " + - " forprojectid, " + - " forprojectname, " + - " status, " + - " statusmessage, " + - " current, " + - " editorfrom, " + - " editorto) " + - "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)", - params, - conn); - - this.cache.put (pe.getKey (), - pe); - - } - - @Override - public void deleteObject (ProjectEditor d, - boolean deleteChildObjects, - Connection conn) - throws GeneralException - { - - List params = new ArrayList (); - params.add (d.getKey ()); - - this.objectManager.executeStatement ("DELETE FROM projecteditor WHERE dbkey = ?", - params, - conn); - - this.cache.remove (d.getKey ()); - - } - - @Override - public void updateObject (ProjectEditor pe, - Connection conn) - throws GeneralException - { - - List params = new ArrayList (); - - params.add (pe.getForProjectName ()); - params.add (pe.getStatus ().getType ()); - params.add (pe.getStatusMessage ()); - params.add (pe.isCurrent ()); - params.add (pe.getEditorFrom ()); - params.add (pe.getEditorTo ()); - params.add (pe.getKey ()); - - this.objectManager.executeStatement ("UPDATE projecteditor " + - "SET forprojectname = ?, " + - " status = ?, " + - " statusmessage = ?, " + - " current = ?, " + - " editorfrom = ?, " + - " editorto = ? " + - "WHERE dbkey = ?", - params, - conn); - - } - - @Override - public List getObjects (ProjectInfo p, - Connection conn, - boolean loadChildObjects) - throws GeneralException - { - - List ret = new ArrayList (); - - ResultSet rs = null; - - try - { - - List params = new ArrayList (); - params.add (p.getId ()); - - rs = this.objectManager.executeQuery (STD_SELECT_PREFIX + " WHERE forprojectid = ? ORDER BY editorfrom", - params, - conn); - - while (rs.next ()) - { - - ret.add (this.getProjectEditor (rs)); - - } - - } catch (Exception e) { - - throw new GeneralException ("Unable to load project editors for: " + - p, - e); - - } finally { - - try - { - - rs.close (); - - } catch (Exception e) - { - - } - - } - - return ret; - - } - - private ProjectEditor getProjectEditor (ResultSet rs) - throws GeneralException - { - - try - { - - int ind = 1; - - long key = rs.getLong (ind++); - - ProjectEditor pe = this.cache.get (key); - - if (pe != null) - { - - return pe; - - } - - pe = new ProjectEditor (); - - long edKey = rs.getLong (ind++); - - EditorEditor ed = EditorsEnvironment.getEditorByKey (edKey); - - pe.setKey (key); - pe.setEditor (ed); - pe.setForProjectId (rs.getString (ind++)); - pe.setForProjectName (rs.getString (ind++)); - pe.setStatus (ProjectEditor.Status.valueOf (rs.getString (ind++))); - pe.setStatusMessage (rs.getString (ind++)); - pe.setCurrent (rs.getBoolean (ind++)); - pe.setEditorFrom (rs.getTimestamp (ind++)); - pe.setEditorTo (rs.getTimestamp (ind++)); - - this.cache.put (key, - pe); - - return pe; - - } catch (Exception e) - { - - throw new GeneralException ("Unable to load project editor", - e); - - } - - } - - @Override - public ProjectEditor getObjectByKey (long key, - ProjectInfo p, - Connection conn, - boolean loadChildObjects) - throws GeneralException - { - - ResultSet rs = null; - - try - { - - List params = new ArrayList (); - params.add (key); - - rs = this.objectManager.executeQuery (STD_SELECT_PREFIX + " WHERE dbkey = ?", - params, - conn); - - if (rs.next ()) - { - - return this.getProjectEditor (rs); - - } - - return null; - - } catch (Exception e) { - - throw new GeneralException ("Unable to get project editor with key: " + - key, - e); - - } finally { - - try - { - - rs.close (); - - } catch (Exception e) - { - - } - - } - - } - -} diff --git a/src/com/quollwriter/db/UserConfigurableObjectTypeDataHandler.java b/src/com/quollwriter/db/UserConfigurableObjectTypeDataHandler.java deleted file mode 100644 index 999e2952..00000000 --- a/src/com/quollwriter/db/UserConfigurableObjectTypeDataHandler.java +++ /dev/null @@ -1,316 +0,0 @@ -package com.quollwriter.db; - -import java.sql.*; -import java.awt.event.*; -import javax.swing.*; - -import java.util.*; - -import com.gentlyweb.utils.*; - -import com.quollwriter.*; - -import com.quollwriter.ui.*; -import com.quollwriter.data.*; - -public class UserConfigurableObjectTypeDataHandler implements DataHandler -{ - - private static final String STD_SELECT_PREFIX = "SELECT dbkey, userobjtype, name, pluralname, description, markup, icon24x24, icon16x16, layout, assetobjtype, createshortcutkey, lastmodified, datecreated, properties, id, version FROM userobjecttype_v "; - - private ObjectManager objectManager = null; - - /** - * A cache, since the same type can be used in multiple places - * we need a single object so that we have one object -> multiple uses. - */ - private Map cache = new HashMap (); - - public UserConfigurableObjectTypeDataHandler (ObjectManager om) - { - - this.objectManager = om; - - } - - private UserConfigurableObjectType getUserConfigurableObjectType (ResultSet rs, - NamedObject parent, - boolean loadChildObjects) - throws GeneralException - { - - try - { - - int ind = 1; - - long key = rs.getLong (ind++); - - UserConfigurableObjectType t = this.cache.get (key); - - if (t != null) - { - - return t; - - } - - t = new UserConfigurableObjectType (); - t.setKey (key); - t.setUserObjectType (rs.getString (ind++)); - t.setName (rs.getString (ind++)); - t.setObjectTypeName (t.getName ()); - t.setObjectTypeNamePlural (rs.getString (ind++)); - t.setDescription (new StringWithMarkup (rs.getString (ind++), - rs.getString (ind++))); - - t.setIcon24x24 (new ImageIcon (UIUtils.getImage (rs.getBytes (ind++)))); - t.setIcon16x16 (new ImageIcon (UIUtils.getImage (rs.getBytes (ind++)))); - t.setLayout (rs.getString (ind++)); - t.setAssetObjectType (rs.getBoolean (ind++)); - t.setCreateShortcutKeyStroke (KeyStroke.getKeyStroke (rs.getString (ind++))); - t.setLastModified (rs.getTimestamp (ind++)); - t.setDateCreated (rs.getTimestamp (ind++)); - t.setPropertiesAsString (rs.getString (ind++)); - t.setId (rs.getString (ind++)); - t.setVersion (rs.getString (ind++)); - - Connection conn = rs.getStatement ().getConnection (); - - this.objectManager.getObjects (UserConfigurableObjectTypeField.class, - t, - conn, - true); - - Environment.addUserConfigurableObjectType (t); - - this.cache.put (key, - t); - - return t; - - } catch (Exception e) - { - - throw new GeneralException ("Unable to load user configurable object type", - e); - - } - - } - - public List getObjects (NamedObject parent, - Connection conn, - boolean loadChildObjects) - throws GeneralException - { - - List ret = new ArrayList (); - - try - { - - List params = new ArrayList (); - - ResultSet rs = this.objectManager.executeQuery (STD_SELECT_PREFIX + " WHERE latest = TRUE", - params, - conn); - - while (rs.next ()) - { - - ret.add (this.getUserConfigurableObjectType (rs, - parent, - loadChildObjects)); - - } - - try - { - - rs.close (); - - } catch (Exception e) - { - } - - } catch (Exception e) - { - - throw new GeneralException ("Unable to load user configurable object types for: " + - parent, - e); - - } - - return ret; - - } - - public UserConfigurableObjectType getObjectByKey (long key, - NamedObject parent, - Connection conn, - boolean loadChildObjects) - throws GeneralException - { - - UserConfigurableObjectType t = null; - - try - { - - List params = new ArrayList (); - params.add (key); - - ResultSet rs = this.objectManager.executeQuery (STD_SELECT_PREFIX + " WHERE latest = TRUE AND dbkey = ?", - params, - conn); - - if (rs.next ()) - { - - t = this.getUserConfigurableObjectType (rs, - parent, - loadChildObjects); - - } - - try - { - - rs.close (); - - } catch (Exception e) - { - } - - } catch (Exception e) - { - - throw new GeneralException ("Unable to load user configurable object type for key: " + - key, - e); - - } - - return t; - - } - - public void createObject (UserConfigurableObjectType t, - Connection conn) - throws GeneralException - { - - List params = new ArrayList (); - params.add (t.getKey ()); - params.add (t.getUserObjectType ()); - params.add (t.getActualObjectTypeNamePlural ()); - params.add (UIUtils.getImageBytes (UIUtils.iconToImage (t.getIcon24x24 ()))); - params.add (UIUtils.getImageBytes (UIUtils.iconToImage (t.getIcon16x16 ()))); - params.add (t.getLayout ()); - params.add (t.isAssetObjectType ()); - params.add (Utils.keyStrokeToString (t.getCreateShortcutKeyStroke ())); - - this.objectManager.executeStatement ("INSERT INTO userobjecttype (dbkey, userobjtype, pluralname, icon24x24, icon16x16, layout, assetobjtype, createshortcutkey) VALUES (?, ?, ?, ?, ?, ?, ?, ?)", - params, - conn); - - // Save the fields. - this.objectManager.saveObjects (t.getConfigurableFields (), - conn); - - } - - public void deleteObject (UserConfigurableObjectType t, - boolean deleteChildObjects, - Connection conn) - throws GeneralException - { - - // Delete the fields first. - this.objectManager.deleteObjects (t.getConfigurableFields (), - conn); - - List params = new ArrayList (); - params.add (t.getKey ()); - - this.objectManager.executeStatement ("DELETE FROM userobjecttype WHERE dbkey = ?", - params, - conn); - - } - - public void updateObject (UserConfigurableObjectType t, - Connection conn) - throws GeneralException - { - - List params = new ArrayList (); - params.add (t.getActualObjectTypeNamePlural ()); - params.add (UIUtils.getImageBytes (UIUtils.iconToImage (t.getIcon24x24 ()))); - params.add (UIUtils.getImageBytes (UIUtils.iconToImage (t.getIcon16x16 ()))); - params.add (t.getLayout ()); - params.add (Utils.keyStrokeToString (t.getCreateShortcutKeyStroke ())); - params.add (t.getKey ()); - - this.objectManager.executeStatement ("UPDATE userobjecttype SET pluralname = ?, icon24x24 = ?, icon16x16 = ?, layout = ?, createshortcutkey = ? WHERE dbkey = ?", - params, - conn); - - // Save the fields. - this.objectManager.saveObjects (t.getConfigurableFields (), - conn); - - } - - public void updateFieldOrdering (UserConfigurableObjectType t) - throws GeneralException - { - - Connection conn = null; - - try - { - - conn = this.objectManager.getConnection (); - - List params = new ArrayList (); - params.add (t.getKey ()); - - this.objectManager.executeStatement ("UPDATE userobjecttypefield SET orderby = NULL WHERE userobjecttypedbkey = ?", - params, - conn); - - for (UserConfigurableObjectTypeField f : t.getConfigurableFields ()) - { - - params = new ArrayList (); - - params.add (f.getOrder ()); - params.add (f.getKey ()); - params.add (t.getKey ()); - - this.objectManager.executeStatement ("UPDATE userobjecttypefield SET orderby = ? WHERE dbkey = ? AND userobjecttypedbkey = ?", - params, - conn); - - } - - } catch (Exception e) { - - this.objectManager.throwException (conn, - "Unable to update field orderbys for type: " + - t.getKey (), - e); - - } finally { - - this.objectManager.releaseConnection (conn); - - - } - - } - -} diff --git a/src/com/quollwriter/editors/DefaultEditorMessageProcessor.java b/src/com/quollwriter/editors/DefaultEditorMessageProcessor.java deleted file mode 100644 index 66abab4b..00000000 --- a/src/com/quollwriter/editors/DefaultEditorMessageProcessor.java +++ /dev/null @@ -1,945 +0,0 @@ -package com.quollwriter.editors; - -import java.awt.event.*; -import java.awt.image.*; - -import java.util.Set; -import java.util.HashSet; -import java.util.Date; - -import org.bouncycastle.openpgp.*; - -import com.quollwriter.data.editors.*; -import com.quollwriter.data.*; -import com.quollwriter.editors.ui.*; -import com.quollwriter.ui.*; -import com.quollwriter.editors.messages.*; -import com.quollwriter.*; - -import static com.quollwriter.LanguageStrings.*; -import static com.quollwriter.Environment.getUIString; - -public class DefaultEditorMessageProcessor implements EditorMessageProcessor -{ - - public boolean processMessage (final EditorMessage mess) - throws Exception - { - - boolean showPopup = EditorsEnvironment.isShowPopupWhenNewMessageReceived (); - - EditorEditor ed = mess.getEditor (); - - if (mess instanceof EditorInfoMessage) - { - - return this.handleEditorInfoMessage ((EditorInfoMessage) mess, - ed, - showPopup); - - } - - if (mess instanceof EditorChatMessage) - { - - return this.handleChatMessage ((EditorChatMessage) mess, - ed, - showPopup); - - } - - if (mess instanceof InviteMessage) - { - - return this.handleInviteMessage ((InviteMessage) mess, - ed, - showPopup); - - } - - if (mess instanceof InviteResponseMessage) - { - - return this.handleInviteResponseMessage ((InviteResponseMessage) mess, - ed, - showPopup); - - } - - if (mess instanceof NewProjectMessage) - { - - return this.handleNewProjectMessage ((NewProjectMessage) mess, - ed, - showPopup); - - } - - if (mess instanceof NewProjectResponseMessage) - { - - return this.handleNewProjectResponseMessage ((NewProjectResponseMessage) mess, - ed, - showPopup); - - } - - if (mess instanceof UpdateProjectMessage) - { - - return this.handleUpdateProjectMessage ((UpdateProjectMessage) mess, - ed, - showPopup); - - } - - if (mess instanceof ProjectCommentsMessage) - { - - return this.handleProjectCommentsMessage ((ProjectCommentsMessage) mess, - ed, - showPopup); - - } - - if (mess instanceof EditorRemovedMessage) - { - - return this.handleEditorRemovedMessage ((EditorRemovedMessage) mess, - ed, - showPopup); - - } - - if (mess instanceof ProjectEditStopMessage) - { - - return this.handleProjectEditStopMessage ((ProjectEditStopMessage) mess, - ed, - showPopup); - - } - - if (mess instanceof InteractionMessage) - { - - return this.handleInteractionMessage ((InteractionMessage) mess, - ed, - showPopup); - - } - - if (mess instanceof ErrorMessage) - { - - return this.handleErrorMessage ((ErrorMessage) mess, - ed, - showPopup); - - } - - return false; - - } - - private boolean handleInteractionMessage (InteractionMessage im, - EditorEditor ed, - boolean showPopup) - throws Exception - { - - EditorsEnvironment.fireEditorInteractionEvent (im.getEditor (), - im.getAction ()); - - // Fire a status update. - return false; - - } - - private boolean handleEditorRemovedMessage (EditorRemovedMessage mess, - EditorEditor ed, - boolean showPopup) - throws Exception - { - - // Unsubscribe. - EditorsEnvironment.getMessageHandler ().unsubscribeFromEditor (ed); -/* - if (showPopup) - { - - AbstractViewer viewer = Environment.getFocusedViewer (); - - mess.setDealtWith (true); - - UIUtils.showMessage ((PopupsSupported) viewer, - "You have been removed as {an editor}", - String.format ("%s has removed you as {an editor}.

    Note you will no longer be able to send them messages and/or {projects}.", - mess.getEditor ().getShortName ())); - - } -*/ - return true; - - } - - private boolean handleProjectEditStopMessage (ProjectEditStopMessage mess, - EditorEditor ed, - boolean showPopup) - throws Exception - { - - if (ed.isPending ()) - { - - // TODO: Make this nicer, maybe set new project response message to dealt with? - - // This is the rare case where someone has been invited, they accepted the project then deleted it - // before the user could find out. - - // Get the NewProjectResponseMessage and set it as dealt with so the user doesn't have to bother with it. - - } - -/* - Project p = Environment.getProjectById (mess.getForProjectId (), - Project.NORMAL_PROJECT_TYPE); - - ProjectEditor pe = EditorsEnvironment.getProjectEditor (p, - mess.getEditor ()); - - pe.setCurrent (false); - pe.setEditorTo (new Date ()); - pe.setStatusMessage (String.format ("Stopped editing: %s", - Environment.formatDate (pe.getEditorTo ()))); - - EditorsEnvironment.updateProjectEditor (pe); -*/ -/* - if (showPopup) - { - - AbstractViewer viewer = Environment.getFocusedViewer (); - - UIUtils.showMessage ((PopupsSupported) viewer, - "An {editor} has stopped editing your {project}", - String.format ("%s has decided to stop editing %s.", - mess.getEditor ().getShortName (), - mess.getForProjectName ())); - - mess.setDealtWith (true); - - } -*/ - return true; - - } - - private boolean handleProjectCommentsMessage (final ProjectCommentsMessage mess, - final EditorEditor ed, - final boolean showPopup) - throws Exception - { - - String projId = mess.getForProjectId (); - - ProjectInfo proj = null; - - try - { - - proj = Environment.getProjectById (projId, - Project.NORMAL_PROJECT_TYPE); - - } catch (Exception e) { - - throw new GeneralException ("Unable to get project for id: " + - projId, - e); - - } - - ProjectEditor pe = EditorsEnvironment.getProjectEditor (proj, - ed); - - if (pe == null) - { - - throw new IllegalArgumentException ("Editor is not a project editor for project: " + projId + ", editor: " + ed); - - } - - // It may be that we get some comments before the user acknowledged the editor's acceptance of the - // project. In which case we need to update the project editor to current. - if (pe.isInvited ()) - { - - pe.setEditorFrom (mess.getWhen ()); - pe.setCurrent (true); - - pe.setStatus (ProjectEditor.Status.accepted); - - } - - int c = mess.getComments ().size (); - - pe.setStatusMessage (String.format (getUIString (editors,user,commentsreceived,editorstatus), - //"Received %s {comment%s}: %s", - Environment.formatNumber (c), - Environment.formatDate (mess.getWhen ()))); - - EditorsEnvironment.updateProjectEditor (pe); -/* - if (showPopup) - { - - AbstractViewer viewer = Environment.getFocusedViewer (); - - UIUtils.createQuestionPopup (viewer, - "{Comments} received about a {project}", - Constants.COMMENT_ICON_NAME, - String.format ("%s has sent %s {comments} about version %s of your {project} %s.

    Would you like to view the {comments} now?", - mess.getEditor ().getShortName (), - mess.getForProjectName ()), - "Yes, show me them", - "No, I'll do it later", - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - AbstractViewer viewer = Environment.getFocusedViewer (); - - EditorsUIUtils.showProjectComments (mess, - viewer, - null); - - } - - }, - null, - null, - null); - - mess.setDealtWith (true); - - } -*/ - return true; - - } - - private boolean handleInviteMessage (final InviteMessage inv, - final EditorEditor ed, - final boolean showPopup) - throws Exception - { - - ed.setName (inv.getEditorName ()); - ed.setAvatar (inv.getEditorAvatar ()); - - // TODO: Need a nicer way of doing this. - if (ed.getKey () != null) - { - - EditorsEnvironment.updateEditor (ed); - - } else { - - EditorsEnvironment.addNewEditor (ed); - - } -/* - if (!showPopup) - { - - return true; - - } - - ActionListener onAccept = new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - try - { - - EditorsEnvironment.addMessage (inv); - - } catch (Exception e) { - - Environment.logError ("Unable to save message for editor: " + - ed, - e); - - return; - - } - - InviteResponseMessage rm = new InviteResponseMessage (true, - EditorsEnvironment.getUserAccount ()); - rm.setEditor (ed); - - EditorsEnvironment.acceptInvite (ed, - rm, - null); - - } - - }; - - ActionListener onReject = new ActionListener () - { - - // Rejects, so update and ignore the message. - public void actionPerformed (ActionEvent ev) - { - - InviteResponseMessage rm = new InviteResponseMessage (false, - EditorsEnvironment.getUserAccount ()); - rm.setEditor (ed); - - EditorsEnvironment.rejectInvite (ed, - rm, - null); - - } - - }; - - // Pending, user needs to respond. - EditorsUIUtils.showInviteFromEditor ((ed.getName () != null ? String.format ("%s (%s)", - ed.getName (), - ed.getEmail ()) : ed.getMainName ()), - onAccept, - onReject); -*/ - return true; - - } - - private boolean handleInviteResponseMessage (InviteResponseMessage rm, - EditorEditor ed, - boolean showPopup) - throws Exception - { - - if (ed.getEditorStatus () != EditorEditor.EditorStatus.pending) - { - - // Actually an error, but probably ok to just ignore? - Environment.logError ("Invalid statue, received invite response message from editor: " + - ed); - - return false; - - } - - if (rm.isAccepted ()) - { - - EditorsEnvironment.getMessageHandler ().subscribeToEditor (ed); - - } - - /* - // Show the response. - rm.setDealtWith (true); - - if (rm.isAccepted ()) - { - - // Show the acceptance. - // Set the editor as current. - ed.setEditorStatus (EditorEditor.EditorStatus.current); - - EditorsEnvironment.getMessageHandler ().subscribeToEditor (ed); - - if (rm.getEditorName () != null) - { - - ed.setName (rm.getEditorName ()); - - } - - if (rm.getEditorAvatar () != null) - { - - ed.setAvatar (rm.getEditorAvatar ()); - - } - - EditorsEnvironment.updateEditor (ed); - - // Is this response for an invite message or just out of the blue from a web service invite? - if (!EditorsEnvironment.hasSentMessageOfTypeToEditor (ed, - InviteMessage.MESSAGE_TYPE)) - { - - EditorsEnvironment.sendUserInformationToEditor (ed, - null, - null, - null); - - } - - if (showPopup) - { - - EditorsUIUtils.showInviteAcceptance (ed); - - } - - } else { - - ed.setEditorStatus (EditorEditor.EditorStatus.rejected); - - EditorsEnvironment.updateEditor (ed); - - if (showPopup) - { - - EditorsUIUtils.showInviteRejection (ed); - - } - - } - */ - return true; - - } - - private boolean handleErrorMessage (ErrorMessage error, - EditorEditor ed, - boolean showPopup) - throws Exception - { - - // Check the type and decide what to do... - if (error.getErrorType () == ErrorMessage.ErrorType.projectnotexists) - { - - // Eerk! - - } - - return false; - - } - - private boolean handleEditorInfoMessage (EditorInfoMessage info, - EditorEditor ed, - boolean showPopup) - throws Exception - { - - // Check to see if this is the first time that the editor has sent this info, if so - // then just update don't prompt. - // Need a better way of doing this, save me Hibernate! - /* - boolean hasSentInfo = false; - - try - { - - hasSentInfo = EditorsEnvironment.hasEditorSentInfo (ed); - - } catch (Exception e) { - - Environment.logError ("Unable to check if editor has sent info: " + ed, - e); - - return true; - - } - */ - /* - if (hasSentInfo) - { - - if (showPopup) - { - - EditorsUIUtils.showEditorInfoReceived (info); - - } - - } else { - - // Just update the info. - String newName = info.getName (); - - if (newName != null) - { - - ed.setName (newName.trim ()); - - } - - java.awt.image.BufferedImage newImage = info.getAvatar (); - - if (newImage != null) - { - - ed.setAvatar (newImage); - - } - - info.setDealtWith (true); - - try - { - - EditorsEnvironment.updateEditor (ed); - - } catch (Exception e) { - - Environment.logError ("Unable to update editor: " + ed, - e); - - } - - } - */ - return true; - - } - - private boolean handleChatMessage (EditorChatMessage mess, - EditorEditor ed, - boolean showPopup) - throws Exception - { - -/* - // Show a notification then inform our listeners. - if (showPopup) - { - - mess.setDealtWith (true); - - EditorsUIUtils.showNewEditorChatMessageNotification ((EditorChatMessage) mess); - - } -*/ - return true; - - } - - private boolean handleNewProjectResponseMessage (NewProjectResponseMessage res, - EditorEditor ed, - boolean showPopup) - throws Exception - { - - if (ed.isPending ()) - { - - if (res.isAccepted ()) - { - - EditorsEnvironment.getMessageHandler ().subscribeToEditor (ed); - - } - - } - - // Set the response in the new project message we have stored. - // Get the message. - NewProjectMessage npmess = EditorsEnvironment.getNewProjectMessage (ed, - res.getForProjectId (), - true); - - if (npmess == null) - { - - // Return an error saying that the project no longer exists. - EditorsEnvironment.sendError (res, - ErrorMessage.ErrorType.invalidstate, - "No new project message found for project: " + res.getForProjectId ()); - - return false; - - } - - boolean accepted = res.isAccepted (); - - npmess.setAccepted (accepted); - npmess.setResponseMessage (res.getResponseMessage ()); - - EditorsEnvironment.updateMessage (npmess); -/* - if (showPopup) - { - - EditorsUIUtils.showNewProjectResponseNotification (res); - - return true; - - } - - ProjectInfo proj = null; - - try - { - - proj = Environment.getProjectById (res.getForProjectId (), - Project.NORMAL_PROJECT_TYPE); - - } catch (Exception e) { - - Environment.logError ("Unable to get project info for project with id: " + - res.getForProjectId (), - e); - - return false; - - } - - ProjectEditor pe = null; - - try - { - - pe = EditorsEnvironment.getProjectEditor (proj, - ed); - - } catch (Exception e) { - - Environment.logError ("Unable to get project editor: " + - proj + - ", editor: " + - ed, - e); - - return false; - - } -*/ - /* - if (ed.isPending ()) - { - - if (accepted) - { - - EditorsEnvironment.getMessageHandler ().subscribeToEditor (ed); - - if (res.getEditorName () != null) - { - - ed.setName (res.getEditorName ()); - - } - - if (res.getEditorAvatar () != null) - { - - ed.setAvatar (res.getEditorAvatar ()); - - } - - - } - - ed.setEditorStatus ((accepted ? EditorEditor.EditorStatus.current : EditorEditor.EditorStatus.rejected)); - - try - { - - EditorsEnvironment.updateEditor (ed); - - } catch (Exception e) { - - Environment.logError ("Unable to update editor: " + - ed, - e); - - } - - } - */ - /* - if (pe != null) - { - - if (!accepted) - { - - try - { - - EditorsEnvironment.removeProjectEditor (pe); - - } catch (Exception e) { - - Environment.logError ("Unable to remove project editor: " + - pe, - e); - - } - - } else { - - try - { - - pe.setStatus (ProjectEditor.Status.accepted); - - EditorsEnvironment.updateProjectEditor (pe); - - } catch (Exception e) { - - Environment.logError ("Unable to accept project editor: " + - pe, - e); - - } - - } - - } -*/ - return true; - - - } - - private boolean handleNewProjectMessage (NewProjectMessage proj, - EditorEditor ed, - boolean showPopup) - throws Exception - { - - // TODO: Need a nicer way of doing this. - if (ed.getKey () != null) - { - - EditorsEnvironment.updateEditor (ed); - - } else { - - // Only set the name/avatar for new editors. - ed.setName (proj.getEditorName ()); - ed.setAvatar (proj.getEditorAvatar ()); - - EditorsEnvironment.addNewEditor (ed); - - } - - NewProjectMessage npmess = EditorsEnvironment.getNewProjectMessage (ed, - proj.getForProjectId (), - false); - - ProjectInfo pr = Environment.getProjectById (proj.getForProjectId (), - Project.EDITOR_PROJECT_TYPE); - - ProjectEditor pe = EditorsEnvironment.getProjectEditor (pr, - ed); - - if ((npmess != null) - && - (pe != null) - && - (pe.isCurrent ()) - ) - { - - // Return an error saying that it can only be sent once. - EditorsEnvironment.sendError (proj, - ErrorMessage.ErrorType.invalidstate, - "Already received a new project message for: " + proj.getForProjectId ()); - - Environment.logError ("Received duplicate new project message from: " + - ed + - " for project: " + - proj.getForProjectId ()); - - return false; - - } - -/* - if (!showPopup) - { - - // Save the message. - return true; - - } - - // Check to see if the editor is already editing the project. - EditorsUIUtils.showNewProjectReceived (proj); -*/ - return true; - - - } - - private boolean handleUpdateProjectMessage (UpdateProjectMessage mess, - EditorEditor ed, - boolean showPopup) - throws Exception - { - - /* - Project pr = Environment.getProjectById (mess.getForProjectId (), - Project.EDITOR_PROJECT_TYPE); - - // If we don't have the project then send an error. - if (pr == null) - { - - EditorsEnvironment.sendError (mess, - ErrorMessage.ErrorType.projectnotexists, - "No project with id: " + mess.getForProjectId ()); - - Environment.logError ("Received an update project message from editor: " + - ed + - ", but project is unknown to user."); - - return false; - - } - - // Auto update. - if (!pr.isEncrypted ()) - { - - try - { - - Environment.updateToNewVersions (pr, - mess.getProjectVersion (), - mess.getChapters (), - null); - - } catch (Exception e) { - - Environment.logError ("Unable to update project to new versions of chapters: " + - pr, - e); - - return false; - - } - - } - */ -/* - if (showPopup) - { - - EditorsUIUtils.showProjectUpdateReceived (mess); - - } -*/ - // Save the message. - return true; - - } - -} diff --git a/src/com/quollwriter/editors/DefaultEditorsWebServiceErrorAction.java b/src/com/quollwriter/editors/DefaultEditorsWebServiceErrorAction.java deleted file mode 100644 index b85bd3ad..00000000 --- a/src/com/quollwriter/editors/DefaultEditorsWebServiceErrorAction.java +++ /dev/null @@ -1,193 +0,0 @@ -package com.quollwriter.editors; - -import java.awt.event.*; - -import java.net.*; - -import com.quollwriter.*; -import com.quollwriter.ui.*; -import com.quollwriter.editors.ui.*; -import com.quollwriter.data.editors.*; - -import static com.quollwriter.LanguageStrings.*; -import static com.quollwriter.Environment.getUIString; - -public class DefaultEditorsWebServiceErrorAction implements EditorsWebServiceAction -{ - - private EditorsWebServiceHandler handler = null; - - public DefaultEditorsWebServiceErrorAction (EditorsWebServiceHandler handler) - { - - this.handler = handler; - - } - - protected void handleForbiddenResponse () - { - - EditorsEnvironment.clearUserPassword (); - - AbstractViewer viewer = Environment.getFocusedViewer (); - - if (viewer == null) - { - - throw new IllegalStateException ("Unable to handle response, no viewer available."); - - } - - UIUtils.doLater (new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - AbstractViewer viewer = Environment.getFocusedViewer (); - - EditorsUIUtils.showLoginError (getUIString (editors,login,errors,maxloginattempts)); - //"You have reached the maximum number of login attempts possible. Please try logging in again in a few minutes."); - - } - - }); - - } - - protected void handleUnauthorizedResponse (EditorsWebServiceResult res, - ActionListener onLogin, - ActionListener onCancel) - { - - AbstractViewer viewer = Environment.getFocusedViewer (); - - if (viewer == null) - { - - throw new IllegalStateException ("Unable to handle response, no viewer available."); - - } - - if (res.getErrorType ().equals ("InvalidCredentials")) - { - - EditorsEnvironment.clearUserPassword (); - - // Need to login again, probably the password has been changed. - EditorsUIUtils.showLoginError (getUIString (editors,login,errors,invalidcredentials), - //"Your login details do not appear to be correct.", - onLogin, - onCancel); - - return; - - } - - if (res.getErrorType ().equals ("AccountNotActive")) - { - - // Need to activate the account first. - EditorsUIUtils.showLoginError (getUIString (editors,login,errors,inactiveaccount)); - //"You must activate your account (check your email) first."); - - return; - - } - - // See if we have login credentials, if so try getting a new session. - if ((res.getErrorType ().equals ("SessionExpired")) - || - (res.getErrorType ().equals ("UnknownSessionId")) - ) - { - - EditorAccount acc = EditorsEnvironment.getUserAccount (); - - if (acc.getPassword () == null) - { - - // How did we wind up here? - EditorsUIUtils.showLoginError (getUIString (editors,login,errors,invalidcredentials), - //"Your login details do not appear to be correct.", - onLogin, - onCancel); - - return; - - } - - acc.setWebServiceSessionId (null); - - this.handler.login (onLogin, - null); - - return; - - } - - EditorsEnvironment.clearUserPassword (); - - // Something unexpected happened, just show the login again. - EditorsUIUtils.showLoginError (getUIString (editors,login,errors,invalidcredentials), - //"Your login details do not appear to be correct.", - onLogin, - onCancel); - - } - - public void processResult (final EditorsWebServiceResult res) - { - - if (!res.isError ()) - { - - - - } - - // Has the current session expired? - if (res.code == HttpURLConnection.HTTP_UNAUTHORIZED) - { - - this.handleUnauthorizedResponse (res, - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - EditorAccount acc = EditorsEnvironment.getUserAccount (); - - // Recall. - res.getCall ().sessionId (acc.getWebServiceSessionId ()).call (); - - } - - }, - null); - - return; - - } - - if (res.code == HttpURLConnection.HTTP_FORBIDDEN) - { - - this.handleForbiddenResponse (); - - return; - - } - - // Get the response code. - if (res.code != HttpURLConnection.HTTP_OK) - { - - EditorsUIUtils.showResultError (res); - - } - - } - -} diff --git a/src/com/quollwriter/editors/EditorsEnvironment.java b/src/com/quollwriter/editors/EditorsEnvironment.java deleted file mode 100644 index ac29f3f1..00000000 --- a/src/com/quollwriter/editors/EditorsEnvironment.java +++ /dev/null @@ -1,3428 +0,0 @@ -package com.quollwriter.editors; - -import java.io.*; -import java.awt.event.*; -import java.awt.image.*; -import java.net.*; -import java.util.*; -import java.sql.*; -import javax.swing.*; -import javax.swing.event.*; - -import com.gentlyweb.xml.*; -import com.gentlyweb.properties.*; - -import org.bouncycastle.openpgp.*; - -import com.quollwriter.*; -import com.quollwriter.data.*; -import com.quollwriter.events.*; -import com.quollwriter.db.*; -import com.quollwriter.ui.*; -import com.quollwriter.ui.components.QPopup; -import com.quollwriter.ui.components.HyperlinkAdapter; -import com.quollwriter.data.editors.*; -import com.quollwriter.editors.messages.*; -import com.quollwriter.editors.ui.*; - -import static com.quollwriter.LanguageStrings.*; -import static com.quollwriter.Environment.getUIString; - -public class EditorsEnvironment -{ - - private static EditorsObjectManager editorsManager = null; - private static EditorsWebServiceHandler editorsHandler = null; - private static EditorsMessageHandler messageHandler = null; - private static EditorAccount editorAccount = null; - //private static boolean hasRegisteredForEditorService = false; - public static boolean serviceAvailable = true; - private static List editors = new ArrayList (); - - // TODO: This is *NOT* the way to handle this but is ok for now and saves faffing with dirs and files. - protected static int schemaVersion = 0; - private static com.gentlyweb.properties.Properties editorsProps = new com.gentlyweb.properties.Properties (); - private static EditorEditor.OnlineStatus currentOnlineStatus = EditorEditor.OnlineStatus.offline; - private static EditorEditor.OnlineStatus lastOnlineStatus = null; - - private static Map editorChangedListeners = null; - private static Map projectEditorChangedListeners = null; - private static Map editorMessageListeners = null; - private static Map userStatusListeners = null; - private static Map editorInteractionListeners = null; - - private static boolean startupLoginTried = false; - - // Just used in the maps above as a placeholder for the listeners. - private static final Object listenerFillObj = new Object (); - - // We create the listener containers here to allow others to listen for events even though the service - // may not be running or ever available. This is sort of wasteful but prevents clients having to bother - // about checking for the service being available, they just won't receive events. - static - { - - // We use a synchronized weak hash map here so that we don't have to worry about all the - // references since they will be transient compared to the potential length of the service - // running. - - // Where possible listeners should de-register as normal but this just ensure that objects - // that don't have a controlled pre-defined lifecycle (as opposed say to AbstractSideBar) - // won't leak. - EditorsEnvironment.editorChangedListeners = Collections.synchronizedMap (new WeakHashMap ()); - - EditorsEnvironment.projectEditorChangedListeners = Collections.synchronizedMap (new WeakHashMap ()); - - EditorsEnvironment.editorMessageListeners = Collections.synchronizedMap (new WeakHashMap ()); - - EditorsEnvironment.userStatusListeners = Collections.synchronizedMap (new WeakHashMap ()); - - EditorsEnvironment.editorInteractionListeners = Collections.synchronizedMap (new WeakHashMap ()); - - } - - public static void logEditorMessages (boolean v) - { - - EditorsEnvironment.messageHandler.logMessages (v); - - } - - public static void init (com.gentlyweb.properties.Properties props) - throws Exception - { - - if (!EditorsEnvironment.serviceAvailable) - { - - return; - - } - - if (props == null) - { - - throw new GeneralException ("Properties must be provided."); - - } - - EditorsEnvironment.editorsProps = props; - - try - { - - EditorsEnvironment.schemaVersion = Integer.parseInt (Environment.getResourceFileAsString (Constants.EDITORS_SCHEMA_VERSION_FILE).trim ()); - - } catch (Exception e) - { - - Environment.logError ("Unable to read editors schema version file", - e); - - EditorsEnvironment.serviceAvailable = false; - - return; - - } - - EditorsEnvironment.editorsHandler = new EditorsWebServiceHandler (); - EditorsEnvironment.editorsHandler.init (); - - EditorsEnvironment.messageHandler = new EditorsMessageHandler (); - EditorsEnvironment.messageHandler.init (); - - String eddir = EditorsEnvironment.editorsProps.getProperty (Constants.QW_EDITORS_DB_DIR_PROPERTY_NAME); - - if (eddir != null) - { - - File dir = new File (eddir); - - if ((dir.exists ()) - && - (dir.isDirectory ()) - ) - { - - EditorsEnvironment.initDB (dir); - - } - - } - - // Bit of spelunking anyone??? - Environment.addStartupProgressListener (new PropertyChangedListener () - { - - public void propertyChanged (PropertyChangedEvent ev) - { - - if ((Environment.isStartupComplete ()) - && - (!EditorsEnvironment.startupLoginTried) - ) - { - - if (EditorsEnvironment.getEditorsPropertyAsBoolean (Constants.QW_EDITORS_SERVICE_LOGIN_AT_QW_START_PROPERTY_NAME)) - { - - UIUtils.doLater (new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - String pwd = EditorsEnvironment.getEditorsProperty (Constants.QW_EDITORS_SERVICE_PASSWORD_PROPERTY_NAME); - - String email = null; - - if (EditorsEnvironment.editorAccount != null) - { - - email = EditorsEnvironment.editorAccount.getEmail (); - - } - - if (email == null) - { - - // Can't login, no account, this can happen if the user used to have an account and has - // deleted it with the setting enabled. - return; - - } - - // Add a notification to the project viewer saying we are logging in. - final AbstractViewer viewer = Environment.getFocusedViewer (); - - Notification _n = null; - - // We may not have a viewer if we are opening an encrypted project. - if (viewer != null) - { - - _n = viewer.addNotification (getUIString (LanguageStrings.editors,login,auto,notification), - //"Logging in to the Editors service...", - Constants.EDITORS_ICON_NAME, - 30); - - } - - final Notification n = _n; - - EditorsEnvironment.setLoginCredentials (email, - pwd); - - EditorsEnvironment.startupLoginTried = true; - - EditorsEnvironment.goOnline (null, - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - if (viewer != null) - { - - viewer.removeNotification (n); - - } - - } - - }, - // On cancel - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - if (viewer != null) - { - - viewer.removeNotification (n); - - } - - } - - }, - // On error - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - EditorsEnvironment.setLoginCredentials (EditorsEnvironment.editorAccount.getEmail (), - null); - - if (viewer != null) - { - - viewer.removeNotification (n); - - } - - EditorsUIUtils.showLoginError (getUIString (LanguageStrings.editors,login,auto,actionerror), - //"Unable to automatically login, please check your email and password.", - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - EditorsEnvironment.goOnline (null, - null, - null, - null); - - } - - }, - null); - - } - - }); - - } - - }); - - } - - } - - - } - - }); - - } - - public static void removeEditorInteractionListener (EditorInteractionListener l) - { - - EditorsEnvironment.editorInteractionListeners.remove (l); - - } - - public static void addEditorInteractionListener (EditorInteractionListener l) - { - - EditorsEnvironment.editorInteractionListeners.put (l, - EditorsEnvironment.listenerFillObj); - - } - - public static void fireEditorInteractionEvent (final EditorEditor ed, - final InteractionMessage.Action action) - { - - UIUtils.doActionLater (new ActionListener () - { - - public void actionPerformed (ActionEvent aev) - { - - Set ls = null; - - EditorInteractionEvent ev = new EditorInteractionEvent (ed, - action); - - // Get a copy of the current valid listeners. - synchronized (EditorsEnvironment.editorInteractionListeners) - { - - ls = new LinkedHashSet (EditorsEnvironment.editorInteractionListeners.keySet ()); - - } - - for (EditorInteractionListener l : ls) - { - - l.handleInteraction (ev); - - } - - } - - }); - - } - - public static void removeUserOnlineStatusListener (UserOnlineStatusListener l) - { - - EditorsEnvironment.userStatusListeners.remove (l); - - } - - public static void addUserOnlineStatusListener (UserOnlineStatusListener l) - { - - EditorsEnvironment.userStatusListeners.put (l, - EditorsEnvironment.listenerFillObj); - - } - - private static void fireUserOnlineStatusChanged (final EditorEditor.OnlineStatus status) - { - - UIUtils.doActionLater (new ActionListener () - { - - public void actionPerformed (ActionEvent aev) - { - - Set ls = null; - - UserOnlineStatusEvent ev = new UserOnlineStatusEvent (status); - - // Get a copy of the current valid listeners. - synchronized (EditorsEnvironment.userStatusListeners) - { - - ls = new LinkedHashSet (EditorsEnvironment.userStatusListeners.keySet ()); - - } - - for (UserOnlineStatusListener l : ls) - { - - l.userOnlineStatusChanged (ev); - - } - - } - - }); - - } - - public static void setDefaultUserOnlineStatus () - { - - EditorEditor.OnlineStatus status = null; - - String defOnlineStatus = EditorsEnvironment.getEditorsProperty (Constants.QW_EDITORS_SERVICE_DEFAULT_ONLINE_STATUS_PROPERTY_NAME); - - if (defOnlineStatus != null) - { - - try - { - - status = EditorEditor.OnlineStatus.valueOf (defOnlineStatus); - - } catch (Exception e) { - - Environment.logError ("Unable to set default online status to: " + - defOnlineStatus, - e); - - } - - } - - if (status == null) - { - - status = EditorEditor.OnlineStatus.online; - - } - - try - { - - EditorsEnvironment.setUserOnlineStatus (status); - - } catch (Exception e) { - - Environment.logError ("Unable to set default online status to: " + - status, - e); - - } - - } - - public static void setUserOnlineStatus (EditorEditor.OnlineStatus status) - throws Exception - { - - if (!EditorsEnvironment.messageHandler.isLoggedIn ()) - { - - throw new IllegalStateException ("Cant set user online status if they are not logged in."); - - } - - if (EditorsEnvironment.currentOnlineStatus == status) - { - - return; - - } - - EditorsEnvironment.currentOnlineStatus = status; - - // Send the presence. - EditorsEnvironment.messageHandler.setOnlineStatus (status); - - EditorsEnvironment.fireUserOnlineStatusChanged (EditorsEnvironment.currentOnlineStatus); - - } - - public static EditorEditor.OnlineStatus getUserOnlineStatus () - { - - return EditorsEnvironment.currentOnlineStatus; - - } - - public static boolean isUserLoggedIn () - { - - return EditorsEnvironment.messageHandler.isLoggedIn (); - - } - - public static boolean isEditorsDBDir (File dir) - { - - if (dir == null) - { - - return false; - - } - - if (dir.isFile ()) - { - - return false; - - } - - if (!dir.exists ()) - { - - return false; - - } - - File f = new File (dir, Constants.EDITORS_DB_FILE_NAME_PREFIX + Constants.H2_DB_FILE_SUFFIX); - - if ((f.exists ()) - && - (f.isFile ()) - ) - { - - return true; - - } - - return false; - - } - - public static void initDB (File dir) - throws Exception - { - - if (EditorsEnvironment.editorsProps == null) - { - - throw new IllegalStateException ("Editors properties has not yet been set, try init(Properties) first."); - - } - - // Get the username and password. - String username = EditorsEnvironment.editorsProps.getProperty (Constants.DB_USERNAME_PROPERTY_NAME); - String password = EditorsEnvironment.editorsProps.getProperty (Constants.DB_PASSWORD_PROPERTY_NAME); - - EditorsEnvironment.editorsManager = new EditorsObjectManager (); - - File f = EditorsEnvironment.getEditorsDBFile (dir); - - EditorsEnvironment.editorsManager.init (f, - username, - password, - null, - EditorsEnvironment.getSchemaVersion (dir)); - - // Create a file that indicates that the directory can be deleted. - Utils.createQuollWriterDirFile (dir); - - EditorsEnvironment.editorAccount = EditorsEnvironment.editorsManager.getUserAccount (); - - if (EditorsEnvironment.editorAccount != null) - { - - // Load up the editors. - EditorsEnvironment.editors = (List) EditorsEnvironment.editorsManager.getObjects (EditorEditor.class, - null, - null, - true); - - } - - } - - public static boolean hasUserSentAProjectBefore () - throws Exception - { - - if (EditorsEnvironment.editorsManager == null) - { - - return false; - - } - - return EditorsEnvironment.editorsManager.hasUserSentAProjectBefore (); - - } - - public static void fireEditorMessageEvent (final EditorMessageEvent ev) - { - - UIUtils.doActionLater (new ActionListener () - { - - public void actionPerformed (ActionEvent aev) - { - - Set ls = null; - - // Get a copy of the current valid listeners. - synchronized (EditorsEnvironment.editorMessageListeners) - { - - ls = new LinkedHashSet (EditorsEnvironment.editorMessageListeners.keySet ()); - - } - - for (EditorMessageListener l : ls) - { - - l.handleMessage (ev); - - } - - } - - }); - - } - - public static NewProjectMessage getNewProjectMessage (EditorEditor ed, - String projectId, - boolean sentByMe) - throws Exception - { - - return EditorsEnvironment.editorsManager.getNewProjectMessage (ed, - projectId, - sentByMe); - - } - - public static boolean hasMyPublicKeyBeenSentToEditor (EditorEditor ed) - throws Exception - { - - return EditorsEnvironment.editorsManager.hasMyPublicKeyBeenSentToEditor (ed); - - } - - public static boolean hasSentMessageOfTypeToEditor (EditorEditor ed, - String messageType) - throws Exception - { - - return EditorsEnvironment.editorsManager.hasSentMessageOfTypeToEditor (ed, - messageType); - - } - - public static boolean hasEditorSentInfo (EditorEditor ed) - throws Exception - { - - if (ed.messagesLoaded ()) - { - - return ed.hasSentInfo (); - - } - - return EditorsEnvironment.editorsManager.hasEditorSentInfo (ed); - - } - - public static void removeEditorMessageListener (EditorMessageListener l) - { - - EditorsEnvironment.editorMessageListeners.remove (l); - - } - - public static void addEditorMessageListener (EditorMessageListener l) - { - - EditorsEnvironment.editorMessageListeners.put (l, - EditorsEnvironment.listenerFillObj); - - } - - public static void fireEditorChangedEvent (EditorEditor ed, - int changeType) - { - - EditorsEnvironment.fireEditorChangedEvent (new EditorChangedEvent (ed, - changeType)); - - } - - public static void fireEditorChangedEvent (final EditorChangedEvent ev) - { - - UIUtils.doActionLater (new ActionListener () - { - - public void actionPerformed (ActionEvent aev) - { - - Set ls = null; - - // Get a copy of the current valid listeners. - synchronized (EditorsEnvironment.editorChangedListeners) - { - - ls = new LinkedHashSet (EditorsEnvironment.editorChangedListeners.keySet ()); - - } - - for (EditorChangedListener l : ls) - { - - l.editorChanged (ev); - - } - - } - - }); - - } - - public static void removeEditorChangedListener (EditorChangedListener l) - { - - EditorsEnvironment.editorChangedListeners.remove (l); - - } - - public static void addEditorChangedListener (EditorChangedListener l) - { - - EditorsEnvironment.editorChangedListeners.put (l, - EditorsEnvironment.listenerFillObj); - - } - - public static void fireProjectEditorChangedEvent (ProjectEditor pe, - int changeType) - { - - EditorsEnvironment.fireProjectEditorChangedEvent (new ProjectEditorChangedEvent (pe, - changeType)); - - } - - public static void fireProjectEditorChangedEvent (final ProjectEditorChangedEvent ev) - { - - UIUtils.doActionLater (new ActionListener () - { - - public void actionPerformed (ActionEvent aev) - { - - Set ls = null; - - // Get a copy of the current valid listeners. - synchronized (EditorsEnvironment.projectEditorChangedListeners) - { - - ls = new LinkedHashSet (EditorsEnvironment.projectEditorChangedListeners.keySet ()); - - } - - for (ProjectEditorChangedListener l : ls) - { - - l.projectEditorChanged (ev); - - } - - } - - }); - - } - - public static void removeProjectEditorChangedListener (ProjectEditorChangedListener l) - { - - EditorsEnvironment.projectEditorChangedListeners.remove (l); - - } - - public static void addProjectEditorChangedListener (ProjectEditorChangedListener l) - { - - EditorsEnvironment.projectEditorChangedListeners.put (l, - EditorsEnvironment.listenerFillObj); - - } - - public static boolean isEditorsServiceAvailable () - { - - return EditorsEnvironment.serviceAvailable; - - } - - public static void setUserInformation (String name, - BufferedImage avatarImage) - throws GeneralException - { - - if (EditorsEnvironment.editorsManager == null) - { - - throw new IllegalStateException ("Editor object manager not inited."); - - } - - if (avatarImage != null) - { - - if (avatarImage.getWidth () > 300) - { - - avatarImage = UIUtils.getScaledImage (avatarImage, - 300); - - } - - } - - EditorsEnvironment.editorAccount.setName (name); - EditorsEnvironment.editorAccount.setAvatar (avatarImage); - - EditorsEnvironment.editorsManager.setUserInformation (EditorsEnvironment.editorAccount); - - } - - private static File getEditorsDBFile (File dir) - { - - return new File (dir, Constants.EDITORS_DB_FILE_NAME_PREFIX); - - } - - public static int getSchemaVersion (File dir) - { - - File dbf = new File (EditorsEnvironment.getEditorsDBFile (dir).getPath () + Constants.H2_DB_FILE_SUFFIX); - - if (!dbf.exists ()) - { - - return 0; - - } - - return EditorsEnvironment.schemaVersion; - - } - - public static EditorAccount getUserAccount () - { - - return EditorsEnvironment.editorAccount; - - } - - public static EditorsMessageHandler getMessageHandler () - { - - return EditorsEnvironment.messageHandler; - - } - - public static Set getWritingGenres () - { - - String gt = EditorsEnvironment.editorsProps.getProperty (Constants.WRITING_GENRES_PROPERTY_NAME); - - Set gitems = new LinkedHashSet (); - - StringTokenizer t = new StringTokenizer (gt, - ","); - - while (t.hasMoreTokens ()) - { - - gitems.add (t.nextToken ().trim ()); - - } - - return gitems; - - } - - public static EditorsWebServiceHandler getEditorsWebServiceHandler () - { - - return EditorsEnvironment.editorsHandler; - - } - - public static Set getAllUndealtWithMessages () - throws Exception - { - - if (EditorsEnvironment.editorsManager == null) - { - - return null; - - } - - return EditorsEnvironment.editorsManager.getAllUndealtWithMessages (); - - } - - public static Set getProjectMessages (String projId, - String... messageTypes) - throws Exception - { - - return EditorsEnvironment.editorsManager.getProjectMessages (projId, - messageTypes); - - } - - /** - * Get a count of all the messages the user hasn't dealt with. - * - * @return The count. - */ - public static int getUndealtWithMessageCount () - throws Exception - { - - if (EditorsEnvironment.editorsManager == null) - { - - return 0; - - } - - return EditorsEnvironment.editorsManager.getUndealtWithMessageCount (); - - } - - public static File getEditorsAuthorAvatarImageFile (String suffix) - { - - if (suffix == null) - { - - return null; - - } - - File f = new File (Environment.getUserQuollWriterDir (), - Constants.EDITORS_AUTHOR_AVATAR_IMAGE_FILE_NAME_PREFIX + "." + suffix); - - f.getParentFile ().mkdirs (); - - return f; - - } - - public static File getEditorsAuthorAvatarImageFile () - { - - if (EditorsEnvironment.editorsHandler == null) - { - - return null; - - } - - if (EditorsEnvironment.editorAccount == null) - { - - return null; - - } - - EditorAuthor au = EditorsEnvironment.editorAccount.getAuthor (); - - if (au == null) - { - - return null; - - } - - String t = EditorsEnvironment.editorsProps.getProperty (Constants.EDITORS_AUTHOR_AVATAR_IMAGE_FILE_TYPE_PROPERTY_NAME); - - return EditorsEnvironment.getEditorsAuthorAvatarImageFile (t); - - } - - public static File getEditorsAuthorFile () - { - - File f = new File (Environment.getUserQuollWriterDir (), - Constants.EDITORS_AUTHOR_FILE_NAME); - - f.getParentFile ().mkdirs (); - - return f; - - } - - public static File getEditorsEditorAvatarImageFile (String suffix) - { - - if (suffix == null) - { - - return null; - - } - - File f = new File (Environment.getUserQuollWriterDir (), - Constants.EDITORS_EDITOR_AVATAR_IMAGE_FILE_NAME_PREFIX + "." + suffix); - - f.getParentFile ().mkdirs (); - - return f; - - } - - public static File getEditorsEditorAvatarImageFile () - { - - if (EditorsEnvironment.editorsHandler == null) - { - - return null; - - } - - if (EditorsEnvironment.editorAccount == null) - { - - return null; - - } - - EditorEditor ed = EditorsEnvironment.editorAccount.getEditor (); - - if (ed == null) - { - - return null; - - } - - String t = EditorsEnvironment.editorsProps.getProperty (Constants.EDITORS_EDITOR_AVATAR_IMAGE_FILE_TYPE_PROPERTY_NAME); - - return EditorsEnvironment.getEditorsEditorAvatarImageFile (t); - - } - - public static File getEditorsEditorFile () - { - - File f = new File (Environment.getUserQuollWriterDir (), - Constants.EDITORS_EDITOR_FILE_NAME); - - f.getParentFile ().mkdirs (); - - return f; - - } - - public static void clearUserPassword () - { - - if (EditorsEnvironment.editorAccount != null) - { - - EditorsEnvironment.editorAccount.setPassword (null); - - } - - } - - public static void getInvite (EditorEditor editor, - EditorsWebServiceAction onComplete, - EditorsWebServiceAction onError) - { - - EditorsEnvironment.editorsHandler.getInvite (editor, - onComplete, - onError); - - } - - public static void getInvite (String fromEmail, - EditorsWebServiceAction onComplete, - EditorsWebServiceAction onError) - { - - EditorsEnvironment.editorsHandler.getInvite (fromEmail, - onComplete, - onError); - - } - - public static void deleteMessages (Set messages) - throws Exception - { - - // TODO: Clean up the Set/List mess. - EditorsEnvironment.editorsManager.deleteObjects (new ArrayList (messages), - null); - - } - - public static void acceptInvite (final EditorEditor editor, - final EditorMessage message, - final ActionListener onComplete) - { - - final String email = editor.getEmail (); - - EditorsEnvironment.editorsHandler.updateInvite (email, - Invite.Status.accepted, - new EditorsWebServiceAction () - { - - public void processResult (EditorsWebServiceResult res) - { - - try - { - - editor.setEditorStatus (EditorEditor.EditorStatus.current); - - EditorsEnvironment.updateEditor (editor); - - } catch (Exception e) { - - Environment.logError ("Unable to update editor: " + - editor + - " to accepted", - e); - - AbstractViewer viewer = Environment.getFocusedViewer (); - - UIUtils.showErrorMessage (viewer, - getUIString (LanguageStrings.editors,LanguageStrings.editor,edit,actionerror)); - //"Unable to update {editor} information in local database."); - - return; - - } - - // Send an invite response message. - EditorsEnvironment.getMessageHandler ().subscribeToEditor (editor); - - EditorsEnvironment.sendMessageToEditor (message, - onComplete, - null, - null); - - } - }, - null); - - } - - public static void rejectInvite (final EditorEditor editor, - final EditorMessage message, - final ActionListener onComplete) - { - - final String email = editor.getEmail (); - - EditorsEnvironment.editorsHandler.updateInvite (email, - Invite.Status.rejected, - new EditorsWebServiceAction () - { - - public void processResult (EditorsWebServiceResult res) - { - - try - { - - editor.setEditorStatus (EditorEditor.EditorStatus.rejected); - - EditorsEnvironment.updateEditor (editor); - - } catch (Exception e) { - - AbstractViewer viewer = Environment.getFocusedViewer (); - - UIUtils.showErrorMessage (viewer, - getUIString (LanguageStrings.editors,LanguageStrings.editor,edit,actionerror)); - //"Unable to update {editor} information in local database."); - - Environment.logError ("Unable to update editor: " + - editor + - " to rejected", - e); - - return; - - } - - EditorsEnvironment.sendMessageToEditor (message, - onComplete, - null, - null); - - } - }, - null); - - } - - public static void updateInvite (final String email, - final Invite.Status newStatus, - final ActionListener onUpdateComplete) - { - - EditorsEnvironment.editorsHandler.updateInvite (email, - newStatus, - new EditorsWebServiceAction () - { - - public void processResult (EditorsWebServiceResult res) - { - - EditorEditor ed = EditorsEnvironment.getEditorByEmail (email); - - EditorEditor.EditorStatus status = null; - - if (newStatus == Invite.Status.accepted) - { - - status = EditorEditor.EditorStatus.current; - - } else { - - status = EditorEditor.EditorStatus.valueOf (newStatus.getType ()); - - } - - try - { - - if (ed != null) - { - - ed.setEditorStatus (status); - - EditorsEnvironment.updateEditor (ed); - - } else { - - ed = new EditorEditor (); - - ed.setEmail (email); - ed.setEditorStatus (status); - - // Add to our editors. - EditorsEnvironment.addNewEditor (ed); - - } - - } catch (Exception e) { - - AbstractViewer viewer = Environment.getFocusedViewer (); - - UIUtils.showErrorMessage (viewer, - getUIString (LanguageStrings.editors,editor,edit,actionerror)); - //"Unable to update {editor} information in local database."); - - Environment.logError ("Unable to update editor: " + - email + - " to status: " + - status, - e); - - return; - - } - - if (onUpdateComplete != null) - { - - onUpdateComplete.actionPerformed (new ActionEvent ("update", 1, "update")); - - } - - } - }, - null); - - } - - public static void closeDown () - { - - EditorsEnvironment.goOffline (); - - // Close all the db connections. - if (EditorsEnvironment.editorsManager != null) - { - - EditorsEnvironment.editorsManager.closeConnectionPool (); - - } - - } - public static void goOffline () - { - - EditorsEnvironment.editorsHandler.logout (); - - EditorsEnvironment.messageHandler.logout (null); - - EditorsEnvironment.currentOnlineStatus = EditorEditor.OnlineStatus.offline; - - EditorsEnvironment.fireUserOnlineStatusChanged (EditorsEnvironment.currentOnlineStatus); - - for (EditorEditor ed : EditorsEnvironment.editors) - { - - ed.setOnlineStatus (null); - - EditorsEnvironment.fireEditorChangedEvent (new EditorChangedEvent (ed, - EditorChangedEvent.EDITOR_CHANGED)); - - } - - } - - public static boolean isMessageSendInProgress () - { - - return EditorsEnvironment.messageHandler.isMessageSendInProgress (); - - } - - public static void updateUserPassword (final String newPassword) - { - - final ActionListener onError = new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - UIUtils.showErrorMessage (Environment.getFocusedViewer (), - getUIString (LanguageStrings.editors,user,edit,password,actionerror)); - //"Unable to update your password, please contact Quoll Writer support for assistance."); - - } - - }; - - EditorsEnvironment.editorsHandler.changePassword (newPassword, - new EditorsWebServiceAction () - { - - @Override - public void processResult (EditorsWebServiceResult res) - { - - EditorsEnvironment.messageHandler.changePassword (newPassword, - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - UIUtils.showMessage ((PopupsSupported) Environment.getFocusedViewer (), - getUIString (LanguageStrings.editors,user,edit,password,confirmpopup,title), - //"Password updated", - getUIString (LanguageStrings.editors,user,edit,password,confirmpopup,text)); - //"Your password has been updated."); - - } - - }, - onError); - - } - - }, - new EditorsWebServiceAction () - { - - @Override - public void processResult (EditorsWebServiceResult res) - { - - onError.actionPerformed (new ActionEvent ("error", 1, "")); - - } - - }); - - } - - private static void checkForUndealtWithMessages () - { - - final AbstractViewer viewer = Environment.getFocusedViewer (); - - if (viewer == null) - { - - return; - - } - - if (!viewer.isEditorsVisible ()) - { - - int c = 0; - - try - { - - c = EditorsEnvironment.getUndealtWithMessageCount (); - - } catch (Exception e) { - - Environment.logError ("Unable to get undealt with message count", - e); - - return; - - } - - if (c > 0) - { - -/* - String s = "There are %s {Editor} messages requiring your attention."; - - if (c == 1) - { - - s = "There is 1 {Editor} message that requires your attention."; - - } -*/ - //xxx get notification by name. - final Notification n = viewer.addNotification (String.format (getUIString (LanguageStrings.editors,messages,undealtwith,notification), - //+ " Click here to view the message(s).", - c), - Constants.EDITORS_ICON_NAME, - 60); - - // TODO: Find a nicer way of getting rid of clickable notifications. - // Bit of a risk this... - JTextPane tp = (JTextPane) n.getContent (); - - tp.addHyperlinkListener (new HyperlinkAdapter () - { - - public void hyperlinkUpdate (HyperlinkEvent ev) - { - - if (ev.getEventType () == HyperlinkEvent.EventType.ACTIVATED) - { - - viewer.removeNotification (n); - - } - - } - - }); - - } - - } - - } - - private static void startMessageNotificationThread () - { - - // Start the listener for messages. - // Display a notification is there are undealt with messages. - // Only show if the editors side bar isn't visible. - Thread t = new Thread (new Runnable () - { - - public void run () - { - - while (EditorsEnvironment.editorAccount != null) - { - - try - { - - EditorsEnvironment.checkForUndealtWithMessages (); - - Thread.sleep (10 * 60 * 1000); - - } catch (Exception e) { - - Environment.logError ("Unable to get undealt with messages", - e); - - break; - - } - - } - - } - - }); - - t.setName ("editors-service-check-for-undealt-with-messages"); - t.setPriority (Thread.MIN_PRIORITY); - t.setDaemon (true); - - t.start (); - - } - - public static void goOnline (final String loginReason, - final ActionListener onLogin, - final ActionListener onCancel, - final ActionListener onError) - { - - final AbstractViewer viewer = Environment.getFocusedViewer (); - - final String reason = (loginReason != null ? loginReason : getUIString (LanguageStrings.editors,login,reasons,_default)); - //"To go online you must first login."); - - ActionListener login = new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - EditorsEnvironment.editorsHandler.login (new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - EditorsEnvironment.messageHandler.login (new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - EditorsUIUtils.hideLogin (); - - try - { - - EditorsEnvironment.setEditorsProperty (Constants.QW_EDITORS_SERVICE_HAS_LOGGED_IN_PROPERTY_NAME, - true); - - } catch (Exception e) { - - Environment.logError ("Unable to set property", - e); - - } - - //EditorsEnvironment.getEditorsWebServiceHandler ().checkPendingInvites (); - - if (EditorsEnvironment.editorAccount.getLastLogin () == null) - { - - EditorsEnvironment.getEditorsWebServiceHandler ().checkPendingInvites (); - - } - - EditorsEnvironment.setDefaultUserOnlineStatus (); - - //EditorsEnvironment.currentOnlineStatus = EditorEditor.OnlineStatus.online; - - //EditorsEnvironment.fireUserOnlineStatusChanged (EditorsEnvironment.currentOnlineStatus); - - java.util.Date d = new java.util.Date (); - - EditorsEnvironment.editorAccount.setLastLogin (d); - - try - { - - EditorsEnvironment.editorsManager.setLastLogin (d); - - } catch (Exception e) { - - Environment.logError ("Unable to set last login date", - e); - - } - - EditorsEnvironment.startMessageNotificationThread (); - - if (onLogin != null) - { - - onLogin.actionPerformed (ev); - - } - - } - - }, - onError); - - } - - }, - onError); - - } - - }; - - if (EditorsEnvironment.hasLoginCredentials ()) - { - - login.actionPerformed (new ActionEvent ("login", 1, "login")); - - } else { - - EditorsUIUtils.showLogin (viewer, - reason, - login, - onCancel); - - } - - } - - public static void sendMessageToAllEditors (String loginReason, - EditorMessage mess, - ActionListener onSend, - ActionListener onLoginCancel, - ActionListener onError) - { - - EditorsEnvironment.sendMessageToAllEditors (new ArrayDeque (EditorsEnvironment.editors), - loginReason, - mess, - onSend, - onLoginCancel, - onError); - - } - - private static void sendMessageToAllEditors (final Deque eds, - final String loginReason, - final EditorMessage mess, - final ActionListener onSend, - final ActionListener onLoginCancel, - final ActionListener onError) - { - - if (eds.size () == 0) - { - - if (onSend != null) - { - - onSend.actionPerformed (new ActionEvent ("sent", 1, "sent")); - - } - - } else { - - EditorEditor ed = eds.pop (); - - ActionListener onSendComplete = new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - EditorsEnvironment.sendMessageToAllEditors (eds, - loginReason, - mess, - onSend, - onLoginCancel, - onError); - - } - - }; - - EditorsEnvironment.messageHandler.sendMessage (loginReason, - mess, - ed, - onSendComplete, - onLoginCancel, - onError); - - } - - } - - - public static void sendUserInformationToAllEditors (ActionListener onSend, - ActionListener onLoginCancel, - ActionListener onError) - { - - String loginReason = getUIString (LanguageStrings.editors,login,reasons,updateinfotoall); - - EditorsEnvironment.sendMessageToAllEditors (loginReason, - new EditorInfoMessage (EditorsEnvironment.getUserAccount ()), - onSend, - onLoginCancel, - onError); - - } - - public static void sendUserInformationToEditor (EditorEditor ed, - ActionListener onSend, - ActionListener onLoginCancel, - ActionListener onError) - { - - EditorsEnvironment.messageHandler.sendMessage (String.format (getUIString (LanguageStrings.editors,login,reasons,updateinfotocontact), - ed.getMainName ()), - //"To send your information to " + ed.getMainName () + " you must first login to the Editors Service.", - new EditorInfoMessage (EditorsEnvironment.getUserAccount ()), - ed, - onSend, - onLoginCancel, - onError); - - } - - public static void sendInteractionMessageToEditor (InteractionMessage.Action action, - EditorEditor ed, - ActionListener onSend) - { - - if (!EditorsEnvironment.messageHandler.isLoggedIn ()) - { - - return; - - } - - // Only send if editor is online. - if (ed.isOffline ()) - { - - return; - - } - - EditorsEnvironment.sendMessageToEditor (new InteractionMessage (action, - ed), - onSend, - null, - null); - - } - - public static void sendMessageToEditor (final EditorMessage mess, - final ActionListener onSend, - final ActionListener onLoginCancel, - final ActionListener onError) - { - - EditorsEnvironment.messageHandler.sendMessage (String.format (getUIString (LanguageStrings.editors,login,reasons,sendmessagetocontact), - mess.getEditor ().getMainName ()), - //"To send a message to " + mess.getEditor ().getMainName () + " you must first login to the Editors service.", - mess, - mess.getEditor (), - onSend, - onLoginCancel, - onError); - - } - - public static void sendInvite (final String toEmail) - { - - EditorsEnvironment.editorsHandler.sendInvite (toEmail, - new EditorsWebServiceAction () - { - - public void processResult (EditorsWebServiceResult res) - { - - final AbstractViewer viewer = Environment.getFocusedViewer (); - boolean add = false; - - // See if we already have this editor and this is a resend. - EditorEditor fed = EditorsEnvironment.getEditorByEmail (toEmail); - - if (fed == null) - { - - fed = new EditorEditor (); - add = true; - - } - - final EditorEditor ed = fed; - - // Add the invite to our local editors. - try - { - - ed.setEmail (toEmail.trim ().toLowerCase ()); - ed.setInvitedByMe (true); - - //String resS = res.getReturnObjectAsString (); - - Invite inv = Invite.createFrom ((Map) res.getReturnObject ()); - /* - if (resS != null) - { - - // Need a better way of handling this. - if (!res.isSuccess ()) - { - - // This is the public key of the editor. - ed.setTheirPublicKey (EditorsUtils.convertToPGPPublicKey (Base64.decode (resS))); - - } - - } - */ - - - ed.setTheirPublicKey (inv.getToPublicKey ()); - ed.setMessagingUsername (inv.getToMessagingUsername ()); - ed.setServiceName (inv.getToServiceName ()); - - if (add) - { - - // Add as new. - EditorsEnvironment.addNewEditor (ed); - - } - - // If they have a public key then send an invite message. - if (ed.getTheirPublicKey () != null) - { - - ActionListener onCancel = new ActionListener () - { - - private boolean inviteSent = false; - - @Override - public void actionPerformed (ActionEvent ev) - { - - if (this.inviteSent) - { - - return; - - } - - this.inviteSent = true; - - InviteMessage invite = new InviteMessage (EditorsEnvironment.editorAccount); - - invite.setEditor (ed); - - // Send an invite. - EditorsEnvironment.sendMessageToEditor (invite, - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - java.util.List prefix = Arrays.asList (LanguageStrings.editors,user,invitesent,popup); - - AbstractViewer viewer = Environment.getFocusedViewer (); - - UIUtils.showMessage ((PopupsSupported) viewer, - getUIString (prefix,title), - //"Invite sent", - String.format (getUIString (prefix,text), - toEmail)); - //"An invite has been sent to: " + toEmail + "."); - - } - - }, - null, - null); - - } - - }; - - if (viewer instanceof AbstractProjectViewer) - { - - java.util.List prefix = Arrays.asList (LanguageStrings.editors,user,sendprojectoninvite,popup); - - // Ask the user if they want to send the editor their project. - QPopup p = UIUtils.createQuestionPopup (viewer, - getUIString (prefix,title), - //"Send {project} / {chapters}?", - Constants.SEND_ICON_NAME, - String.format (getUIString (prefix,text), - //"Would you like to send your {project}/{chapters} to %s now?", - ed.getMainName ()), - getUIString (prefix,buttons,confirm), - //"Yes, send it", - getUIString (prefix,buttons,cancel), - //"No, not now", - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - EditorsUIUtils.showSendProject ((AbstractProjectViewer) viewer, - ed, - null); - - } - - }, - onCancel, - null, - null); - - p.getHeader ().getControls ().setVisible (false); - - return; - - } else { - - onCancel.actionPerformed (new ActionEvent ("send", 0, "send")); - - return; - - } - - } - - } catch (Exception e) { - - Environment.logError ("Unable to add new editor to local", - e); - - // Show an error. - // Can't uninvite, what to do? - UIUtils.showErrorMessage (viewer, - getUIString (LanguageStrings.editors,user,sendinvite,actionerror)); - //"An internal error has occurred while saving the invite to local storage. Please contact Quoll Writer support for assistance."); - - return; - - } - - UIUtils.showMessage ((PopupsSupported) viewer, - getUIString (LanguageStrings.editors,user,invitesent,popup,title), - //"Invite sent", - String.format (getUIString (LanguageStrings.editors,user,invitesent,popup,text), - //"An invite has been sent to: %s.", - toEmail)); - //"Ok, got it", - //null); - - } - - }, - null); - - } - - public static boolean hasLoginCredentials () - { - - if (EditorsEnvironment.editorAccount == null) - { - - return false; - - } - - return ((EditorsEnvironment.editorAccount.getEmail () != null) - && - (EditorsEnvironment.editorAccount.getPassword () != null)); - - } - - public static void setLoginCredentials (String email, - String password) - { - - if (EditorsEnvironment.editorAccount == null) - { - - throw new IllegalStateException ("No account available."); - - } - - EditorsEnvironment.editorAccount.setEmail (email); - EditorsEnvironment.editorAccount.setPassword (password); - - } - - public static void initUserCredentials (String email, - String password, - String serviceName, - String messagingUsername, - PGPPublicKey publicKey, - PGPPrivateKey privateKey) - throws GeneralException - { - - if (EditorsEnvironment.editorAccount != null) - { - - throw new GeneralException ("Already have an editor account"); - - } - - EditorsEnvironment.editorAccount = new EditorAccount (); - - EditorsEnvironment.editorAccount.setEmail (email); - EditorsEnvironment.editorAccount.setPassword (password); - EditorsEnvironment.editorAccount.setPublicKey (publicKey); - EditorsEnvironment.editorAccount.setPrivateKey (privateKey); - EditorsEnvironment.editorAccount.setServiceName (serviceName); - EditorsEnvironment.editorAccount.setMessagingUsername (messagingUsername); - - EditorsEnvironment.editorsManager.setUserInformation (EditorsEnvironment.editorAccount); - - } - - public static boolean hasRegistered () - { - - return EditorsEnvironment.editorAccount != null; - - } - - public synchronized static void loadMessagesForEditor (EditorEditor ed) - throws GeneralException - { - - if (ed == null) - { - - throw new NullPointerException ("Expected an editor"); - - } - - if (ed.messagesLoaded ()) - { - - return; - - } - - synchronized (ed) - { - - // Oh java why you so kooky... - ed.setMessages (new LinkedHashSet ((List) EditorsEnvironment.editorsManager.getObjects (EditorMessage.class, - ed, - null, - true))); - - } - - } - /* - public static void sendNewProjectResponse (final NewProjectMessage mess, - final boolean accepted, - final String responseMessage) - throws GeneralException - { - - NewProjectResponseMessage res = new NewProjectResponseMessage (mess.getForProjectId (), - accepted, - responseMessage, - mess.getEditor ()); - - res.setDealtWith (true); - - // For now just return rejected. - EditorsEnvironment.sendMessageToEditor (res, - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - try - { - - mess.setAccepted (accepted); - mess.setDealtWith (true); - mess.setResponseMessage (responseMessage); - - // Update the original message. - EditorsEnvironment.updateMessage (mess); - - } catch (Exception e) { - - UIUtils.showErrorMessage (null, - "Unable to update {project} message, please contact Quoll Writer support for assistance."); - - Environment.logError ("Unable to update new project message: " + - mess, - e); - - } - - } - - }, - null, - null); - - } - */ - public static void sendError (EditorMessage mess, - ErrorMessage.ErrorType errorType, - String reason) - { - - try - { - - EditorsEnvironment.sendMessageToEditor (new ErrorMessage (mess, - errorType, - reason), - null, - null, - null); - - } catch (Exception e) { - - Environment.logError ("Unable to send error message for message: " + - mess.getMessageId () + - " to editor: " + - mess.getEditor () + - " with error type: " + - errorType.getType (), - e); - - } - - } - - public static Map getOriginalMessageAsMap (EditorMessage m) - throws Exception - { - - if (m.isSentByMe ()) - { - - throw new IllegalArgumentException ("Not supported for messages sent by me."); - - } - - byte[] bytes = EditorsEnvironment.editorsManager.getOriginalMessage (m); - - // Decrypt first. - try - { - - bytes = EditorsUtils.decrypt (bytes, - EditorsEnvironment.editorAccount.getPrivateKey (), - m.getEditor ().getTheirPublicKey ()); - - } catch (Exception e) { - - throw new GeneralException ("Unable to decrypt message from editor: " + - m.getEditor (), - e); - - } - - String messageData = null; - - try - { - - messageData = new String (bytes, - "utf-8"); - - } catch (Exception e) { - - throw new GeneralException ("Unable to convert decrypted message to a string from editor: " + - m.getEditor (), - e); - - } - - // JSON decode - Map data = (Map) JSONDecoder.decode (messageData); - - return data; - - } - - public static ProjectEditor getProjectEditor (Project p, - EditorEditor ed) - throws Exception - { - - return EditorsEnvironment.getProjectEditor (Environment.getProjectById (p.getId (), - p.getType ()), - ed); - - } - - public static ProjectEditor getProjectEditor (ProjectInfo p, - EditorEditor ed) - throws GeneralException - { - - if (EditorsEnvironment.editorAccount == null) - { - - return null; - - } - - if (p == null) - { - - return null; - - } - - if (ed == null) - { - - return null; - - } - - List pes = (List) EditorsEnvironment.editorsManager.getObjects (ProjectEditor.class, - p, - null, - false); - - for (ProjectEditor pe : pes) - { - - if (pe.getEditor () == ed) - { - - return pe; - - } - - } - - return null; - - } - - public static List getProjectEditors (String projectId) - throws GeneralException - { - - if (EditorsEnvironment.editorAccount == null) - { - - return null; - - } - - ProjectInfo p = new ProjectInfo (); - p.setId (projectId); - - return (List) EditorsEnvironment.editorsManager.getObjects (ProjectEditor.class, - p, - null, - false); - - } - /* - public static String getUserPublicKeyBase64EncodedX () - { - - if (this.userPublicKey == null) - { - - return null; - - } - - RSAPublicBCPGKey pubKey = (RSAPublicBCPGKey) this.myPublicKey.getPublicKeyPacket ().getKey (); - - return Base64.encodeBytes (pubKey.getEncoded ()); - - } - */ - - public static void sendProjectEditStopMessage (final Project p, - final ActionListener onComplete) - { - - EditorsEnvironment.sendProjectEditStopMessage (Environment.getProjectInfo (p), - onComplete); - - } - - public static void sendProjectEditStopMessage (final ProjectInfo p, - final ActionListener onComplete) - { - - if (!p.isEditorProject ()) - { - - throw new IllegalArgumentException ("Only editor projects can be deleted."); - - } - - // Send message saying no longer editing. - ProjectEditStopMessage message = new ProjectEditStopMessage (p, - null, - p.getForEditor ()); - - EditorsEnvironment.sendMessageToEditor (message, - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - if (onComplete != null) - { - - UIUtils.doLater (onComplete); - - } - - } - - }, - null, - null); - - } - - public static void addProjectEditor (ProjectEditor pe) - throws GeneralException - { - - EditorsEnvironment.editorsManager.saveObject (pe, - null); - - // Fire an event. - EditorsEnvironment.fireProjectEditorChangedEvent (pe, - ProjectEditorChangedEvent.PROJECT_EDITOR_ADDED); - - } - - public static void removeProjectEditors (Project p) - throws GeneralException - { - - if (EditorsEnvironment.editorsManager == null) - { - - return; - - } - - List pes = EditorsEnvironment.getProjectEditors (p.getId ()); - - EditorsEnvironment.editorsManager.deleteObjects (pes, - null); - - for (ProjectEditor pe : pes) - { - - // Fire an event. - EditorsEnvironment.fireProjectEditorChangedEvent (pe, - ProjectEditorChangedEvent.PROJECT_EDITOR_DELETED); - - } - - } - - public static void removeProjectEditor (ProjectEditor pe) - throws GeneralException - { - - if (EditorsEnvironment.editorsManager == null) - { - - return; - - } - - EditorsEnvironment.editorsManager.deleteObject (pe, - false, - null); - - // Remove from any project tied to a project viewer. - ProjectInfo proj = null; - - try - { - - proj = Environment.getProjectById (pe.getForProjectId (), - Project.NORMAL_PROJECT_TYPE); - - } catch (Exception e) { - - Environment.logError ("Unable to get project for id: " + - pe.getForProjectId (), - e); - - } - - if (proj != null) - { - - AbstractProjectViewer pv = Environment.getProjectViewer (proj); - - pv.getProject ().removeProjectEditor (pe); - - } -/* - if (pe.isAccepted ()) - { - - // Only send this if the editor has already accepted the project. - ProjectEditStopMessage mess = new ProjectEditStopMessage (pe.getProject (), - null, - pe.getEditor ()); - - EditorsEnvironment.sendMessageToEditor (mess); - - } - */ - // Fire an event. - EditorsEnvironment.fireProjectEditorChangedEvent (pe, - ProjectEditorChangedEvent.PROJECT_EDITOR_DELETED); - - } - - public static Set getProjectsSentToEditor (EditorEditor ed) - throws Exception - { - - if (EditorsEnvironment.editorsManager == null) - { - - return null; - - } - - return EditorsEnvironment.editorsManager.getProjectsSentToEditor (ed); - - } - - public static Set getProjectsForEditor (EditorEditor ed) - throws Exception - { - - Set projs = new LinkedHashSet (); - - for (ProjectInfo p : Environment.getAllProjectInfos ()) - { - - if (p.getForEditor () == null) - { - - continue; - - } - - if (p.getForEditor ().getEmail ().equals (ed.getEmail ())) - { - - projs.add (p); - - } - - } - - return projs; - - } - - public static void setProjectEditorStatus (final String projId, - final EditorEditor ed, - final String newStatus) - throws Exception - { - - ProjectInfo proj = null; - - try - { - - proj = Environment.getProjectById (projId, - Project.NORMAL_PROJECT_TYPE); - - } catch (Exception e) { - - throw new GeneralException ("Unable to get project for id: " + - projId, - e); - - } - - ProjectEditor pe = EditorsEnvironment.getProjectEditor (proj, - ed); - - if (pe == null) - { - - throw new IllegalArgumentException ("Editor is not a project editor for project: " + projId + ", editor: " + ed); - - } - - pe.setStatusMessage (newStatus); - - EditorsEnvironment.updateProjectEditor (pe); - - } - - public static void removeEditorAsProjectEditorForAllProjects (final EditorEditor ed) - throws Exception - { - - Set projs = Environment.getAllProjectInfos (); - - for (ProjectInfo p : projs) - { - - ProjectEditor pe = EditorsEnvironment.getProjectEditor (p, - ed); - - if (pe == null) - { - - continue; - - } - - pe.setEditorTo (new java.util.Date ()); - pe.setCurrent (false); - pe.setStatusMessage (getUIString (LanguageStrings.editors,editor,remove,editorstatus)); - //"Removed"); - - EditorsEnvironment.updateProjectEditor (pe); - - } - - } - - public static void removePendingEditor (final EditorEditor ed, - final ActionListener onDeleteComplete) - { - - if (!ed.isPending ()) - { - - throw new IllegalStateException ("Only pending editors can be deleted using this method."); - - } - - final ActionListener doDelete = new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - EditorsEnvironment.removeEditor (ed, - onDeleteComplete); - - } - - }; - - EditorsEnvironment.editorsHandler.deleteInvite (ed, - new EditorsWebServiceAction () - { - - public void processResult (EditorsWebServiceResult res) - { - - doDelete.actionPerformed (new ActionEvent ("delete", 1, " delete")); - - } - }, - new EditorsWebServiceAction () - { - - public void processResult (EditorsWebServiceResult res) - { - - // If the invite couldn't be found then just delete the editor anyway since it's - // probably been removed from the QW end. - if (res.isNoDataFoundError ()) - { - - doDelete.actionPerformed (new ActionEvent ("delete", 1, " delete")); - - } else { - - EditorsEnvironment.editorsHandler.getDefaultEditorsWebServiceErrorAction ().processResult (res); - - } - - } - - }); - - } - - public static void removeEditor (final EditorEditor ed, - final ActionListener onComplete) - { - - if (ed.isPrevious ()) - { - - if (onComplete != null) - { - - UIUtils.doLater (onComplete); - - } - - } - - // It may be that the user deletes their account and the editor is in a pending - // state but doesn't have an account so we can't send them a message. Instead just - // delete the invite. - if ((ed.isPending ()) - && - (ed.getTheirPublicKey () == null) - ) - { - - try - { - - // Uupdate the editor to be previous. - ed.setEditorStatus (EditorEditor.EditorStatus.previous); - - EditorsEnvironment.updateEditor (ed); - - } catch (Exception e) { - - Environment.logError ("Unable to update editor: " + - ed, - e); - - AbstractViewer viewer = Environment.getFocusedViewer (); - - UIUtils.showErrorMessage (viewer, - getUIString (LanguageStrings.editors,editor,edit,actionerror)); - //"Unable to update {editor}, please contact Quoll Writer support for assistance."); - - return; - - } - - if (onComplete != null) - { - - UIUtils.doLater (onComplete); - - } - - return; - - } - - // Send the editor removed message - EditorRemovedMessage mess = new EditorRemovedMessage (ed); - - EditorsEnvironment.sendMessageToEditor (mess, - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - try - { - - // Uupdate the editor to be previous. - ed.setEditorStatus (EditorEditor.EditorStatus.previous); - - EditorsEnvironment.updateEditor (ed); - - } catch (Exception e) { - - Environment.logError ("Unable to update editor: " + - ed, - e); - - AbstractViewer viewer = Environment.getFocusedViewer (); - - UIUtils.showErrorMessage (viewer, - getUIString (LanguageStrings.editors,editor,edit,actionerror)); - //"Unable to update {editor}, please contact Quoll Writer support for assistance."); - - return; - - } - - try - { - - EditorsEnvironment.removeEditorAsProjectEditorForAllProjects (ed); - - } catch (Exception e) { - - Environment.logError ("Unable to remove editor as project editor: " + - ed, - e); - - AbstractViewer viewer = Environment.getFocusedViewer (); - - UIUtils.showErrorMessage (viewer, - getUIString (LanguageStrings.editors,editor,edit,actionerror)); - //"Unable to update {editor}, please contact Quoll Writer support for assistance."); - - return; - - } - - // Unsubscribe. - EditorsEnvironment.messageHandler.unsubscribeFromEditor (ed); - - if (onComplete != null) - { - - UIUtils.doLater (onComplete); - - } - - } - - }, - null, - null); - - } - - public static EditorMessage getMessageByKey (int key) - throws GeneralException - { - - if (EditorsEnvironment.editorsManager == null) - { - - return null; - - } - - return (EditorMessage) (DataObject) EditorsEnvironment.editorsManager.getObjectByKey (EditorMessage.class, - key, - null, // parent object - null, // connection - true); - - } - - public static void addMessage (EditorMessage mess) - throws GeneralException - { - - // TODO: This needs to be changed, ok for now. - if (mess instanceof InteractionMessage) - { - - return; - - } - - EditorsEnvironment.editorsManager.saveObject (mess, - null); - - mess.getEditor ().addMessage (mess); - - EditorsEnvironment.fireEditorMessageEvent (new EditorMessageEvent (mess.getEditor (), - mess, - EditorMessageEvent.MESSAGE_ADDED)); - - } - - public static void updateMessage (EditorMessage mess) - throws GeneralException - { - - EditorsEnvironment.editorsManager.saveObject (mess, - null); - - // Fire an event. - EditorsEnvironment.fireEditorMessageEvent (new EditorMessageEvent (mess.getEditor (), - mess, - EditorMessageEvent.MESSAGE_CHANGED)); - - } - - public static void updateProjectEditor (ProjectEditor pe) - throws GeneralException - { - - EditorsEnvironment.editorsManager.saveObject (pe, - null); - - // Fire an event. - EditorsEnvironment.fireProjectEditorChangedEvent (pe, - ProjectEditorChangedEvent.PROJECT_EDITOR_CHANGED); - - } - - public static void updateEditor (EditorEditor ed) - throws GeneralException - { - - EditorsEnvironment.editorsManager.saveObject (ed, - null); - - // Fire an event. - EditorsEnvironment.fireEditorChangedEvent (ed, - EditorChangedEvent.EDITOR_CHANGED); - - } - - public static void addNewEditor (EditorEditor ed) - throws GeneralException - { - - EditorsEnvironment.editorsManager.saveObject (ed, - null); - - EditorsEnvironment.editors.add (ed); - - // Fire an event. - EditorsEnvironment.fireEditorChangedEvent (ed, - EditorChangedEvent.EDITOR_ADDED); - - } - - public static void deleteEditor (EditorEditor ed) - throws GeneralException - { - - EditorsEnvironment.editorsManager.deleteObject (ed, - false, - null); - - EditorsEnvironment.editors.remove (ed); - - // Fire an event. - EditorsEnvironment.fireEditorChangedEvent (ed, - EditorChangedEvent.EDITOR_DELETED); - - } - - public static EditorEditor getEditorByEmail (String em) - { - - if (em == null) - { - - return null; - - } - - em = em.toLowerCase (); - - for (EditorEditor ed : EditorsEnvironment.editors) - { - - if ((ed.getEmail () != null) - && - (ed.getEmail ().equals (em)) - ) - { - - return ed; - - } - - } - - return null; - - } - - public static EditorEditor getEditorByMessagingUsername (String u) - { - - if (u == null) - { - - return null; - - } - - for (EditorEditor ed : EditorsEnvironment.editors) - { - - if ((ed.getMessagingUsername () != null) - && - (ed.getMessagingUsername ().equals (u)) - ) - { - - return ed; - - } - - } - - return null; - - } - - public static EditorEditor getEditorByKey (long key) - { - - if (key < 1) - { - - return null; - - } - - for (EditorEditor ed : EditorsEnvironment.editors) - { - - if (ed.getKey () == key) - { - - return ed; - - } - - } - - return null; - - } - - /** - * Return a count of the number of editors with a status of "pending". - * - * @return The count. - */ - public static int getPendingEditorsCount () - { - - int c = 0; - - for (EditorEditor ed : EditorsEnvironment.editors) - { - - if (ed.getEditorStatus () == EditorEditor.EditorStatus.pending) - { - - c++; - - } - - } - - return c; - - } - - public static List getEditors () - { - - return EditorsEnvironment.editors; - - } - - public static void fireProjectEvent (ProjectEvent ev) - { - - // We'll see? - // Fire to all project viewers? - - } - - public static String getNewMessageId (EditorEditor ed, - String messageType) - throws Exception - { - - return EditorsEnvironment.editorsManager.getNewMessageId (ed, - messageType); - - } - - /* - public static com.gentlyweb.properties.Properties getUserEditorsProperties () - { - - return Environment.userEditorsProperties; - - } -*/ - public static void setEditorsProperty (String name, - AbstractProperty prop) - throws Exception - { - - EditorsEnvironment.editorsProps.setProperty (name, - prop); - - EditorsEnvironment.saveEditorsProperties (null); - - } - - public static void setEditorsProperty (String name, - String value) - throws Exception - { - - EditorsEnvironment.editorsProps.setProperty (name, - new StringProperty (name, - value)); - - EditorsEnvironment.saveEditorsProperties (null); - - } - - public static void setEditorsProperty (String name, - boolean value) - throws Exception - { - - EditorsEnvironment.editorsProps.setProperty (name, - new BooleanProperty (name, - value)); - - EditorsEnvironment.saveEditorsProperties (null); - - } - - public static void removeEditorsProperty (String name) - throws Exception - { - - EditorsEnvironment.editorsProps.removeProperty (name); - - EditorsEnvironment.saveEditorsProperties (null); - - } - - public static void saveEditorsProperties (com.gentlyweb.properties.Properties props) - throws Exception - { - - if (props == null) - { - - props = EditorsEnvironment.editorsProps; - - } - - // Load the per user properties. - File pf = Environment.getUserEditorsPropertiesFile (); - - JDOMUtils.writeElementToFile (props.getAsJDOMElement (), - pf, - true); - - } - - public static boolean getEditorsPropertyAsBoolean (String name) - { - - return EditorsEnvironment.editorsProps.getPropertyAsBoolean (name); - - } - - public static String getEditorsProperty (String name) - { - - return EditorsEnvironment.editorsProps.getProperty (name); - - } - - public static boolean isShowPopupWhenNewMessageReceived () - { - - // Never show popups in full screen mode. - if (Environment.isInFullScreen ()) - { - - return false; - - } - - return false; - //return EditorsEnvironment.getEditorsPropertyAsBoolean (Constants.EDITORS_SHOW_POPUP_WHEN_NEW_MESSAGE_RECEIVED_PROPERTY_NAME); - - } -/* - public static void setShowPopupWhenNewMessageReceived (boolean v) - throws Exception - { - - BooleanProperty prop = new BooleanProperty (Constants.EDITORS_SHOW_POPUP_WHEN_NEW_MESSAGE_RECEIVED_PROPERTY_NAME, - v); - EditorsEnvironment.setEditorsProperty (Constants.EDITORS_SHOW_POPUP_WHEN_NEW_MESSAGE_RECEIVED_PROPERTY_NAME, - prop); - - } -*/ - public static void fullScreenEntered () - { - - // Get the current status. - if (EditorsEnvironment.isUserLoggedIn ()) - { - - if (EditorsEnvironment.getEditorsPropertyAsBoolean (Constants.QW_EDITORS_SERVICE_SET_BUSY_ON_FULL_SCREEN_ENTERED_PROPERTY_NAME)) - { - - - // Get the current status, if it's not "busy" then change it to busy. - if (EditorsEnvironment.getUserOnlineStatus () != EditorEditor.OnlineStatus.busy) - { - - EditorsEnvironment.lastOnlineStatus = EditorsEnvironment.getUserOnlineStatus (); - - try - { - - EditorsEnvironment.setUserOnlineStatus (EditorEditor.OnlineStatus.busy); - - } catch (Exception e) { - - Environment.logError ("Unable to set user online status to busy", - e); - - } - - } - - } - - } - - } - - public static void fullScreenExited () - { - - if (EditorsEnvironment.lastOnlineStatus != null) - { - - try - { - - EditorsEnvironment.setUserOnlineStatus (EditorsEnvironment.lastOnlineStatus); - - } catch (Exception e) { - - Environment.logError ("Unable to set user online status to last: " + - EditorsEnvironment.lastOnlineStatus, - e); - - } - - EditorsEnvironment.lastOnlineStatus = null; - - } - - // Check for new messages and show a notification if there are any. - EditorsEnvironment.checkForUndealtWithMessages (); - - } - - /** - * Show a warning message if the editor is offline when the user is trying to send them a message. - * - * @param ed The editor the user is sending a message to. - */ - public static void showMessageSendWarningIfEditorOfflineMessage (EditorEditor ed) - { - - if (ed.isOffline ()) - { - - // TODO: Next release change this to be more in context. - // Has the user seen this before? - //if (!EditorsEnvironment.getEditorsPropertyAsBoolean (Constants.EDITORS_SEEN_OFFLINE_SEND_MESSAGE_PROPERTY_NAME)) - //{ - - AbstractViewer viewer = Environment.getFocusedViewer (); - - UIUtils.showMessage ((PopupsSupported) viewer, - getUIString (LanguageStrings.editors,messages,editoroffline,popup,title), - //"{Editor} is offline", - String.format (getUIString (LanguageStrings.editors,messages,editoroffline,popup,text), - //"%s is currently offline. Your message will be stored on the server (encrypted) until they log in again and retrieve the message.

    Note: this applies whenever you send a message to {an editor} that is offline. This message won't be shown again.", - ed.getShortName ())); - - try - { - - EditorsEnvironment.setEditorsProperty (Constants.EDITORS_SEEN_OFFLINE_SEND_MESSAGE_PROPERTY_NAME, - true); - - } catch (Exception e) { - - Environment.logError ("Unable to set property", - e); - - } - - //} - - } - - - } - - public static URL getReportMessageURL () - throws Exception - { - - return new URL (Environment.getQuollWriterWebsite () + Environment.getProperty (Constants.EDITORS_SERVICE_REPORT_MESSAGE_PAGE_PROPERTY_NAME)); - - } - - private static void removeAllEditors (final Deque eds, - final ActionListener onComplete) - { - - if (eds.size () == 0) - { - - if (onComplete != null) - { - - onComplete.actionPerformed (new ActionEvent ("deleted", 1, "deleted")); - - } - - } else { - - EditorEditor ed = eds.pop (); - - ActionListener onDeleteComplete = new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - EditorsEnvironment.removeAllEditors (eds, - onComplete); - - } - - }; - - if (ed.isPending ()) - { - - EditorsEnvironment.removePendingEditor (ed, - onDeleteComplete); - - } else { - - EditorsEnvironment.removeEditor (ed, - onDeleteComplete); - - } - - } - - } - - public static void deleteUserAccount (final ActionListener onComplete, - final ActionListener onError) - { - - // Send EditorRemoved messages for all editors (but don't remove them). - EditorsEnvironment.goOnline (getUIString (LanguageStrings.editors,login,reasons,deleteaccount), - //"To delete your account you must first go online.", - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - EditorsEnvironment.removeAllEditors (new ArrayDeque (EditorsEnvironment.editors), - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - ActionListener deleteAcc = new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - // Delete the account. - EditorsEnvironment.editorsHandler.deleteAccount (new EditorsWebServiceAction () - { - - public void processResult (EditorsWebServiceResult res) - { - - // Sign out. - EditorsEnvironment.goOffline (); - - // Remove saved values (if present). - try - { - - EditorsEnvironment.removeEditorsProperty (Constants.QW_EDITORS_SERVICE_PASSWORD_PROPERTY_NAME); - - } catch (Exception e) { - - Environment.logError ("Unable to remove editors property", - e); - - } - - // Close all the db connections. - EditorsEnvironment.editorsManager.closeConnectionPool (); - - EditorsEnvironment.editorAccount = null; - - try - { - - EditorsEnvironment.removeEditorsProperty (Constants.QW_EDITORS_DB_DIR_PROPERTY_NAME); - - } catch (Exception e) { - - Environment.logError ("Unable to remove editors database location", - e); - - } - - if (onComplete != null) - { - - onComplete.actionPerformed (new ActionEvent ("deleted", 1, "deleted")); - - } - - } - }, - new EditorsWebServiceAction () - { - - public void processResult (EditorsWebServiceResult res) - { - - Environment.logError ("Unable to delete user account: " + - res); - - if (onError != null) - { - - onError.actionPerformed (new ActionEvent (res, 1, "error")); - - } else { - - UIUtils.showErrorMessage (Environment.getFocusedViewer (), - getUIString (LanguageStrings.editors,user,deleteaccount,actionerror)); - //"Unable to delete your account, please contact Quoll Writer support for assistance."); - - } - - } - - }); - - - - } - }; - - // Offer to remove all the editor projects. - EditorsUIUtils.showDeleteProjectsForAllEditors (Environment.getFocusedViewer (), - deleteAcc); - - } - - }); - - } - - }, - null, - onError); - - } - - public static File getEditorsMessageLogFile () - { - - return new File (Environment.getLogDir (), - Constants.EDITOR_MESSAGES_LOG_NAME); - - } - -} diff --git a/src/com/quollwriter/editors/EditorsMessageHandler.java b/src/com/quollwriter/editors/EditorsMessageHandler.java deleted file mode 100644 index 5870e11a..00000000 --- a/src/com/quollwriter/editors/EditorsMessageHandler.java +++ /dev/null @@ -1,1511 +0,0 @@ -package com.quollwriter.editors; - -import java.io.*; -import java.util.*; -import java.util.concurrent.atomic.*; - -import javax.net.ssl.*; - -import java.awt.event.*; -import javax.swing.*; - -import org.jxmpp.util.*; -import org.jivesoftware.smack.*; -import org.jivesoftware.smack.chat.*; -import org.jivesoftware.smack.roster.*; -import org.jivesoftware.smack.packet.*; -import org.jivesoftware.smack.filter.*; -import org.jivesoftware.smack.provider.*; -import org.jivesoftware.smack.util.*; -import org.jivesoftware.smack.tcp.*; - -import org.jivesoftware.smackx.iqregister.*; -import org.jivesoftware.smackx.offline.*; - -import com.gentlyweb.logging.Logger; - -//import com.gentlyweb.utils.*; - -import com.quollwriter.*; -import com.quollwriter.ui.*; -import com.quollwriter.ui.components.QPopup; -import com.quollwriter.data.editors.*; -import com.quollwriter.editors.ui.*; -import com.quollwriter.editors.messages.*; - -import static com.quollwriter.LanguageStrings.*; -import static com.quollwriter.Environment.getUIString; - -public class EditorsMessageHandler implements ChatMessageListener -{ - - private static String SERVER_SUFFIX = null; - - private XMPPTCPConnection conn = null; - - private String userJID = null; - private boolean loggedIn = false; - private EditorMessageProcessor messageProcessor = null; - private boolean logMessages = false; - private Logger messageLog = null; - - // We use an atomic integer here (rather than volatile which has problems with value increment/decrement) - // to keep track of how many messages we are in the process of sending. This is most useful when sending a - // large message and the user has closed down the last project viewer. For example if they send their project - // then close QW straight after. - private AtomicInteger messageSendInProgressCount = new AtomicInteger (0); - - private volatile boolean logoutRequested = false; - - public EditorsMessageHandler () - { - - this.messageProcessor = new DefaultEditorMessageProcessor (); - - } - - public void init () - throws Exception - { - - if (EditorsMessageHandler.SERVER_SUFFIX == null) - { - - EditorsMessageHandler.SERVER_SUFFIX = EditorsEnvironment.getEditorsProperty (Constants.EDITORS_JID_SUFFIX_PROPERTY_NAME); - - if (EditorsMessageHandler.SERVER_SUFFIX == null) - { - - EditorsMessageHandler.SERVER_SUFFIX = "@www.quollwriter.com"; - - } - - } - - File lf = EditorsEnvironment.getEditorsMessageLogFile (); - - lf.delete (); - - this.messageLog = new Logger (); - this.messageLog.initLogFile (lf); - - } - - private void logMessage (String text) - { - - this.logMessage (text, - null); - - } - - private void logMessage (String text, - EditorMessage mess) - { - - if ((this.logMessages) - || - (Environment.isDebugModeEnabled ()) - ) - { - - String t = text + (mess != null ? ": " + mess : ""); - - if (this.messageLog != null) - { - - this.messageLog.logInformationMessage (t); - - } else { - - Environment.logMessage (t); - - } - - } - - } - - public void logMessages (boolean v) - { - - this.logMessages = v; - - } - - public boolean isMessageSendInProgress () - { - - return this.messageSendInProgressCount.intValue () > 0; - - } - - public boolean isLoggedIn () - { - - return this.loggedIn; - - } - - public EditorEditor.OnlineStatus getOnlineStatus (EditorEditor ed) - { - - if ((this.conn == null) - || - (ed == null) - || - (!this.loggedIn) - ) - { - - return null; - - } - - Roster r = Roster.getInstanceFor (this.conn); - - if (r == null) - { - - return null; - - } - - return this.getOnlineStatus (r.getPresence (this.getJID (ed))); - - } - - public EditorEditor.OnlineStatus getOnlineStatus (Presence p) - { - - EditorEditor.OnlineStatus status = EditorEditor.OnlineStatus.offline; - - if (p == null) - { - - return status; - - } - - if (!p.isAvailable ()) - { - - return status; - - } - - switch (p.getMode ()) - { - - case available : - { - - return EditorEditor.OnlineStatus.online; - - } - - case away : - { - - return EditorEditor.OnlineStatus.away; - - } - - case dnd : - { - - return EditorEditor.OnlineStatus.busy; - - } - - case xa : - { - - return EditorEditor.OnlineStatus.snooze; - - } - - } - - return null; - - } - - public void setOnlineStatus (EditorEditor.OnlineStatus status) - throws Exception - { - - Presence.Type type = Presence.Type.available; - Presence.Mode mode = Presence.Mode.available; - - switch (status) - { - - case online : - { - - break; - - } - - case away : - { - - mode = Presence.Mode.away; - break; - - } - - case busy : - { - - mode = Presence.Mode.dnd; - break; - - } - - case snooze : - { - - mode = Presence.Mode.xa; - break; - - } - - } - - Presence presence = new Presence (type); - presence.setMode (mode); - this.conn.sendStanza (presence); - - } - - /** - * Set the object that will deal with the message once it has been received and built. - * We only allow a single instance, as opposed to a listener to prevent handling/displaying - * the message multiple times. The processor is basically responsible for updating the UI and/or - * bringing the message to the user's attention, usually via event firing or displaying popups. - * The processor should NOT save the message, this class handles that. - * - * Where a processor is not specified then an instance of {@link DefaultEditorMessageProcessor} - * will be used. - * - * @param p The processor. - */ - public void setMessageProcessor (EditorMessageProcessor p) - { - - this.messageProcessor = p; - - } - - private void handleMessageForUnknownEditor (final String fromUsername, - final Message message) - { - - final EditorsMessageHandler _this = this; - - this.logMessage ("Processing message for unknown editor: " + fromUsername); - - EditorsEnvironment.getInvite (fromUsername, - new EditorsWebServiceAction () - { - - @Override - public void processResult (EditorsWebServiceResult res) - { - - Map m = (Map) res.getReturnObject (); - - if (m == null) - { - - _this.logMessage ("No invite from unknown editor: " + fromUsername); - - // No invite. - return; - - } - - Invite invite = null; - - try - { - - invite = Invite.createFrom (m); - - } catch (Exception e) { - - Environment.logError ("Unable to create invite from: " + - m + - " from username: " + - fromUsername, - e); - - return; - - } - - // Is the invite deleted? If so just ignore the message. - if (invite.getStatus () == Invite.Status.deleted) - { - - return; - - } - - // Did I send the invite or receive it? - if (invite.getFromEmail ().equals (EditorsEnvironment.getUserAccount ().getEmail ())) - { - - // Send by me. - // Get the editor by their email. - EditorEditor ed = EditorsEnvironment.getEditorByEmail (invite.getToEmail ()); - - if (ed == null) - { - - Environment.logError ("Unable to find editor with email: " + - invite.getToEmail ()); - - return; - - } - - // Update the editor. - ed.setTheirPublicKey (invite.getToPublicKey ()); - - ed.setMessagingUsername (invite.getToMessagingUsername ()); - ed.setServiceName (invite.getToServiceName ()); - - try - { - - _this.processMessageForEditor (ed, - message); - - } catch (Exception e) { - - Environment.logError ("Unable to process message for editor: " + - ed, - e); - - } - - } else { - - // Invite I've received. - if ((invite.getStatus () == Invite.Status.rejected) - || - (invite.getStatus () == Invite.Status.accepted) - ) - { - - Environment.logError ("Illegal state, received invite from: " + - fromUsername + - " but invite status is: " + - invite.getStatus ().getType ()); - - // Already accepted/rejected the invite. - // Need to report. - return; - - } - - final Invite finvite = invite; - - if (invite.getStatus () == Invite.Status.pending) - { - - // Create a new holding editor. - EditorEditor ed = new EditorEditor (); - ed.setEmail (invite.getFromEmail ()); - ed.setTheirPublicKey (invite.getFromPublicKey ()); - - ed.setMessagingUsername (invite.getFromMessagingUsername ()); - ed.setServiceName (invite.getFromServiceName ()); - - try - { - - _this.processMessageForEditor (ed, - message); - - } catch (Exception e) { - - Environment.logError ("Unable to process message for editor: " + - ed, - e); - - } - - } - - } - - } - - }, - null); - - } - - private void processMessageForEditor (EditorEditor ed, - Message message) - throws Exception - { - - // All messages should be encrypted. - String body = message.getBody (); - - EditorMessage mess = null; - - try - { - - mess = MessageFactory.getMessage (body, - ed, - true); - - } catch (Exception e) { - - throw new GeneralException ("Unable to convert message", - e); - - } - - this.logMessage ("<<< Received", - mess); - - boolean saveMessage = false; - - try - { - - if (this.messageProcessor == null) - { - - this.messageProcessor = new DefaultEditorMessageProcessor (); - - } - - try - { - - saveMessage = this.messageProcessor.processMessage (mess); - - } catch (Exception e) { - - throw new GeneralException ("Unable to process message: " + - mess + - ", using: " + - this.messageProcessor, - e); - - } - - } finally { - - if ((saveMessage) - && - // May have a "fake" editor so don't save. - (ed.getKey () > 0) - ) - { - - try - { - - EditorsEnvironment.addMessage (mess); - - } catch (Exception e) { - - throw new GeneralException ("Unable to save message: " + - mess, - e); - - } - - } - - } - - } - - public void processMessage (final Chat chat, - final Message message) - { - - // Check to make sure we know who this is. - final String username = this.getUsernameFromJID (message.getFrom ()); - - this.logMessage ("Received message from user: " + username); - - final EditorEditor ed = EditorsEnvironment.getEditorByMessagingUsername (username); - - final EditorsMessageHandler _this = this; - - if (ed == null) - { - - // We don't know about this editor, get any invite from them. - this.handleMessageForUnknownEditor (username, - message); - - return; - - } - - if (ed.isRejected ()) - { - - // Send an unsubscribed, this user shouldn't be contacting us. - this.sendUnsubscribed (ed); - return; - - } - - if (ed.isPrevious ()) - { - - // They are a previous editor, this shouldn't be contacting us. - this.sendUnsubscribed (ed); - return; - - } - - if (ed.getTheirPublicKey () == null) - { - - // Get the invite and their public key. - EditorsEnvironment.getInvite (ed, - new EditorsWebServiceAction () - { - - @Override - public void processResult (EditorsWebServiceResult res) - { - - Map m = (Map) res.getReturnObject (); - - if (m == null) - { - - Environment.logError ("Unable to get invite for editor: " + - ed); - - // No invite. - return; - - } - - Invite invite = null; - - try - { - - invite = Invite.createFrom (m); - - } catch (Exception e) { - - Environment.logError ("Unable to create invite from: " + - m + - " from editor: " + - ed, - e); - - return; - - } - - if (invite.getStatus () == Invite.Status.rejected) - { - - Environment.logError ("Received message from: " + - ed + - " even though associated invite is rejected."); - - return; - - } - - if (invite.getStatus () == Invite.Status.pending) - { - - Environment.logError ("Received message from: " + - ed + - " even though invite is pending."); - - return; - - } - - // We are interested in the to public key here since "we" sent the - // invite. - ed.setTheirPublicKey (invite.getToPublicKey ()); - - try - { - - EditorsEnvironment.updateEditor (ed); - - } catch (Exception e) - { - - Environment.logError ("Unable to update editor: " + - ed, - e); - - return; - - } - - // Now process the message. - try - { - - _this.processMessageForEditor (ed, - message); - - } catch (Exception e) { - - Environment.logError ("Unable to process message for editor: " + - ed, - e); - - } - - } - - }, - null); - - return; - - } - - try - { - - this.processMessageForEditor (ed, - message); - - } catch (Exception e) { - - Environment.logError ("Unable to process message for editor: " + - ed, - e); - - } - - } - - private boolean shouldShowLogin () - { - - return (EditorsEnvironment.getUserAccount () == null) - || - (EditorsEnvironment.getUserAccount ().getPassword () == null); - - } - - private void doLogin (final String loginReason, - final ActionListener onLogin, - final ActionListener onCancel) - { - - final EditorsMessageHandler _this = this; - - if (!this.shouldShowLogin ()) - { - - this.login (onLogin, - null); - - return; - - } - - EditorsEnvironment.goOnline (loginReason, - onLogin, - onCancel, - null); - - } - - public void logout (final ActionListener onLogout) - { - - if (this.isMessageSendInProgress ()) - { - - this.logoutRequested = true; - - return; - - } - - this.logoutRequested = false; - - this.userJID = null; - this.loggedIn = false; - - final EditorsMessageHandler _this = this; - - new Thread (new Runnable () - { - - public void run () - { - - if (_this.conn != null) - { - - try - { - - _this.conn.disconnect (); - - _this.conn = null; - - } catch (Exception e) { } - - if (onLogout != null) - { - - onLogout.actionPerformed (new ActionEvent ("logout", 1, "logout")); - - } - - } - - } - - }).start (); - - } - - public void changePassword (final String newPassword, - final ActionListener onComplete, - final ActionListener onError) - { - - final EditorsMessageHandler _this = this; - - this.doLogin (getUIString (editors,login,reasons,changepassword), - //"To change your password you must first login to the Editors service.", - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - try - { - - AccountManager.getInstance (_this.conn).changePassword (newPassword); - - if (onComplete != null) - { - - onComplete.actionPerformed (new ActionEvent ("complete", 1, "")); - - } - - } catch (Exception e) { - - Environment.logError ("Unable to change password", - e); - - if (onError != null) - { - - onError.actionPerformed (new ActionEvent (e, 1, "error")); - - return; - - } - - UIUtils.showErrorMessage (Environment.getFocusedViewer (), - getUIString (editors,user,changepassword,actionerror)); - //"Unable to change password, please contact Quoll Writer support for assistance."); - - } - - - } - - }, - onError); - - } - - public void login (final ActionListener onLogin, - final ActionListener onError) - { - - final EditorsMessageHandler _this = this; - - this.logoutRequested = false; - - if (this.loggedIn) - { - - if (onLogin != null) - { - - onLogin.actionPerformed (new ActionEvent ("login", 1, "login")); - - } - - return; - - } - - new Thread (new Runnable () - { - - public void run () - { - - try - { - - EditorAccount acc = EditorsEnvironment.getUserAccount (); - - int port = 5222; - - try - { - - port = Integer.parseInt (EditorsEnvironment.getEditorsProperty (Constants.EDITORS_SERVICE_PORT_PROPERTY_NAME)); - - } catch (Exception e) { - - // ??? - - } - - XMPPTCPConnectionConfiguration config = XMPPTCPConnectionConfiguration.builder () - .setUsernameAndPassword (acc.getMessagingUsername (), - acc.getPassword ()) - .setServiceName (acc.getServiceName ()) - .setConnectTimeout (10 * 1000) - .setCompressionEnabled (true) - //.setDebuggerEnabled (true) - .setPort (port) - .build (); - - _this.conn = new XMPPTCPConnection (config); - - _this.conn.setUseStreamManagement (true); - _this.conn.setPacketReplyTimeout (30 * 3000); - - try - { - - _this.conn.connect (); - - } catch (Exception e) { - - Environment.logError ("Unable to connect to Editors service", - e); - - if (onError != null) - { - - UIUtils.doLater (onError); - - } else { - - EditorsUIUtils.showLoginError (getUIString (editors,login,errors,other)); - //"Unable to connect to the Editors service, please contact Quoll Writer support for assistance."); - - } - - return; - - } - - _this.userJID = _this.conn.getUser (); - - final Roster roster = Roster.getInstanceFor (_this.conn); - - roster.setSubscriptionMode (Roster.SubscriptionMode.manual); - - ChatManager chatMan = ChatManager.getInstanceFor (_this.conn); - - chatMan.addChatListener (new ChatManagerListener () - { - - public void chatCreated (Chat chat, boolean createdLocally) - { - - if (!createdLocally) - { - - chat.addMessageListener (_this); - - } - - } - - }); - - // Add a check for subscriptions. - _this.conn.addAsyncStanzaListener (new StanzaListener () - { - - public void processPacket (Stanza p) - { - - if (p instanceof Presence) - { - - Presence pp = (Presence) p; - - final Presence pre = (Presence) p; - - final String username = EditorsMessageHandler.getUsernameFromJID (pre.getFrom ()); - - final String jid = pre.getFrom (); - - final EditorEditor ed = EditorsEnvironment.getEditorByMessagingUsername (username); - - if (pre.getType () == Presence.Type.unsubscribe) - { - - // Send unsubscribe. - _this.sendPresence (Presence.Type.unsubscribed, - pre.getFrom ()); - - return; - - - } - - if (pre.getType () == Presence.Type.subscribed) - { - - } - - if (pre.getType () == Presence.Type.subscribe) - { - - if ((ed == null) - || - (ed.getEditorStatus () == EditorEditor.EditorStatus.rejected) - ) - { - - // No idea who this is, just return unsubscribed. - _this.sendPresence (Presence.Type.unsubscribed, - pre.getFrom ()); - - return; - - } - - _this.sendSubscribedToEditor (ed); - - - } - - } - - } - - }, - new StanzaFilter () - { - - public boolean accept (Stanza p) - { - - if (p instanceof Presence) - { - - return true; - - } - /* - if (super.accept (p)) - { - - Presence pp = (Presence) p; - - return true; - - } - */ - return false; - - } - - }); - - // Enable automatic reconnection. - ReconnectionManager.getInstanceFor (_this.conn).enableAutomaticReconnection (); - - try - { - - _this.conn.login (); - - } catch (Exception e) { - - Environment.logError ("User: " + - acc.getEmail () + - " is unable to login to editors service.", - e); - - EditorsUIUtils.showLoginError (getUIString (editors,login,errors,invalidcredentials)); - //"Unable to login. Please check your email and password."); - - if (onError != null) - { - - UIUtils.doLater (onError); - - } - - return; - - } - - for (EditorEditor ed : EditorsEnvironment.getEditors ()) - { - - Presence p = roster.getPresence (_this.getJID (ed)); - - EditorEditor.OnlineStatus status = _this.getOnlineStatus (p); - - ed.setOnlineStatus (status); - - EditorsEnvironment.fireEditorChangedEvent (new EditorChangedEvent (ed, - EditorChangedEvent.EDITOR_CHANGED)); - - } - - roster.addRosterListener (new RosterListener () - { - - public void entriesAdded (Collection addrs) - { - - } - - public void entriesDeleted (Collection addrs) - { - - } - - public void entriesUpdated (Collection addrs) - { - - } - - public void presenceChanged (Presence p) - { - - try - { - - // Get the editor associated with the presence. - String jid = p.getFrom (); - - String username = EditorsMessageHandler.getUsernameFromJID (jid); - - EditorEditor ed = EditorsEnvironment.getEditorByMessagingUsername (username); - - if (ed != null) - { - - ed.setOnlineStatus (_this.getOnlineStatus (p)); - - EditorsEnvironment.fireEditorChangedEvent (new EditorChangedEvent (ed, - EditorChangedEvent.EDITOR_CHANGED)); - - } - - } catch (Exception e) { - - Environment.logError ("Unable to update editor", - e); - - } - - } - - }); - - _this.loggedIn = true; - - if (onLogin != null) - { - - UIUtils.doLater (onLogin); - - } - - } catch (Exception e) { - - Environment.logError ("Unable to login", - e); - - if (onError != null) - { - - UIUtils.doLater (onError); - - } else { - - EditorsUIUtils.showLoginError (getUIString (editors,login,errors,other)); - //"Unable to login to the Editors service, please contact Quoll Writer support for assistance."); - - } - - } - - } - - }).start (); - - } - - private static String getUsernameFromJID (String jid) - { - - return XmppStringUtils.unescapeLocalpart (XmppStringUtils.parseLocalpart (jid)); - - } - - private static String getJID (EditorEditor ed) - { - - return ed.getMessagingUsername () + "@" + ed.getServiceName (); - - } - - private void sendUnsubscribed (EditorEditor ed) - { - - // Just in case. - String jid = this.getJID (ed); - - try - { - - Presence ret = new Presence (Presence.Type.unsubscribed); - ret.setTo (jid); - this.conn.sendStanza (ret); - - } catch (Exception e) { - - Environment.logError ("Unable to send unsubscribed presence to: " + - jid, - e); - - } - - } - - private void sendPresence (Presence.Type type, - String to) - { - - try - { - - Presence ret = new Presence (type); - ret.setTo (to); - this.conn.sendStanza (ret); - - } catch (Exception e) { - - Environment.logError ("Unable to send presence: " + - type + - " to: " + - to, - e); - - } - - } - - private void sendSubscribedToEditor (final EditorEditor ed) - { - - try - { - - String jid = this.getJID (ed); - - this.sendPresence (Presence.Type.subscribed, - jid); - - } catch (Exception e) { - - Environment.logError ("Unable to send subscribed to editor: " + ed, - e); - - } - - } - - public void unsubscribeFromEditor (final EditorEditor ed) - { - - final EditorsMessageHandler _this = this; - - new Thread (new Runnable () - { - - public void run () - { - - String jid = _this.getJID (ed); - - _this.sendPresence (Presence.Type.unsubscribe, - jid); - _this.sendPresence (Presence.Type.unsubscribed, - jid); - - } - - }).start (); - - } - - public void subscribeToEditor (final EditorEditor ed) - { - - final EditorsMessageHandler _this = this; - - new Thread (new Runnable () - { - - public void run () - { - - try - { - - String jid = _this.getJID (ed); - - Roster.getInstanceFor (_this.conn).createEntry (jid, - null, - null); - - _this.sendPresence (Presence.Type.subscribe, - jid); - - - //_this.sendMyPublicKeyToEditor (ed); - - } catch (Exception e) { - - /* - AbstractProjectViewer viewer = Environment.getFocusedProjectViewer (); - - UIUtils.showErrorMessage (viewer, - "Unable to subscribe to editor: " + ed.getEmail ()); -*/ - Environment.logError ("Unable to subscribe to editor: " + ed, - e); - - } - - } - - }).start (); - - } - - public void sendMessage (final String loginReason, - final EditorMessage mess, - final EditorEditor to, - final ActionListener onSend, - final ActionListener onLoginCancel) - { - - this.sendMessage (loginReason, - mess, - to, - onSend, - onLoginCancel, - null); - - } - - public void sendMessage (final String loginReason, - final EditorMessage mess, - final EditorEditor to, - final ActionListener onSend, - final ActionListener onLoginCancel, - final ActionListener onError) - { - - final EditorsMessageHandler _this = this; - - this.logoutRequested = false; - - if (to.isPrevious ()) - { - - Environment.logError ("Trying to send message to previous editor: " + to + ", message is: " + mess); - - if (onError != null) - { - - UIUtils.doLater (onError, - new Exception ("Trying to send message to: " + to)); - - } - - return; - - } - - this.doLogin (loginReason, - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - // TODO: Next release change this to be more in context. - //EditorsEnvironment.showMessageSendWarningIfEditorOfflineMessage (to); - - if (_this.messageSendInProgressCount.intValue () < 0) - { - - _this.messageSendInProgressCount.set (0); - - } - - _this.messageSendInProgressCount.incrementAndGet (); - - Thread t = new Thread (new Runnable () - { - - public void run () - { - - try - { - - _this.logMessage (">>> Sending", - mess); - - mess.setEditor (to); - mess.setSentByMe (true); - mess.setWhen (new Date ()); - mess.setDealtWith (true); - - Map data = mess.toMap (); - - String dmess = JSONEncoder.encode (data); - - byte[] bmess = dmess.getBytes (); - - if (mess.isEncrypted ()) - { - - if (to.getTheirPublicKey () == null) - { - - throw new GeneralException ("Invalid state, no public key available for editor: " + - to + - ", unable to send message: " + - mess); - - } - - bmess = EditorsUtils.encrypt (dmess, - EditorsEnvironment.getUserAccount ().getPrivateKey (), - to.getTheirPublicKey ()); - - mess.setOriginalMessage (new String (bmess, "utf-8")); - - } else { - - mess.setOriginalMessage (dmess); - - } - - Chat c = ChatManager.getInstanceFor (_this.conn).createChat (_this.getJID (to), - _this); - - Message m = new Message (); - m.setBody (new String (bmess, "utf-8")); - m.setType (Message.Type.normal); - - c.sendMessage (m); - - // Save the message away. - EditorsEnvironment.addMessage (mess); - - if (onSend != null) - { - - UIUtils.doLater (onSend); - - } - - } catch (Exception e) { - - if (onError != null) - { - - UIUtils.doLater (onError, - new Exception ("Unable to send message to " + to, - e)); - - } else { - - AbstractViewer viewer = Environment.getFocusedViewer (); - - UIUtils.showErrorMessage (viewer, - String.format (getUIString (editors,messages,send,actionerror), - to.getName ())); - //"Unable to send message to " + to.getName () + ". Please contact Quoll Writer support for assistance."); - - Environment.logError ("Unable to send message to: " + - to, - e); - - } - - } finally { - - _this.messageSendInProgressCount.decrementAndGet (); - - if ((_this.messageSendInProgressCount.intValue () <= 0) - && - (_this.logoutRequested) - ) - { - - _this.logout (null); - - } - - } - - } - - }); - - t.setDaemon (false); - - t.start (); - - } - - }, - onLoginCancel); - - } - -} diff --git a/src/com/quollwriter/editors/ui/ChatMessageAccordionItem.java b/src/com/quollwriter/editors/ui/ChatMessageAccordionItem.java deleted file mode 100644 index e4c7a5c7..00000000 --- a/src/com/quollwriter/editors/ui/ChatMessageAccordionItem.java +++ /dev/null @@ -1,88 +0,0 @@ -package com.quollwriter.editors.ui; - -import java.awt.Component; -import java.awt.Point; -import java.awt.Color; -import java.awt.Dimension; -import java.awt.Image; -import java.awt.image.*; -import java.awt.event.*; -import java.awt.dnd.*; - -import java.util.Date; -import java.util.List; -import java.util.ArrayList; -import java.util.StringTokenizer; -import java.util.Set; -import java.util.LinkedHashSet; - -import javax.swing.*; -import javax.swing.border.*; -import javax.swing.tree.*; - -import com.jgoodies.forms.builder.*; -import com.jgoodies.forms.factories.*; -import com.jgoodies.forms.layout.*; - -import com.quollwriter.data.*; -import com.quollwriter.data.editors.*; -import com.quollwriter.*; -import com.quollwriter.editors.*; -import com.quollwriter.events.*; -import com.quollwriter.editors.messages.*; -import com.quollwriter.ui.*; -import com.quollwriter.ui.actionHandlers.*; -import com.quollwriter.ui.components.ActionAdapter; -import com.quollwriter.ui.components.Header; -import com.quollwriter.ui.components.ImagePanel; -import com.quollwriter.ui.renderers.*; - -public class ChatMessageAccordionItem extends MessageAccordionItem -{ - - public ChatMessageAccordionItem (AbstractViewer pv, - Date d, - Set messages) - { - - super (pv, - d, - messages); - - } - - @Override - public JComponent getMessageBox (EditorChatMessage m) - { - - ChatMessageBox cmb = new ChatMessageBox (m, - this.viewer); - - try - { - - cmb.init (); - - } catch (Exception e) { - - Environment.logError ("Unable to init chat message box for message: " + - m, - e); - - } - - Box b = new Box (BoxLayout.X_AXIS); - b.setAlignmentX (Component.LEFT_ALIGNMENT); - - b.add (cmb); - - b.setBorder (new CompoundBorder (new MatteBorder (0, 0, 1, 0, UIUtils.getColor ("#eeeeee")), - UIUtils.createPadding (7, 5, 3, 5))); - b.setMaximumSize (new Dimension (Short.MAX_VALUE, - b.getPreferredSize ().height)); - - return b; - - } - -} \ No newline at end of file diff --git a/src/com/quollwriter/editors/ui/ChatMessageBox.java b/src/com/quollwriter/editors/ui/ChatMessageBox.java deleted file mode 100644 index 97bdae7b..00000000 --- a/src/com/quollwriter/editors/ui/ChatMessageBox.java +++ /dev/null @@ -1,175 +0,0 @@ -package com.quollwriter.editors.ui; - -import java.util.List; -import java.util.ArrayList; - -import java.awt.Image; -import java.awt.image.*; -import java.awt.Dimension; -import java.awt.event.*; -import java.awt.Component; -import java.awt.Point; -import javax.swing.*; -import javax.swing.border.*; - -import com.quollwriter.*; -import com.quollwriter.ui.*; -import com.quollwriter.ui.components.ImagePanel; -import com.quollwriter.editors.messages.*; -import com.quollwriter.editors.*; - -import static com.quollwriter.LanguageStrings.*; -import static com.quollwriter.Environment.getUIString; - -public class ChatMessageBox extends MessageBox -{ - - public ChatMessageBox (EditorChatMessage mess, - AbstractViewer viewer) - { - - super (mess, - viewer); - - } - - public boolean isAutoDealtWith () - { - - return true; - - } - - public void doUpdate () - { - - } - - public void doInit () - { - - //final JComponent b = this.getMessageQuoteComponent (this.message.getMessage ()); - - //this.add (b); - - Box b = new Box (BoxLayout.X_AXIS); - b.setAlignmentX (Component.LEFT_ALIGNMENT); - - this.add (b); - - JComponent message = UIUtils.createHelpTextPane (this.message.getMessage (), - this.viewer); - message.setAlignmentY (Component.TOP_ALIGNMENT); - message.setSize (new Dimension (300, - 500)); - - message.setBorder (null); - message.setOpaque (false); - message.setMaximumSize (new Dimension (Short.MAX_VALUE, - Short.MAX_VALUE)); - - String name = this.message.getEditor ().getMainName (); - - if (this.message.isSentByMe ()) - { - - BufferedImage av = EditorsEnvironment.getUserAccount ().getAvatar (); - - if (av != null) - { - - av = UIUtils.getScaledImage (av, - 28); - - if (av.getHeight () > 28) - { - - av = UIUtils.getScaledImage (av, - 28, - 28); - - } - - } - - message.setAlignmentX (Component.RIGHT_ALIGNMENT); - b.add (message); - - JComponent avl = this.createAvatar (av, - (av == null ? getUIString (editors,editor,view,chatmessages,sentbyme) + "
    " : "") + Environment.formatTime (this.message.getWhen ())); - avl.setBorder (UIUtils.createPadding (0, 5, 0, 0)); - b.add (avl); - - } else { - - message.setAlignmentX (Component.LEFT_ALIGNMENT); - BufferedImage av = this.message.getEditor ().getDisplayAvatar (); - - if (av == null) - { - - av = Environment.getNoEditorAvatarImage (); - - } - - av = UIUtils.getScaledImage (av, - 28); - - if (av.getHeight () > 28) - { - - av = UIUtils.getScaledImage (av, - 28, - 28); - - } - - JComponent avl = this.createAvatar (av, - Environment.formatTime (this.message.getWhen ())); - avl.setBorder (UIUtils.createPadding (0, 0, 0, 5)); - b.add (avl); - b.add (message); - - } - - } - - private JComponent createAvatar (Image im, - String message) - { - - Box b = new Box (BoxLayout.Y_AXIS); - - JLabel ic = new JLabel (); - - if (im != null) - { - - ic.setIcon (new ImageIcon (im)); - - ic.setBorder (UIUtils.createLineBorder ()); - - } - - ic.setAlignmentX (Component.RIGHT_ALIGNMENT); - - b.add (ic); - - b.add (Box.createVerticalStrut (0)); - - JLabel l = UIUtils.createInformationLabel (message); - l.setHorizontalTextPosition (JLabel.RIGHT); - l.setAlignmentX (Component.RIGHT_ALIGNMENT); - l.setForeground (UIUtils.getColor ("#aaaaaa")); - - l.setFont (l.getFont ().deriveFont (UIUtils.getScaledFontSize (10))); - b.add (l); - - b.setMaximumSize (b.getPreferredSize ()); - b.setAlignmentY (Component.TOP_ALIGNMENT); - - return b; - - } - -} diff --git a/src/com/quollwriter/editors/ui/CommentActionHandler.java b/src/com/quollwriter/editors/ui/CommentActionHandler.java deleted file mode 100644 index 69ca2f4d..00000000 --- a/src/com/quollwriter/editors/ui/CommentActionHandler.java +++ /dev/null @@ -1,543 +0,0 @@ -package com.quollwriter.editors.ui; - -import java.awt.Point; -import java.awt.Rectangle; -import java.awt.event.*; -import java.awt.font.*; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.StringTokenizer; -import java.util.Vector; -import java.util.Set; -import java.util.LinkedHashSet; - -import javax.swing.*; -import javax.swing.border.*; -import javax.swing.tree.*; -import javax.swing.text.*; - -import com.gentlyweb.properties.*; - -import com.quollwriter.*; -import com.quollwriter.text.*; -import com.quollwriter.data.*; - -import com.quollwriter.ui.*; -import com.quollwriter.ui.actionHandlers.*; -import com.quollwriter.ui.panels.*; -import com.quollwriter.ui.forms.*; -import com.quollwriter.ui.components.QTextEditor; -import com.quollwriter.ui.components.BlockPainter; -import com.quollwriter.ui.renderers.*; - -import com.quollwriter.editors.ui.panels.*; - -import static com.quollwriter.LanguageStrings.*; -import static com.quollwriter.Environment.getUIString; - -/** - * A comment action handler is really just a tweaked note action handler. A comment is a note but for - * the editor project viewer behaves a little differently. - * - * TODO: Merge/extend from NoteActionHandler? - */ -public class CommentActionHandler extends AbstractFormPopup //ProjectViewerActionHandler -{ - - private MultiLineTextFormItem comment = null; - protected Chapter chapter = null; - protected int showAt = -1; - private QTextEditor editor = null; - private ChapterItemViewer itemViewer = null; - - public CommentActionHandler (final Note n, - final ChapterItemViewer itemViewer) - { - - super (n, - itemViewer.getViewer (), - EDIT); - - this.chapter = n.getChapter (); - this.showAt = n.getPosition (); - - this.itemViewer = itemViewer; - - final EditorChapterPanel qep = (EditorChapterPanel) this.viewer.getEditorForChapter (this.chapter); - - this.setPopupOver (qep); - - this.editor = itemViewer.getEditor (); - - final int origSelStart = this.editor.getSelectionStart (); - - final BlockPainter highlight = new BlockPainter (Environment.getHighlightColor ()); - - final Caret origCaret = editor.getCaret (); - - final CommentActionHandler _this = this; - - this.setOnShowAction (new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - qep.setChapterItemEditVisible (true); - - editor.setCaret (new DefaultCaret () - { - - private boolean isVis = false; - - @Override - public void setSelectionVisible (boolean vis) - { - - _this.editor.removeAllHighlights (highlight); - - if (vis != this.isVis) { - this.isVis = vis; - super.setSelectionVisible(false); - super.setSelectionVisible(true); - } - - } - - }); - - if (n.getEndPosition () > n.getStartPosition ()) - { - - _this.editor.addHighlight (n.getStartPosition (), - n.getEndPosition (), - highlight, - false); - - } - - } - - }); - - this.setOnHideAction (new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - qep.setChapterItemEditVisible (false); - - _this.editor.removeAllHighlights (highlight); - - _this.editor.setCaret (origCaret); - - _this.editor.setSelectionStart (origSelStart); - - _this.editor.grabFocus (); - - } - - }); - - } - - public CommentActionHandler (Chapter c, - ChapterItemViewer itemViewer, - int showAt) - { - - super (new Note (0, - c), - itemViewer.getViewer (), - ADD); - - this.showAt = showAt; - - this.chapter = c; - - this.itemViewer = itemViewer; - - this.editor = itemViewer.getEditor (); - - final EditorChapterPanel qep = (EditorChapterPanel) this.viewer.getEditorForChapter (this.chapter); - - this.setPopupOver (qep); - - this.object.setType (Note.EDIT_NEEDED_NOTE_TYPE); - - final CommentActionHandler _this = this; - - this.setOnShowAction (new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - try - { - - _this.itemViewer.addItem (_this.getChapterItem ()); - - } catch (Exception e) - { - - Environment.logError ("Unable to add item: " + - _this.object + - " to editor panel", - e); - - } - - } - - }); - - } - - @Override - public Point getShowAtPosition () - { - - int y = 0; - - Point lastMousePosition = this.itemViewer.getLastMousePosition (); - - int at = this.showAt; - - QTextEditor editor = this.itemViewer.getEditor (); - - if (at == -1) - { - - // Calculate where it should be displayed. - String sel = editor.getSelectedText (); - - if ((sel != null) && - (!sel.trim ().equals (""))) - { - - // We have some text so use "at"... - at = editor.getSelectionStart (); - - } else - { - - int c = editor.getCaret ().getDot (); - - if (c >= 0) - { - - at = c; - - } else - { - - if (lastMousePosition != null) - { - - at = editor.viewToModel (new Point (lastMousePosition.x, - lastMousePosition.y)); - - } else - { - - at = editor.getText ().length () - 1; - - } - - } - - } - - } - - this.object.setPosition (at); - - Rectangle r = null; - - try - { - - r = editor.modelToView (at); - - } catch (Exception e) - { - - Environment.logError ("Position: " + - at + - " is not valid.", - e); - - return super.getShowAtPosition (); - - } - - JScrollPane scrollPane = this.itemViewer.getScrollPane (); - - y = r.y + 22 - scrollPane.getVerticalScrollBar ().getValue (); - - if ((y < 0) || - (y > (scrollPane.getViewport ().getViewRect ().height + scrollPane.getVerticalScrollBar ().getValue ()))) - { - - // Recalculate y since we have moved the scroll position. - y = r.y + 22; // - scrollPane.getVerticalScrollBar ().getValue (); - - } -/* - // Adjust the bounds so that the form is fully visible. - if ((y + this.f.getPreferredSize ().height) > (scrollPane.getViewport ().getViewRect ().height + scrollPane.getVerticalScrollBar ().getValue ())) - { - - y = y - 22 - this.f.getPreferredSize ().height; - - } - - y -= this.f.getPreferredSize ().height; - */ - int xOffset = this.itemViewer.getIconColumnXOffset (this.object); - - Point p = new Point (this.itemViewer.getIconColumn ().getWidth () - xOffset, - y); - - return p; - - } - - public Note getChapterItem () - { - - return this.object; - - } - - @Override - public JComponent getFocussedField () - { - - return this.comment; - - } - - @Override - public Icon getIcon (int iconTypeSize) - { - - return Environment.getIcon (Constants.COMMENT_ICON_NAME, - iconTypeSize); - - } - - @Override - public String getTitle () - { - - if (mode == CommentActionHandler.EDIT) - { - - return getUIString (comments,edit,title); - //"Edit Comment"; - - } - - return getUIString (comments,_new,title); - //"Add New Comment"; - - } - - @Override - public Set getFormItems (String selectedText) - { - - Set items = new LinkedHashSet (); - - this.comment = new MultiLineTextFormItem (null, - this.viewer, - getUIString (comments,addedit,labels,LanguageStrings.comment,tooltip), - //"Enter your comment here...", - 5, - -1, - false, - null); - - UIUtils.addDoActionOnReturnPressed (this.comment.getTextArea (), - this.getSaveAction ()); - - if (mode == CommentActionHandler.ADD) - { - - } else - { - - this.comment.setText (this.object.getDescription ()); - - } - - items.add (this.comment); - - return items; - - } - - @Override - public Set getFormErrors () - { - - Set errs = new LinkedHashSet (); - - if (this.comment.getValue () == null) - { - - errs.add (getUIString (comments,addedit,errors,novalue)); - //"Please enter a comment."); - - } - - return errs; - - } - - @Override - public void handleCancel () - { - - if (this.mode == ADD) - { - - this.itemViewer.removeItem (this.object); - - } - - } - - @Override - public boolean handleSave () - { - - String c = this.comment.getText (); - - this.object.setDescription (this.comment.getValue ()); - - // Use the first line of the description as the summary. - Paragraph p = new Paragraph (c, - 0); - - this.object.setSummary (p.getFirstSentence ().getText ()); - - String type = Note.EDIT_NEEDED_NOTE_TYPE; - - int s = this.editor.getSelectionStart (); - int e = this.editor.getSelectionEnd (); - - if ((mode == CommentActionHandler.EDIT) - && - (s != e) - && - (e > s) - ) - { - - this.object.setPosition (s); - this.object.setEndPosition (e); - - } - - if (mode == CommentActionHandler.ADD) - { - - this.object.setPosition (s); - this.object.setEndPosition (e); - - } - - try - { - - this.viewer.saveObject (this.object, - true); - - if (this.mode == CommentActionHandler.ADD) - { - - // Add the item to the chapter. - this.chapter.addNote (this.object); - - } - - this.viewer.fireProjectEvent (this.object.getObjectType (), - (this.mode == CommentActionHandler.ADD ? ProjectEvent.NEW : ProjectEvent.EDIT), - this.object); - - } catch (Exception ex) - { - - Environment.logError ("Unable to save/add comment: " + - this.object, - ex); - - UIUtils.showErrorMessage (this.viewer, - getUIString (comments,(this.mode == CommentActionHandler.ADD ? _new : edit),actionerror)); - //"Unable to " + ((this.mode == CommentActionHandler.ADD) ? "add new " : "save") + " comment."); - - return false; - - } - - try - { - - Position pos = this.editor.getDocument ().createPosition (this.object.getPosition ()); - - this.object.setTextPosition (pos); - - if (this.object.getEndPosition () > -1) - { - - this.object.setEndTextPosition (this.editor.getDocument ().createPosition (this.object.getEndPosition ())); - - } - - } catch (Exception ex) { - - Environment.logError ("Unable to set text position", - ex); - - } - - if (this.object.getChapter () != null) - { - - this.editor.grabFocus (); - - } - - // Need to reindex the chapter to ensure that things are in the right order. - this.chapter.reindex (); - - // Expand the note type. - this.viewer.showObjectInTree (Note.OBJECT_TYPE, - new TreeParentNode (Note.OBJECT_TYPE, - type)); - - this.viewer.reloadTreeForObjectType (Note.OBJECT_TYPE); - - this.viewer.reloadTreeForObjectType (Chapter.OBJECT_TYPE); - - if (e > s) - { - - this.editor.setSelectionEnd (s); - - } - - return true; - - } - -} diff --git a/src/com/quollwriter/editors/ui/DeleteCommentActionHandler.java b/src/com/quollwriter/editors/ui/DeleteCommentActionHandler.java deleted file mode 100644 index 0e793f63..00000000 --- a/src/com/quollwriter/editors/ui/DeleteCommentActionHandler.java +++ /dev/null @@ -1,118 +0,0 @@ -package com.quollwriter.editors.ui; - -import java.awt.*; -import java.awt.event.*; - -import javax.swing.*; - -import com.quollwriter.*; - -import com.quollwriter.data.*; - -import com.quollwriter.ui.*; -import com.quollwriter.ui.components.ActionAdapter; -import com.quollwriter.editors.ui.panels.*; - -import static com.quollwriter.LanguageStrings.*; -import static com.quollwriter.Environment.getUIString; - -public class DeleteCommentActionHandler extends ActionAdapter -{ - - private EditorProjectViewer projectViewer = null; - private Note item = null; - private boolean showAtItem = false; - - public DeleteCommentActionHandler (Note item, - EditorProjectViewer projectViewer, - boolean showAtItem) - { - - this.item = item; - this.projectViewer = projectViewer; - this.showAtItem = showAtItem; - - } - - public void actionPerformed (ActionEvent ev) - { - - final DeleteCommentActionHandler _this = this; - - Point showAt = null; - - // Sigh... - if (this.showAtItem) - { - - // Get the editor panel. - EditorChapterPanel p = this.projectViewer.getEditorForChapter (this.item.getChapter ()); - - if (p != null) - { - - showAt = p.getIconColumn ().getLocation (this.item); - - showAt = SwingUtilities.convertPoint (p, - showAt, - this.projectViewer); - - showAt.y -= p.getScrollOffset (); - - } - - } - - UIUtils.createQuestionPopup (this.projectViewer, - getUIString (comments,delete,popup,title), - //"Delete {Comment}", - Constants.DELETE_ICON_NAME, - String.format (getUIString (comments,delete,popup,text), - //"Please confirm you wish to delete {Comment}
       %s?", - this.item.getSummary ()), - getUIString (comments,delete,popup,buttons,confirm), - //"Yes, delete it", - getUIString (comments,delete,popup,buttons,cancel), - //null, - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.deleteItem (); - - } - - }, - null, - null, - showAt); - - } - - private void deleteItem () - { - - try - { - - this.projectViewer.deleteObject (this.item, - false); - - } catch (Exception e) - { - - Environment.logError ("Unable to delete comment: " + - this.item, - e); - - com.quollwriter.ui.UIUtils.showErrorMessage (this.projectViewer, - getUIString (comments,delete,actionerror)); - //"Unable to delete."); - - } - - } - -} diff --git a/src/com/quollwriter/editors/ui/EditorChaptersAccordionItem.java b/src/com/quollwriter/editors/ui/EditorChaptersAccordionItem.java deleted file mode 100644 index 933e61e8..00000000 --- a/src/com/quollwriter/editors/ui/EditorChaptersAccordionItem.java +++ /dev/null @@ -1,337 +0,0 @@ -package com.quollwriter.editors.ui; - -import java.awt.Component; -import java.awt.Point; -import java.awt.event.*; -import java.awt.dnd.*; - -import java.util.List; -import java.util.ArrayList; -import java.util.Enumeration; -import java.util.Arrays; - -import javax.swing.*; -import javax.swing.tree.*; - -import com.quollwriter.data.*; -import com.quollwriter.*; -import com.quollwriter.ui.*; -import com.quollwriter.ui.sidebars.*; -import com.quollwriter.ui.actionHandlers.*; -import com.quollwriter.ui.components.ActionAdapter; -import com.quollwriter.ui.renderers.*; -import com.quollwriter.editors.ui.panels.*; - -import static com.quollwriter.LanguageStrings.*; -import static com.quollwriter.Environment.getUIString; - -public class EditorChaptersAccordionItem extends ChaptersAccordionItem -{ - - public EditorChaptersAccordionItem (AbstractProjectViewer pv) - { - - super (pv); - - } - - @Override - public void fillHeaderPopupMenu (JPopupMenu m, - MouseEvent ev) - { - - } - - @Override - public void reloadTree () - { - - java.util.List openPaths = new ArrayList (); - - Enumeration paths = this.tree.getExpandedDescendants (new TreePath (this.tree.getModel ().getRoot ())); - - if (paths != null) - { - - while (paths.hasMoreElements ()) - { - - openPaths.add (paths.nextElement ()); - - } - - } - - ((DefaultTreeModel) this.tree.getModel ()).setRoot (EditorsUIUtils.createTree (this.viewer.getProject (), - null, - null, - false)); - - DefaultTreeModel dtm = (DefaultTreeModel) this.tree.getModel (); - - DefaultMutableTreeNode root = (DefaultMutableTreeNode) dtm.getRoot (); - - for (TreePath p : openPaths) - { - - this.tree.expandPath (UIUtils.getTreePathForUserObject (root, - ((DefaultMutableTreeNode) p.getLastPathComponent ()).getUserObject ())); - - } - - } - - @Override - public void initTree () - { - - ((DefaultTreeModel) this.tree.getModel ()).setRoot (EditorsUIUtils.createTree (this.viewer.getProject (), - null, - null, - false)); - - this.tree.setCellRenderer (new ProjectTreeCellRenderer (true) - { - - public Component getTreeCellRendererComponent (JTree tree, - Object value, - boolean sel, - boolean expanded, - boolean leaf, - int row, - boolean hasFocus) - { - - Component co= super.getTreeCellRendererComponent (tree, - value, - sel, - expanded, - leaf, - row, - hasFocus); - - DefaultMutableTreeNode node = (DefaultMutableTreeNode) value; - - value = node.getUserObject (); - - if (value instanceof Chapter) - { - - Chapter c = (Chapter) value; - - String n = c.getName (); - - int s = c.getNotes ().size (); - - if (s > 0) - { - - n += " (" + c.getNotes ().size () + ")"; - - } - - this.setText (n); - - } - - return this; - - } - - @Override - public String getIconType (DataObject d, - DefaultMutableTreeNode par) - { - - if (d instanceof Note) - { - - return Constants.COMMENT_ICON_NAME; - - } - - return super.getIconType (d, - par); - - } - - }); - - } - - @Override - public void fillTreePopupMenu (JPopupMenu m, - MouseEvent ev) - { - - final EditorChaptersAccordionItem _this = this; - - final AbstractProjectViewer pv = this.viewer; - - final TreePath tp = this.tree.getPathForLocation (ev.getX (), - ev.getY ()); - - JMenuItem mi = null; - - if (tp != null) - { - - final DefaultMutableTreeNode node = (DefaultMutableTreeNode) tp.getLastPathComponent (); - - final DataObject d = (DataObject) node.getUserObject (); - - if (d instanceof Note) - { - - final Note n = (Note) d; - - java.util.List prefix = Arrays.asList (editors,project,sidebar,comments,treepopupmenu,comments,items); - - m.add (UIUtils.createMenuItem (getUIString (prefix,view), - //"View", - Constants.VIEW_ICON_NAME, - new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - pv.viewObject (n); - - } - - })); - - m.add (UIUtils.createMenuItem (getUIString (prefix,edit), - //"Edit", - Constants.EDIT_ICON_NAME, - pv.getAction (EditorProjectViewer.EDIT_COMMENT_ACTION, - n))); - - m.add (UIUtils.createMenuItem (getUIString (prefix,delete), - //"Delete", - Constants.DELETE_ICON_NAME, - pv.getAction (EditorProjectViewer.DELETE_COMMENT_ACTION, - n))); - - } - - if (d instanceof Chapter) - { - - java.util.List prefix = Arrays.asList (editors,project,sidebar,comments,treepopupmenu,chapters,items); - - final Chapter c = (Chapter) d; - - final String chapterObjTypeName = Environment.getObjectTypeName (c); - - m.add (UIUtils.createMenuItem (getUIString (prefix,view), - //"Edit {Chapter}", - Constants.VIEW_ICON_NAME, - pv.getAction (ProjectViewer.EDIT_CHAPTER_ACTION, - c))); -/* - m.add (UIUtils.createMenuItem ("View {Chapter} Information", - Constants.INFO_ICON_NAME, - pv.getAction (ProjectViewer.VIEW_CHAPTER_INFO_ACTION, - c))); -*/ - if (!c.isEditComplete ()) - { - - m.add (UIUtils.createMenuItem (getUIString (prefix,seteditcomplete), - //"Set as Edit Complete", - Constants.EDIT_COMPLETE_ICON_NAME, - new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - EditorChapterPanel qp = (EditorChapterPanel) pv.getEditorForChapter (c); - - qp.setEditComplete (true); - - } - - })); - - } else { - - m.add (UIUtils.createMenuItem (getUIString (prefix,seteditneeded), - //"Set as Edit Needed", - Constants.EDIT_ICON_NAME, - new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - EditorChapterPanel qp = (EditorChapterPanel) pv.getEditorForChapter (c); - - qp.setEditComplete (false); - - } - - })); - - } - - if (c.getEditPosition () > 0) - { - - m.add (UIUtils.createMenuItem (getUIString (prefix,removeeditposition), - //"Remove Edit Point", - Constants.CANCEL_ICON_NAME, - new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - EditorChapterPanel qp = (EditorChapterPanel) pv.getEditorForChapter (c); - - qp.removeEditPosition (); - - } - - })); - - } - - m.add (UIUtils.createMenuItem (getUIString (prefix,close), - //"Close {Chapter}", - Constants.CLOSE_ICON_NAME, - new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - pv.closePanel (c); - - } - - })); - - } - - } - - } - - public boolean isTreeEditable () - { - - return false; - - } - - public boolean isDragEnabled () - { - - return false; - - } - -} diff --git a/src/com/quollwriter/editors/ui/EditorChatBox.java b/src/com/quollwriter/editors/ui/EditorChatBox.java deleted file mode 100644 index 8c0a1372..00000000 --- a/src/com/quollwriter/editors/ui/EditorChatBox.java +++ /dev/null @@ -1,359 +0,0 @@ -package com.quollwriter.editors.ui; - -import java.awt.Component; -import java.awt.Dimension; -import java.awt.Color; -import java.awt.event.*; - -import java.util.Date; -import java.util.List; -import java.util.ArrayList; - -import javax.swing.*; -import javax.swing.border.*; - -import com.quollwriter.data.editors.*; -import com.quollwriter.ui.*; -import com.quollwriter.events.*; -import com.quollwriter.editors.*; -import com.quollwriter.*; -import com.quollwriter.editors.messages.*; -import com.quollwriter.ui.components.ActionAdapter; - -import static com.quollwriter.LanguageStrings.*; -import static com.quollwriter.Environment.getUIString; - -public class EditorChatBox extends Box implements EditorInteractionListener -{ - - private EditorEditor editor = null; - private TextArea message = null; - private AbstractViewer viewer = null; - private boolean typingStartedSent = false; - private JLabel notification = null; - - public EditorChatBox (EditorEditor ed, - AbstractViewer viewer) - { - - super (BoxLayout.Y_AXIS); - - this.editor = ed; - this.viewer = viewer; - - } - - public EditorChatBox init () - { - - this.message = UIUtils.createTextArea (getUIString (editors,LanguageStrings.editor,sendchat,box,tooltip), - //"Enter your message here...\n\nTo send press Ctrl+Enter or use the button below.", - 5, - -1); - - this.message.setBorder (null); - - final EditorChatBox _this = this; - - this.add (this.message); - - this.notification = UIUtils.createLoadingLabel (getUIString (editors,LanguageStrings.editor,sendchat,sending)); - //"Sending message..."); - - final ActionListener sendMessageAction = new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - String text = _this.message.getText ().trim (); - - if (text.length () == 0) - { - - return; - - } - - _this.showSending (); - - _this.notification.setVisible (true); - - _this.validate (); - _this.repaint (); - - // Add the message to the today list. - final Date when = new Date (); - - final Date w = Utils.zeroTimeFields (when); - - final EditorChatMessage m = new EditorChatMessage (text, - true, - _this.editor, - when); - - m.setDealtWith (true); - - EditorsEnvironment.sendMessageToEditor (m, - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.hideNotification (); - - _this.message.setText (""); - _this.message.grabFocus (); - - _this.validate (); - _this.repaint (); - - } - - }, - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.hideNotification (); - - _this.validate (); - _this.repaint (); - - } - - }, - null); - - } - - }; - - JButton save = UIUtils.createButton ("send-message", - Constants.ICON_MENU, - getUIString (editors,LanguageStrings.editor,sendchat,box,buttons,send,tooltip), - //"Click to send the message", - sendMessageAction); - - JButton cancel = UIUtils.createButton (Constants.CANCEL_ICON_NAME, - Constants.ICON_MENU, - getUIString (editors,LanguageStrings.editor,sendchat,box,buttons,LanguageStrings.cancel,tooltip), - //"Click to cancel", - new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.message.setText (""); - - } - - }); - - List buts = new ArrayList (); - - buts.add (save); - buts.add (cancel); - - JToolBar tb = UIUtils.createButtonBar (buts); - - tb.setAlignmentX (Component.LEFT_ALIGNMENT); - - Box buttons = new Box (BoxLayout.X_AXIS); - buttons.setAlignmentX (Component.LEFT_ALIGNMENT); - buttons.add (Box.createHorizontalStrut (3)); - buttons.add (this.notification); - buttons.add (Box.createHorizontalGlue ()); - buttons.add (tb); - - buttons.setBorder (new CompoundBorder (new MatteBorder (1, - 0, - 0, - 0, - UIUtils.getColor ("#dddddd")), - new EmptyBorder (2, - 2, - 2, - 2))); - - - this.add (buttons); - - final Timer typingStop = new Timer (1500, - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.typingStartedSent = false; - - // Send stopped message. - _this.sendStoppedTyping (); - - } - - }); - - typingStop.setRepeats (false); - - final Timer typingStart = new Timer (750, - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - typingStop.stop (); - - if (!_this.typingStartedSent) - { - - _this.typingStartedSent = true; - - // Send the message. - _this.sendStartedTyping (); - - } - - typingStop.restart (); - - } - - }); - - typingStart.setCoalesce (true); - typingStart.setRepeats (false); - - this.message.addKeyListener (new KeyAdapter () - { - - private boolean typed = false; - - public void keyPressed (KeyEvent ev) - { - - typingStop.stop (); - typingStart.start (); - - if ((ev.getKeyCode () == KeyEvent.VK_ENTER) && - ((ev.getModifiersEx () & InputEvent.CTRL_DOWN_MASK) == InputEvent.CTRL_DOWN_MASK)) - { - - _this.sendStoppedTyping (); - - sendMessageAction.actionPerformed (new ActionEvent (message, 1, "sending")); - - } - - if ((ev.getKeyCode () == KeyEvent.VK_BACK_SPACE) && - ((ev.getModifiersEx () & InputEvent.CTRL_DOWN_MASK) == InputEvent.CTRL_DOWN_MASK)) - { - - _this.message.setText (""); - - } - - } - - }); - - this.message.setBorder (null); - - this.setMaximumSize (new Dimension (Short.MAX_VALUE, - this.getPreferredSize ().height)); - this.setMinimumSize (this.getPreferredSize ()); - - EditorsEnvironment.addEditorInteractionListener (this); - - return this; - - } - - @Override - public void handleInteraction (EditorInteractionEvent ev) - { - - if (this.editor != ev.getEditor ()) - { - - return; - - } - - if (ev.getAction () == InteractionMessage.Action.typing) - { - - this.showTyping (); - - } - - if (ev.getAction () == InteractionMessage.Action.normal) - { - - this.hideNotification (); - - } - - } - - public void grabFocus () - { - - this.message.grabFocus (); - - } - - private void hideNotification () - { - - this.notification.setVisible (false); - - } - - private void showTyping () - { - - this.notification.setText (String.format (getUIString (editors,LanguageStrings.editor,sendchat,contactistyping), - this.editor.getShortName ())); - //this.editor.getShortName () + " is typing..."); - this.notification.setIcon (Environment.getTypingIcon ()); - - this.notification.setVisible (true); - - } - - private void showSending () - { - - this.notification.setText (getUIString (editors,LanguageStrings.editor,sendchat,sending)); - //"Sending message..."); - this.notification.setIcon (Environment.getLoadingIcon ()); - - this.notification.setVisible (true); - - } - - private void sendStartedTyping () - { - - EditorsEnvironment.sendInteractionMessageToEditor (InteractionMessage.Action.typing, - this.editor, - null); - - } - - private void sendStoppedTyping () - { - - EditorsEnvironment.sendInteractionMessageToEditor (InteractionMessage.Action.normal, - this.editor, - null); - - } - -} diff --git a/src/com/quollwriter/editors/ui/EditorInfoBox.java b/src/com/quollwriter/editors/ui/EditorInfoBox.java deleted file mode 100644 index 5ee8b548..00000000 --- a/src/com/quollwriter/editors/ui/EditorInfoBox.java +++ /dev/null @@ -1,2137 +0,0 @@ -package com.quollwriter.editors.ui; - -import java.awt.Component; -import java.awt.Font; -import java.awt.AWTEvent; -import java.awt.event.*; -import java.awt.image.*; -import javax.swing.plaf.LayerUI; - -import java.util.Set; -import java.util.HashSet; -import java.util.LinkedHashSet; -import java.util.Iterator; -import java.util.Map; -import java.util.HashMap; - -import java.io.*; - -import javax.swing.*; -import javax.swing.border.*; - -import com.quollwriter.ui.*; -import com.quollwriter.*; -import com.quollwriter.data.*; -import com.quollwriter.data.editors.*; -import com.quollwriter.events.*; -import com.quollwriter.editors.ui.*; -import com.quollwriter.editors.*; -import com.quollwriter.editors.ui.sidebars.*; -import com.quollwriter.editors.messages.*; -import com.quollwriter.ui.components.ActionAdapter; - -import static com.quollwriter.LanguageStrings.*; -import static com.quollwriter.Environment.getUIString; - -public class EditorInfoBox extends Box implements EditorChangedListener, EditorMessageListener -{ - - private EditorEditor editor = null; - private AbstractViewer viewer = null; - private JLabel avatar = null; - private JLabel mainName = null; - private JLabel onlineStatus = null; - private JLabel other = null; - private Box details = null; - private Box editorInfo = null; - private JButton projectMessages = null; - private JButton importantMessages = null; - private JButton comments = null; - private JButton chat = null; - private boolean showProjectInfo = false; - private ProjectEditor projEditor = null; - private MessageBox pendingMessageBox = null; - private Project proj = null; - private boolean editorProject = false; - - public EditorInfoBox (EditorEditor ed, - AbstractViewer viewer, - boolean showProjectInfo) - throws GeneralException - { - - super (BoxLayout.Y_AXIS); - - final EditorInfoBox _this = this; - - this.editor = ed; - - this.showProjectInfo = showProjectInfo; - - if ((this.showProjectInfo) - && - (!(viewer instanceof AbstractProjectViewer)) - ) - { - - throw new IllegalArgumentException ("To show project information then a project viewer must be provided."); - - } - - if (viewer instanceof AbstractProjectViewer) - { - - this.proj = ((AbstractProjectViewer) viewer).getProject (); - - this.editorProject = this.proj.isEditorProject (); - - } - - // Load the messages. - EditorsEnvironment.loadMessagesForEditor (this.editor); - - // We add ourselves as a listener for editor change events however we don't ever - // remove ourselves since, as a standard component, we don't have a fixed lifecycle. - EditorsEnvironment.addEditorChangedListener (this); - - EditorsEnvironment.addEditorMessageListener (this); - - this.setAlignmentX (Component.LEFT_ALIGNMENT); - - this.viewer = viewer; - - if (this.viewer instanceof AbstractProjectViewer) - { - - this.projEditor = ((AbstractProjectViewer) this.viewer).getProject ().getProjectEditor (this.editor); - - } - - this.editorInfo = new Box (BoxLayout.X_AXIS); - this.editorInfo.setAlignmentX (Component.LEFT_ALIGNMENT); - - JLayer infoWrapper = new JLayer (this.editorInfo, new LayerUI () - { - - @Override - public void installUI(JComponent c) { - super.installUI(c); - // enable mouse motion events for the layer's subcomponents - ((JLayer) c).setLayerEventMask(AWTEvent.MOUSE_EVENT_MASK); - } - - @Override - public void uninstallUI(JComponent c) { - super.uninstallUI(c); - // reset the layer event mask - ((JLayer) c).setLayerEventMask(0); - } - - @Override - public void processMouseEvent (MouseEvent ev, - JLayer l) - { - - // TODO: Check for multi-platform compatibility. - if (ev.getID () != MouseEvent.MOUSE_RELEASED) - { - - return; - - } - - if (ev.getSource () instanceof JButton) - { - - return; - - } - - if (_this.editor.getEditorStatus () == EditorEditor.EditorStatus.pending) - { - - return; - - } - - if (ev.getClickCount () != 1) - { - - return; - - } - - if (ev.isPopupTrigger ()) - { - - return; - - } - - // Show the editor. - try - { - - _this.viewer.sendMessageToEditor (_this.editor); - - } catch (Exception e) { - - Environment.logError ("Unable to show editor: " + - _this.editor, - e); - - UIUtils.showErrorMessage (_this.viewer, - getUIString (editors,LanguageStrings.editor,view,actionerror)); - //"Unable to show {editor}."); - - } - - } - - }); - - infoWrapper.setAlignmentX (Component.LEFT_ALIGNMENT); - - this.add (infoWrapper); - - this.setOpaque (false); - - this.avatar = new JLabel (); - - this.avatar.setAlignmentY (Component.TOP_ALIGNMENT); - - this.editorInfo.add (this.avatar); - this.avatar.setOpaque (false); - - this.avatar.setBorder (new CompoundBorder (UIUtils.createPadding (0, 0, 0, 5), - UIUtils.createLineBorder ())); - - final boolean pending = ed.isPending (); - - this.details = new Box (BoxLayout.Y_AXIS); - details.setAlignmentY (Component.TOP_ALIGNMENT); - - JLabel l = new JLabel (""); - l.setBorder (null); - l.setVerticalAlignment (JLabel.TOP); - l.setAlignmentX (Component.LEFT_ALIGNMENT); - l.setFont (l.getFont ().deriveFont ((float) UIUtils.getScaledFontSize (14)).deriveFont (java.awt.Font.PLAIN)); - - //l.setFont (l.getFont ().deriveFont ((float) 16).deriveFont (Font.PLAIN)); - l.setAlignmentY (Component.TOP_ALIGNMENT); - l.setVerticalAlignment (SwingConstants.TOP); - this.details.add (l); - this.mainName = l; - - l = UIUtils.createInformationLabel (null); - this.onlineStatus = l; - - UIUtils.setPadding (l, 0, 3, 0, 5); - //this.details.add (this.onlineStatus); - - l.setVisible (false); - //l.setAlignmentY (Component.TOP_ALIGNMENT); - //l.setVerticalAlignment (SwingConstants.TOP); - UIUtils.setPadding (l, 0, 3, 0, 5); - - l = UIUtils.createInformationLabel (null); - l.setVisible (false); - UIUtils.setPadding (l, 3, 3, 0, 5); - this.details.add (l); - - this.other = l; - - this.projectMessages = UIUtils.createButton (Project.OBJECT_TYPE, - Constants.ICON_MENU, - "", - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - try - { - - EditorsUIUtils.showProjectMessagesForEditor (_this.editor, - (AbstractProjectViewer) _this.viewer, - _this.projectMessages); - - } catch (Exception e) { - - Environment.logError ("Unable to show project messages for editor: " + - _this.editor, - e); - - UIUtils.showErrorMessage (_this.viewer, - getUIString (editors,messages,show,project,actionerror)); - //"Unable to show {project} messages for {editor}."); - - } - - } - - }); - - this.projectMessages.setIconTextGap (2); - this.projectMessages.setFont (this.projectMessages.getFont ().deriveFont (Font.BOLD, - 14)); - - this.importantMessages = UIUtils.createButton (Constants.ERROR_ICON_NAME, - Constants.ICON_MENU, - "", - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - try - { - - EditorsUIUtils.showImportantMessagesForEditor (_this.editor, - _this.viewer, - _this.importantMessages); - - } catch (Exception e) { - - Environment.logError ("Unable to show important messages for editor: " + - _this.editor, - e); - - UIUtils.showErrorMessage (_this.viewer, - getUIString (editors,messages,show,important,actionerror)); - //"Unable to show important messages for {editor}."); - - } - - } - - }); - - this.importantMessages.setIconTextGap (2); - this.importantMessages.setFont (this.importantMessages.getFont ().deriveFont (Font.BOLD, - 14)); - - this.comments = UIUtils.createButton (Constants.COMMENT_ICON_NAME, - Constants.ICON_MENU, - "", - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - try - { - - EditorsUIUtils.showAllCommentsForEditor (_this.editor, - (AbstractProjectViewer) _this.viewer, - _this.comments); - - } catch (Exception e) { - - Environment.logError ("Unable to show comments for editor: " + - _this.editor, - e); - - UIUtils.showErrorMessage (_this.viewer, - getUIString (editors,LanguageStrings.editor,view,actionerror)); - //"Unable to show {comments} for {editor}."); - - } - - } - - }); - - this.comments.setIconTextGap (2); - this.comments.setFont (this.comments.getFont ().deriveFont (Font.BOLD, - 14)); - - this.chat = UIUtils.createButton (Constants.MESSAGE_ICON_NAME, - Constants.ICON_MENU, - "", - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - try - { - - _this.viewer.sendMessageToEditor (_this.editor); - - } catch (Exception e) { - - Environment.logError ("Unable to show editor: " + - _this.editor, - e); - - UIUtils.showErrorMessage (_this.viewer, - getUIString (editors,LanguageStrings.editor,view,actionerror)); - //"Unable to show {editor}."); - - } - - } - - }); - - this.chat.setIconTextGap (2); - this.chat.setFont (this.projectMessages.getFont ().deriveFont (Font.BOLD, - 14)); - - Box statusBox = new Box (BoxLayout.X_AXIS); - - statusBox.setAlignmentX (Component.LEFT_ALIGNMENT); - this.details.add (statusBox); - - java.util.List buts = new java.util.ArrayList (); - buts.add (this.onlineStatus); - buts.add (this.importantMessages); - buts.add (this.comments); - buts.add (this.projectMessages); - buts.add (this.chat); - - statusBox.add (UIUtils.createButtonBar (buts)); - statusBox.add (Box.createHorizontalGlue ()); - - this.editorInfo.add (this.details); - - } - - public void setShowProjectInfo (boolean v) - { - - this.showProjectInfo = v; - - this.update (); - - } - - public boolean isShowProjectInfo () - { - - return this.showProjectInfo; - - } - - private boolean isShowAttentionBorder () - { - - final EditorInfoBox _this = this; - - // TODO: Investigate why this is needed, this is being called on closedown of QW. - // Probably from close of link to message server. - if (this.viewer instanceof AbstractProjectViewer) - { - - if (((AbstractProjectViewer) this.viewer).getProject () == null) - { - - return false; - - } - - } - - if (this.editor.isPrevious ()) - { - - return false; - - } - - return this.editor.getMessages (EditorsUIUtils.getImportantMessageFilter ()).size () > 0; - - } - - private Set getProjectComments () - { - - return this.editor.getMessages (new DefaultEditorMessageFilter (this.proj, - ProjectCommentsMessage.MESSAGE_TYPE)); - - } - - private Set getChatMessages () - { - - return this.editor.getMessages (new EditorMessageFilter () - { - - @Override - public boolean accept (EditorMessage m) - { - - if ((m.getMessageType ().equals (EditorChatMessage.MESSAGE_TYPE)) - && - (!m.isDealtWith ()) - ) - { - - return true; - - } - - return false; - - } - - }); - - } - - private Set getProjectMessages () - { - - final EditorInfoBox _this = this; - - final String projId = this.proj.getId (); - - return this.editor.getMessages (new EditorMessageFilter () - { - - @Override - public boolean accept (EditorMessage m) - { - - if (!projId.equals (m.getForProjectId ())) - { - - return false; - - } - - if ((m.getMessageType ().equals (NewProjectMessage.MESSAGE_TYPE)) - || - (m.getMessageType ().equals (NewProjectResponseMessage.MESSAGE_TYPE)) - || - (m.getMessageType ().equals (UpdateProjectMessage.MESSAGE_TYPE)) - || - (m.getMessageType ().equals (ProjectEditStopMessage.MESSAGE_TYPE)) - ) - { - - return true; - - } - - return false; - - } - - }); - - } - - private Set getImportantMessages () - { - - if (this.editor.isPrevious ()) - { - - return new HashSet (); - - } - - final EditorInfoBox _this = this; - - String _projId = ""; - - if (this.proj != null) - { - - _projId = this.proj.getId (); - - } - - final String projId = _projId; - - Set mess = this.editor.getMessages (new EditorMessageFilter () - { - - @Override - public boolean accept (EditorMessage m) - { - - if (!EditorsUIUtils.getImportantMessageFilter ().accept (m)) - { - - return false; - - } - - if (m.getMessageType ().equals (EditorChatMessage.MESSAGE_TYPE)) - { - - return false; - - } - - if (_this.showProjectInfo) - { - - if (projId.equals (m.getForProjectId ())) - { - - return false; - - } - - } - - return true; - - } - - }); - - return mess; - - } - public ProjectEditor getProjectEditor () - { - - return this.projEditor; - - - } - public EditorEditor getEditor () - { - - return this.editor; - - } - - public void handleMessage (EditorMessageEvent ev) - { - - if (ev.getEditor () == this.editor) - { - - this.update (); - - } - - } - - public void editorChanged (EditorChangedEvent ev) - { - - if (ev.getEditor () == this.editor) - { - - this.update (); - - } - - } - - private void update () - { - - if (this.proj != null) - { - - // TODO: Fix this. - if (((AbstractProjectViewer) this.viewer).getProject () == null) - { - - // We are closing down. - return; - - } - - } - - this.onlineStatus.setVisible (false); - this.other.setVisible (false); - this.projectMessages.setVisible (false); - this.importantMessages.setVisible (false); - - this.mainName.setText (this.editor.getMainName ()); - - BufferedImage bi = null; - - if (this.editor.getMainAvatar () != null) - { - - bi = UIUtils.getScaledImage (this.editor.getMainAvatar (), - 50); - - } else { - - bi = Environment.getNoEditorAvatarImage (); - - } - - this.avatar.setIcon (new ImageIcon (bi)); - - if (this.editor.getOnlineStatus () != null) - { - - String type = Constants.ONLINE_STATUS_ICON_NAME_PREFIX + this.editor.getOnlineStatus ().getType (); - - this.onlineStatus.setIcon (Environment.getIcon (type, - Constants.ICON_MENU_INNER)); - this.onlineStatus.setToolTipText (this.editor.getOnlineStatus ().getName ()); - //this.onlineStatus.setText (this.editor.getOnlineStatus ().getName ()); - this.onlineStatus.setText (""); - this.onlineStatus.setVisible (true); - this.onlineStatus.setMaximumSize (this.onlineStatus.getPreferredSize ()); - - } - - if (this.pendingMessageBox != null) - { - - this.pendingMessageBox.setVisible (false); - this.remove (this.pendingMessageBox); - - } - - if (!this.editor.isPending ()) - { - - UIUtils.setAsButton (this.editorInfo); - - if (!this.editor.isPrevious ()) - { - - this.editorInfo.setToolTipText (String.format (getUIString (editors,LanguageStrings.editor,view,info,tooltip,currenteditor), - //"Click to send a message to %s, right click to see the menu", - this.editor.getMainName ())); - - } else { - - this.editorInfo.setToolTipText (getUIString (editors,LanguageStrings.editor,view,info,tooltip,previouseditor)); - //"Right click to see the menu"); - - } - - } else { - - if (!this.editor.isInvitedByMe ()) - { - - this.other.setText (String.format (getUIString (editors,LanguageStrings.editor,view,LanguageStrings.other,pendingeditor,invitereceived), - //"Received: %s", - Environment.formatDate (this.editor.getDateCreated ()))); - - } else { - - this.other.setText (String.format (getUIString (editors,LanguageStrings.editor,view,LanguageStrings.other,pendingeditor,invitesent), - //"Invited: %s", - Environment.formatDate (this.editor.getDateCreated ()))); - - } - - this.other.setVisible (true); - - } - - //final String projId = this.projectViewer.getProject ().getId (); - - Set mess = this.getImportantMessages (); - - int ms = mess.size (); - - this.importantMessages.setForeground (java.awt.Color.black); - - if (ms > 0) - { - - this.importantMessages.setForeground (java.awt.Color.red); - - this.importantMessages.setToolTipText (String.format (getUIString (editors,LanguageStrings.editor,view,importantmessages,tooltip), - //"%s new/important message%s requiring your attention, click to view them", - Environment.formatNumber (ms))); - //(ms == 1 ? "" : "s"), - //(ms == 1 ? "s" : ""))); - - this.importantMessages.setText (String.format ("%s", - Environment.formatNumber (ms))); - - this.importantMessages.setVisible (true); - - } - /* - if (this.editor.isPending ()) - { - - this.importantMessages.setVisible (false); - - } - */ - - if (this.editor.isPrevious ()) - { - - this.onlineStatus.setIcon (Environment.getIcon (Constants.ERROR_RED_ICON_NAME, - Constants.ICON_MENU_INNER)); - this.onlineStatus.setToolTipText (getUIString (editors,LanguageStrings.editor,view,previouseditor,onlinestatus,tooltip)); - //"This is a previous {contact}.")); - this.onlineStatus.setText (""); - this.onlineStatus.setMaximumSize (this.onlineStatus.getPreferredSize ()); - - this.onlineStatus.setVisible (true); - - } - - if ((this.showProjectInfo) - && - ((this.projEditor != null) - || - (this.editorProject) - ) - ) - { - - if (this.projEditor != null) - { - - this.other.setVisible (true); - this.other.setText (Environment.replaceObjectNames (this.projEditor.getStatusMessage ())); - - } - - int undealtWithCount = 0; - - // Get undealt with messages that are not chat. - // If there is just one then show it, otherwise show a link that will display a popup of them. - Set projMess = this.getProjectMessages (); - - for (EditorMessage em : projMess) - { - - if (!em.isDealtWith ()) - { - - undealtWithCount++; - - } - - } - - int ps = projMess.size (); - - this.projectMessages.setForeground (java.awt.Color.black); - - if (undealtWithCount > 0) - { - - this.projectMessages.setForeground (java.awt.Color.red); - - this.projectMessages.setToolTipText (String.format (getUIString (editors,LanguageStrings.editor,view,projecteditor,undealtwithmessagecount,tooltip), - //"%s {project} message%s requiring your attention, click to view them", - Environment.formatNumber (undealtWithCount))); - //(undealtWithCount == 1 ? "" : "s"), - //(undealtWithCount == 1 ? "s" : ""))); - - } else { - - this.projectMessages.setToolTipText (String.format (getUIString (editors,LanguageStrings.editor,view,projecteditor,undealtwithmessagecount,tooltip), - //"%s {project} message%s, click to view them", - Environment.formatNumber (ps))); - //(projMess.size () == 1 ? "" : "s"), - //(projMess.size () == 1 ? "s" : ""))); - - } - - this.projectMessages.setText (String.format ("%s", - Environment.formatNumber (ps))); - - this.projectMessages.setVisible (true); - - } - - this.comments.setVisible (false); - - if (this.showProjectInfo) - { - - AbstractProjectViewer pv = (AbstractProjectViewer) this.viewer; - - int commCount = 0; - - if (!this.editor.isPending ()) - { - - this.comments.setVisible (true); - this.comments.setForeground (java.awt.Color.black); - - // Get undealt with messages that are not chat. - // If there is just one then show it, otherwise show a link that will display a popup of them. - Set comments = this.editor.getMessages (new DefaultEditorMessageFilter (pv.getProject (), - ProjectCommentsMessage.MESSAGE_TYPE)); - - if (comments.size () > 0) - { - - int sets = comments.size (); - int undealtWithCount = 0; - - for (EditorMessage m : comments) - { - - if (!m.isDealtWith ()) - { - - undealtWithCount++; - - - } - - ProjectCommentsMessage pcm = (ProjectCommentsMessage) m; - - commCount += pcm.getComments ().size (); - - } - - if (undealtWithCount > 0) - { - - this.comments.setForeground (java.awt.Color.red); - - } - - this.comments.setToolTipText (Environment.replaceObjectNames (String.format (getUIString (editors,LanguageStrings.editor,view,projectcomments,(this.projEditor != null ? received : sent),tooltip), - //"%s {comment%s} %s %s", - Environment.formatNumber (commCount), - //(commCount == 1 ? "" : "s"), - //(this.projEditor != null ? "from" : "sent to"), - this.editor.getShortName ()))); - - } else { - - if (this.projEditor != null) - { - - this.comments.setToolTipText (Environment.replaceObjectNames (String.format (getUIString (editors,LanguageStrings.editor,view,noprojectcomments,received,tooltip), - //"%s has not sent you any {comments} yet.", - this.editor.getShortName ()))); - - } else { - - this.comments.setToolTipText (Environment.replaceObjectNames (String.format (getUIString (editors,LanguageStrings.editor,view,noprojectcomments,sent,tooltip), - //"You have not sent any {comments} to %s yet.", - this.editor.getShortName ()))); - - } - - } - - this.comments.setText (Environment.formatNumber (commCount)); - - this.comments.setEnabled (commCount > 0); - - } - - } - - this.chat.setVisible (false); - - Set chatMessages = this.getChatMessages (); - - int chatMessagesSize = chatMessages.size (); - - if (chatMessagesSize > 0) - { - - this.chat.setForeground (java.awt.Color.red); - - this.chat.setToolTipText (Environment.replaceObjectNames (String.format (getUIString (editors,LanguageStrings.editor,view,unreadchatmessages,tooltip), - //"%s unread chat message%s", - Environment.formatNumber (chatMessagesSize)))); - - this.chat.setText (Environment.formatNumber (chatMessagesSize)); - - this.chat.setVisible (true); - - } - - if (this.isShowAttentionBorder ()) - { - - this.editorInfo.setBorder (new CompoundBorder (new MatteBorder (0, 2, 0, 0, UIUtils.getColor ("#ff0000")), - UIUtils.createPadding (0, 5, 0, 0))); - - } else { - - this.editorInfo.setBorder (null); - - } - - this.validate (); - this.repaint (); - - } - - public EditorInfoBox init () - { - - this.update (); - - return this; - - } - - public void addDeleteAllMessagesMenuItem (JPopupMenu menu) - { - - final EditorInfoBox _this = this; - - JMenuItem mi = null; - - if (Environment.isDebugModeEnabled ()) - { - - if ((this.proj != null) - && - (this.proj.getProjectEditor (_this.editor) != null) - ) - { - - menu.add (UIUtils.createMenuItem ("Remove {project} editor [Debug option]", - Constants.DELETE_ICON_NAME, - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - UIUtils.createTextInputPopup (_this.viewer, - "Remove {project} editor?", - Constants.DELETE_ICON_NAME, - String.format ("To remove %s as a {project} editor please enter Yes in the box below. Note: this will also remove all {project} related message types for this {project} (project-new, project-new-response, project-update, project-edit-stop, project-comments)", - _this.editor.getMainName ()), - "Yes, delete them", - Constants.CANCEL_BUTTON_LABEL_ID, - null, - UIUtils.getYesValueValidator (), - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - if (!_this.editor.messagesLoaded ()) - { - - try - { - - EditorsEnvironment.loadMessagesForEditor (_this.editor); - - } catch (Exception e) { - - Environment.logError ("Unable to load messages for editor: " + - _this.editor, - e); - - UIUtils.showErrorMessage (_this.viewer, - "Unable to load messages for editor."); - - return; - - } - - } - - final Set messages = _this.editor.getMessages (new DefaultEditorMessageFilter (_this.proj, - NewProjectMessage.MESSAGE_TYPE, - NewProjectResponseMessage.MESSAGE_TYPE, - UpdateProjectMessage.MESSAGE_TYPE, - ProjectEditStopMessage.MESSAGE_TYPE, - ProjectCommentsMessage.MESSAGE_TYPE)); - - try - { - - EditorsEnvironment.deleteMessages (messages); - - EditorsEnvironment.removeProjectEditor (_this.proj.getProjectEditor (_this.editor)); - - } catch (Exception e) { - - Environment.logError ("Unable to delete messages for editor: " + - _this.editor, - e); - - UIUtils.showErrorMessage (_this.viewer, - "Unable to delete messages for editor."); - - return; - - } - - UIUtils.showMessage ((PopupsSupported) _this.viewer, - "{Project} editor removed", - "All associated {project} messages have been deleted."); - - } - - }, - null, - null); - - } - - })); - - } - - menu.add (UIUtils.createMenuItem ("Delete all messages for types [Debug option]", - Constants.DELETE_ICON_NAME, - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - Box b = new Box (BoxLayout.Y_AXIS); - - Set types = new LinkedHashSet (); - - types.add (NewProjectMessage.MESSAGE_TYPE); - types.add (UpdateProjectMessage.MESSAGE_TYPE); - types.add (NewProjectResponseMessage.MESSAGE_TYPE); - types.add (ProjectEditStopMessage.MESSAGE_TYPE); - types.add (ProjectCommentsMessage.MESSAGE_TYPE); - types.add (InviteMessage.MESSAGE_TYPE); - types.add (InviteResponseMessage.MESSAGE_TYPE); - types.add (EditorChatMessage.MESSAGE_TYPE); - types.add (EditorInfoMessage.MESSAGE_TYPE); - types.add (EditorRemovedMessage.MESSAGE_TYPE); - - final Map cbs = new HashMap (); - - for (String t : types) - { - - JCheckBox cb = UIUtils.createCheckBox (t); - - cbs.put (t, - cb); - - b.add (cb); - - } - - UIUtils.showMessage (_this.viewer, - "Delete types of message", - b, - "Delete", - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - if (!_this.editor.messagesLoaded ()) - { - - try - { - - EditorsEnvironment.loadMessagesForEditor (_this.editor); - - } catch (Exception e) { - - Environment.logError ("Unable to load messages for editor: " + - _this.editor, - e); - - UIUtils.showErrorMessage (_this.viewer, - "Unable to load messages for editor."); - - return; - - } - - } - - Set selTypes = new LinkedHashSet (); - - for (String t : cbs.keySet ()) - { - - if (cbs.get (t).isSelected ()) - { - - selTypes.add (t); - - } - - } - - Set toDel = _this.editor.getMessages (null, - selTypes.toArray (new String[selTypes.size ()])); - - try - { - - EditorsEnvironment.deleteMessages (toDel); - - } catch (Exception e) { - - Environment.logError ("Unable to delete messages for editor: " + - _this.editor, - e); - - UIUtils.showErrorMessage (_this.viewer, - "Unable to delete messages for editor."); - - return; - - } - - for (EditorMessage m : toDel) - { - - _this.editor.removeMessage (m); - - } - - UIUtils.showMessage ((PopupsSupported) _this.viewer, - "Selected message types deleted", - "All message for selected types have been deleted."); - - } - - }, - null); - - } - - })); - - } - - } - - public void addSendMessageMenuItem (JPopupMenu menu) - { - - final EditorInfoBox _this = this; - - if (this.editor.isPrevious ()) - { - - return; - - } - - final boolean pending = this.editor.isPending (); - - if (!pending) - { - - menu.add (UIUtils.createMenuItem (getUIString (editors,LanguageStrings.editor,view,popupmenu,items,sendmessage), - //"Send message", - Constants.MESSAGE_ICON_NAME, - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - try - { - - _this.viewer.sendMessageToEditor (_this.editor); - - } catch (Exception e) { - - Environment.logError ("Unable to show editor: " + - _this.editor, - e); - - UIUtils.showErrorMessage (_this, - getUIString (editors,LanguageStrings.editor,view,actionerror)); - //"Unable to show {editor}."); - - } - - } - - })); - - } - - } - - public void addShowImportantMessagesMenuItem (JPopupMenu menu) - { - - if (this.editor.isPrevious ()) - { - - return; - - } - - final EditorInfoBox _this = this; - - final boolean pending = this.editor.isPending (); - - if (!pending) - { - - final Set messages = this.editor.getMessages (new EditorMessageFilter () - { - - public boolean accept (EditorMessage m) - { - - if (!EditorsUIUtils.getDefaultViewableMessageFilter ().accept (m)) - { - - return false; - - } - - if (m.isDealtWith ()) - { - - return false; - - } - - if (m.getMessageType ().equals (EditorChatMessage.MESSAGE_TYPE)) - { - - return false; - - } - - return true; - - } - - }); - - if (messages.size () > 0) - { - - menu.add (UIUtils.createMenuItem (String.format (getUIString (editors,LanguageStrings.editor,view,popupmenu,items,importantmessages), - //"View new/important messages (%s)", - Environment.formatNumber (messages.size ())), - Constants.ERROR_ICON_NAME, - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - try - { - - EditorsUIUtils.showImportantMessagesForEditor (_this.editor, - _this.viewer, - null); - - } catch (Exception e) { - - Environment.logError ("Unable to show project messages for editor: " + - _this.editor, - e); - - UIUtils.showErrorMessage (_this.viewer, - getUIString (editors,LanguageStrings.messages,show,important,actionerror)); - //"Unable to {project} messages for editor."); - - return; - - } - - } - - })); - - } - - } - - } - - public void addProjectSentAndUpdatesMenuItem (JPopupMenu menu) - { - - final EditorInfoBox _this = this; - - final boolean pending = this.editor.isPending (); - - //boolean isEditorProject = this.projectViewer.getProject ().isEditorProject (); - - if ((!pending) - && - (this.showProjectInfo) - && - (this.proj != null) - ) - { - - final Set messages = this.editor.getMessages (new DefaultEditorMessageFilter (this.proj, - NewProjectMessage.MESSAGE_TYPE, - NewProjectResponseMessage.MESSAGE_TYPE, - UpdateProjectMessage.MESSAGE_TYPE, - ProjectEditStopMessage.MESSAGE_TYPE)); - - if (messages.size () > 0) - { - - menu.add (UIUtils.createMenuItem (String.format (getUIString (editors,LanguageStrings.editor,view,popupmenu,items,projectupdates), - //"View updates you have sent/received for this {project} (%s)", - Environment.formatNumber (messages.size ())), - Project.OBJECT_TYPE, - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - try - { - - EditorsUIUtils.showProjectMessagesForEditor (_this.editor, - (AbstractProjectViewer) _this.viewer, - null); - - } catch (Exception e) { - - Environment.logError ("Unable to show project messages for editor: " + - _this.editor, - e); - - UIUtils.showErrorMessage (_this.viewer, - getUIString (editors,LanguageStrings.messages,show,project,actionerror)); - //"Unable to {project} messages for editor.") - - return; - - } - - } - - })); - - } - - } - - } - - public void addProjectsInvolvedWithMenuItem (JPopupMenu menu) - { - - final EditorInfoBox _this = this; - - final boolean pending = this.editor.isPending (); - - if (!pending) - { - - // Get all the projects. - int projCount = 0; - - try - { - - projCount = Environment.getAllProjectInfos (Project.EDITOR_PROJECT_TYPE).size (); - - } catch (Exception e) { - - Environment.logError ("Unable to get all projects", - e); - - } - - if (projCount > 0) - { - - menu.add (UIUtils.createMenuItem (String.format (getUIString (editors,LanguageStrings.editor,view,popupmenu,items,projectsuserediting), - //"View {projects} I'm editing for %s (%s)", - this.editor.getShortName (), - Environment.formatNumber (projCount)), - Project.OBJECT_TYPE, - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - try - { - - EditorsUIUtils.showProjectsUserIsEditingForEditor (_this.editor, - _this.viewer); - - } catch (Exception e) { - - Environment.logError ("Unable to show projects user is editing for editor: " + - _this.editor, - e); - - UIUtils.showErrorMessage (_this.viewer, - getUIString (editors,LanguageStrings.editor,showprojectscontactisediting,actionerror)); - //String.format ("Unable to show {projects} you are editing for %s.", - // _this.editor.getShortName ())); - - return; - - } - - } - - })); - - } - - final Set messages = this.editor.getMessages (new EditorMessageFilter () - { - - public boolean accept (EditorMessage m) - { - - if (m.isSentByMe ()) - { - - return false; - - } - - if (!m.getMessageType ().equals (NewProjectResponseMessage.MESSAGE_TYPE)) - { - - return false; - - } - - NewProjectResponseMessage nprm = (NewProjectResponseMessage) m; - - if (!nprm.isAccepted ()) - { - - return false; - - } - - return true; - - } - - }); - - if (messages.size () > 0) - { - - menu.add (UIUtils.createMenuItem (String.format (getUIString (editors,LanguageStrings.editor,view,popupmenu,items,projectscontactediting), - //"View {projects} %s is editing for me (%s)", - this.editor.getShortName (), - Environment.formatNumber (messages.size ())), - Project.OBJECT_TYPE, - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - try - { - - EditorsUIUtils.showProjectsEditorIsEditingForUser (_this.editor, - _this.viewer); - - } catch (Exception e) { - - Environment.logError ("Unable to show projects for editor: " + - _this.editor, - e); - - UIUtils.showErrorMessage (_this.viewer, - getUIString (editors,LanguageStrings.editor,showprojectscontactisediting,actionerror)); - //String.format ("Unable to show {projects} %s is editing for you.", - // _this.editor.getShortName ())); - - return; - - } - - } - - })); - - } - - } - - } - - public void addShowCommentsMenuItem (JPopupMenu menu) - { - - final EditorInfoBox _this = this; - - if (this.editor.isPending ()) - { - - return; - - } - - if (this.proj == null) - { - - return; - - } - - boolean isEditorProject = this.proj.isEditorProject (); - - final Set messages = this.editor.getMessages (new EditorMessageFilter () - { - - public boolean accept (EditorMessage m) - { - - return ((m.getMessageType ().equals (ProjectCommentsMessage.MESSAGE_TYPE)) - && - (_this.proj.getId ().equals (m.getForProjectId ()))); - - } - - }); - - String suffix = (this.projEditor != null ? "received" : "sent"); - - if ((isEditorProject) - && - (messages.size () > 0) - ) - { - - menu.add (UIUtils.createMenuItem (getUIString (editors,LanguageStrings.editor,view,popupmenu,items,commentssent), - //String.format ("View all {comments} sent", - // suffix), - Constants.COMMENT_ICON_NAME, - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - try - { - - EditorsUIUtils.showAllCommentsForEditor (_this.editor, - (AbstractProjectViewer) _this.viewer, - null); - - } catch (Exception e) { - - Environment.logError ("Unable to show comments from editor: " + - _this.editor, - e); - - UIUtils.showErrorMessage (_this.viewer, - getUIString (editors,viewcommentserror)); - //"Unable to show {comments} from editor."); - - return; - - } - - } - - })); - - } else { - - Iterator iter = messages.iterator (); - - if (messages.size () > 0) - { - - final ProjectCommentsMessage message = (ProjectCommentsMessage) messages.iterator ().next (); - - menu.add (UIUtils.createMenuItem (String.format (getUIString (editors,LanguageStrings.editor,view,popupmenu,items,(this.projEditor != null ? lastcommentsreceived : lastcommentssent)), - //"View last {comments} %s (%s)", - message.getComments ().size ()), - //suffix), - Constants.FIND_ICON_NAME, - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - EditorsUIUtils.showProjectComments (message, - (AbstractProjectViewer) _this.viewer, - null); - - } - - })); - - } - - if (messages.size () > 1) - { - - menu.add (UIUtils.createMenuItem (getUIString (editors,LanguageStrings.editor,view,popupmenu,items,(this.projEditor != null ? commentsreceived : commentssent)), - //"View all {comments} %s", - //suffix), - Constants.COMMENT_ICON_NAME, - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - try - { - - EditorsUIUtils.showAllCommentsForEditor (_this.editor, - (AbstractProjectViewer) _this.viewer, - null); - - } catch (Exception e) { - - Environment.logError ("Unable to show comments from editor: " + - _this.editor, - e); - - UIUtils.showErrorMessage (_this.viewer, - getUIString (editors,viewcommentserror)); - //"Unable to show {comments} from editor."); - - return; - - } - - } - - })); - - } - - } - - } - - public void addSendOrUpdateProjectMenuItem (JPopupMenu menu) - { - - final EditorInfoBox _this = this; - - if (this.editor.isPrevious ()) - { - - return; - - } - - if (this.proj == null) - { - - return; - - } - - final boolean pending = this.editor.isPending (); - - boolean isEditorProject = this.proj.isEditorProject (); - - if ((!pending) - && - (!isEditorProject) - ) - { - - if (!this.editor.messagesLoaded ()) - { - - try - { - - EditorsEnvironment.loadMessagesForEditor (_this.editor); - - } catch (Exception e) { - - Environment.logError ("Unable to load messages for editor: " + - _this.editor, - e); - - UIUtils.showErrorMessage (_this.viewer, - getUIString (editors,LanguageStrings.editor,view,actionerror)); - //"Unable to load messages for editor."); - - return; - - } - - } - - // Find out what was the last project message sent. - Set messages = this.editor.getMessages (new DefaultEditorMessageFilter (this.proj, - NewProjectMessage.MESSAGE_TYPE, - NewProjectResponseMessage.MESSAGE_TYPE, - ProjectEditStopMessage.MESSAGE_TYPE, - UpdateProjectMessage.MESSAGE_TYPE)); - - EditorMessage last = null; - - for (EditorMessage m : messages) - { - - last = m; - - } - - boolean addSend = false; - boolean addUpdate = false; - - if ((last == null) - || - (last instanceof ProjectEditStopMessage) - ) - { - - addSend = true; - - } - - if (last instanceof NewProjectMessage) - { - - // Sent the project. Do nothing since we have no response. - addSend = true; - //return; - - } - - if (last instanceof NewProjectResponseMessage) - { - - NewProjectResponseMessage npr = (NewProjectResponseMessage) last; - - if (!npr.isAccepted ()) - { - - addSend = true; - - } else { - - addUpdate = true; - - } - - } - - if (last instanceof UpdateProjectMessage) - { - - addUpdate = true; - - } - - if (addSend) - { - - menu.add (UIUtils.createMenuItem (getUIString (editors,LanguageStrings.editor,view,popupmenu,items,sendproject), - //"Send {project}/{chapters}", - Constants.SEND_ICON_NAME, - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - EditorsUIUtils.showSendProject ((AbstractProjectViewer) _this.viewer, - _this.editor, - null); - - } - - })); - - return; - - } - - if (addUpdate) - { - - menu.add (UIUtils.createMenuItem (getUIString (editors,LanguageStrings.editor,view,popupmenu,items,sendupdateproject), - //"Update {project}/{chapters}", - Constants.SEND_ICON_NAME, - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - EditorsUIUtils.showUpdateProject ((AbstractProjectViewer) _this.viewer, - _this.editor, - null); - - } - - })); - - } else { - - menu.add (UIUtils.createMenuItem (getUIString (editors,LanguageStrings.editor,view,popupmenu,items,sendproject), - //"Send {project}/{chapters}", - Constants.SEND_ICON_NAME, - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - EditorsUIUtils.showSendProject ((AbstractProjectViewer) _this.viewer, - _this.editor, - null); - - } - - })); - - } - - } - - } - - public void addUpdateEditorInfoMenuItem (JPopupMenu menu) - { - - final EditorInfoBox _this = this; - - final boolean pending = this.editor.isPending (); - - if (!pending) - { - - menu.add (UIUtils.createMenuItem (getUIString (editors,LanguageStrings.editor,view,popupmenu,items,updatecontactinfo), - //"Update the {contact} information", - Constants.EDIT_ICON_NAME, - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - EditorsUIUtils.updateEditorInfo (_this.viewer, - _this.editor); - - } - - }, - null, - null)); - - } - - } - - /** - * Add a mouse listener to the content, because the JLayer intercepts the mouse events we need to channel the - * listener add to the actual content component. - * - * TODO: Make this nicer somehow, and add removeMouseListener. - */ - @Override - public void addMouseListener (MouseListener m) - { - - this.editorInfo.addMouseListener (m); - - } - - public void addRemoveEditorMenuItem (JPopupMenu menu) - { - - final EditorInfoBox _this = this; - - if (this.editor.isPrevious ()) - { - - return; - - } - - menu.add (UIUtils.createMenuItem (getUIString (editors,LanguageStrings.editor,view,popupmenu,items,removecontact), - //"Remove {contact}", - Constants.DELETE_ICON_NAME, - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - EditorsUIUtils.showRemoveEditor (_this.viewer, - _this.editor, - null); - - } - - })); - - } - - public void addShowAllMessagesMenuItem (final JPopupMenu menu) - { - - final EditorInfoBox _this = this; - - final boolean pending = this.editor.isPending (); - - menu.add (UIUtils.createMenuItem (getUIString (editors,LanguageStrings.editor,view,popupmenu,items,allmessages), - //"View ALL messages sent/received", - Constants.FIND_ICON_NAME, - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - EditorsUIUtils.showAllMessagesForEditor (_this.editor, - _this.viewer, - null); - - } - - })); - - } - -/* - public void addSearchMessagesMenuItem (final JPopupMenu menu, - final EditorPanel panel) - { - - final EditorInfoBox _this = this; - - final boolean pending = this.editor.isPending (); - - if (!pending) - { - - menu.add (UIUtils.createMenuItem ("Search messages", - Constants.FIND_ICON_NAME, - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - panel.showSearch (); - - } - - })); - - } - - } -*/ - public void addFullPopupListener () - { - - final EditorInfoBox _this = this; - - this.editorInfo.addMouseListener (new MouseEventHandler () - { - - @Override - public void fillPopup (JPopupMenu m, - MouseEvent ev) - { - - _this.addSendMessageMenuItem (m); - - _this.addSendOrUpdateProjectMenuItem (m); - - _this.addShowImportantMessagesMenuItem (m); - - //_this.addShowCommentsMenuItem (m); - - //_this.addProjectsInvolvedWithMenuItem (m); - - //_this.addProjectSentAndUpdatesMenuItem (m); - -/* - infBox.addSearchMessagesMenuItem (m, - _this); - */ - - if (_this.editor.isPending ()) - { - - m.add (UIUtils.createMenuItem (getUIString (editors,LanguageStrings.editor,view,popupmenu,items,resendinvite), - //"Resend Invite", - Constants.NOTIFY_ICON_NAME, - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - EditorsEnvironment.sendInvite (_this.editor.getEmail ()); - - } - - })); - - } - - _this.addShowAllMessagesMenuItem (m); - - _this.addUpdateEditorInfoMenuItem (m); - - _this.addRemoveEditorMenuItem (m); - - _this.addDeleteAllMessagesMenuItem (m); - - } - - }); - - } - - public void addBasicPopupListener () - { - - final EditorInfoBox _this = this; - - this.editorInfo.addMouseListener (new MouseEventHandler () - { - - @Override - public void fillPopup (JPopupMenu m, - MouseEvent ev) - { - - _this.addDeleteAllMessagesMenuItem (m); - - _this.addSendMessageMenuItem (m); - - _this.addUpdateEditorInfoMenuItem (m); - - } - - }); - - } - -} diff --git a/src/com/quollwriter/editors/ui/EditorInfoMessageBox.java b/src/com/quollwriter/editors/ui/EditorInfoMessageBox.java deleted file mode 100644 index 916a7456..00000000 --- a/src/com/quollwriter/editors/ui/EditorInfoMessageBox.java +++ /dev/null @@ -1,243 +0,0 @@ -package com.quollwriter.editors.ui; - -import java.util.List; -import java.util.ArrayList; -import java.util.Arrays; - -import java.awt.event.*; -import java.awt.Component; -import javax.swing.*; -import javax.swing.border.*; - -import com.quollwriter.*; -import com.quollwriter.editors.*; -import com.quollwriter.data.editors.*; -import com.quollwriter.ui.*; -import com.quollwriter.ui.components.ImagePanel; -import com.quollwriter.editors.messages.*; - -import static com.quollwriter.LanguageStrings.*; -import static com.quollwriter.Environment.getUIString; - -public class EditorInfoMessageBox extends MessageBox -{ - - private Box responseBox = null; - - public EditorInfoMessageBox (EditorInfoMessage mess, - AbstractViewer viewer) - { - - super (mess, - viewer); - - } - - public boolean isAutoDealtWith () - { - - return false; - - } - - public void doUpdate () - { - - if (this.message.isDealtWith ()) - { - - if (this.responseBox != null) - { - - this.responseBox.setVisible (false); - - } - - } - - } - - public void doInit () - { - - final EditorInfoMessageBox _this = this; - - java.util.List prefix = Arrays.asList (editors,messages,contactinfo); - - String text = getUIString (prefix,sent,title); - //"Sent name/avatar"; - - if (!this.message.isSentByMe ()) - { - - text = getUIString (prefix,received,title); - //"Received name/avatar update"; - - } - - JComponent h = UIUtils.createBoldSubHeader (text, - Constants.INFO_ICON_NAME); - - this.add (h); - - Box editorInfo = new Box (BoxLayout.X_AXIS); - editorInfo.setAlignmentX (Component.LEFT_ALIGNMENT); - editorInfo.setBorder (UIUtils.createPadding (5, 10, 5, 5)); - - this.add (editorInfo); - - if (this.message.getAvatar () != null) - { - - JLabel avatar = new JLabel (); - - avatar.setAlignmentY (Component.TOP_ALIGNMENT); - avatar.setVerticalAlignment (SwingConstants.TOP); - - editorInfo.add (avatar); - avatar.setOpaque (false); - - avatar.setIcon (new ImageIcon (UIUtils.getScaledImage (this.message.getAvatar (), - 50))); - - avatar.setBorder (new CompoundBorder (UIUtils.createPadding (0, 0, 0, 5), - UIUtils.createLineBorder ())); - - } - - String n = this.message.getName (); - - if (n == null) - { - - n = this.message.getEditor ().getShortName (); - - } - - JLabel name = new JLabel (n); - editorInfo.add (name); - - name.setBorder (null); - name.setAlignmentY (Component.TOP_ALIGNMENT); - name.setVerticalAlignment (JLabel.TOP); - name.setAlignmentX (Component.LEFT_ALIGNMENT); - name.setFont (name.getFont ().deriveFont ((float) UIUtils.getScaledFontSize (14)).deriveFont (java.awt.Font.PLAIN)); - - if ((!this.message.isDealtWith ()) - && - (!this.message.isSentByMe ()) - ) - { - - this.responseBox = new Box (BoxLayout.Y_AXIS); - - this.responseBox.setBorder (UIUtils.createPadding (0, 5, 0, 5)); - - this.add (this.responseBox); - - JButton update = UIUtils.createButton (getUIString (prefix,received,buttons,LanguageStrings.update)); - //"Update"); - - update.addActionListener (new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - EditorEditor ed = _this.message.getEditor (); - - try - { - - // Just update the info. - String newName = _this.message.getName (); - - if (newName != null) - { - - ed.setName (newName.trim ()); - - } - - java.awt.image.BufferedImage newImage = _this.message.getAvatar (); - - if (newImage != null) - { - - ed.setAvatar (newImage); - - } - - EditorsEnvironment.updateEditor (ed); - - _this.message.setDealtWith (true); - - EditorsEnvironment.updateMessage (_this.message); - - } catch (Exception e) { - - Environment.logError ("Unable to update editor: " + - ed, - e); - - UIUtils.showErrorMessage (_this.viewer, - getUIString (editors,editor,edit,actionerror)); - //"Unable to update {editor}, please contact Quoll Writer support for assistance."); - - return; - - } - - } - - }); - - JButton ignore = UIUtils.createButton (getUIString (prefix,received,buttons,LanguageStrings.ignore)); - //"Ignore"); - - ignore.addActionListener (new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - try - { - - _this.message.setDealtWith (true); - - EditorsEnvironment.updateMessage (_this.message); - - } catch (Exception e) { - - Environment.logError ("Unable to update message: " + - _this.message, - e); - - UIUtils.showErrorMessage (_this.viewer, - getUIString (editors,editor,edit,actionerror)); - //"Unable to update {editor}, please contact Quoll Writer support for assistance."); - - return; - - } - - } - - }); - - JButton[] buts = new JButton[] { update, ignore }; - - JPanel bb = UIUtils.createButtonBar2 (buts, - Component.LEFT_ALIGNMENT); - bb.setOpaque (false); - bb.setAlignmentX (Component.LEFT_ALIGNMENT); - bb.setBorder (UIUtils.createPadding (5, 0, 0, 0)); - - this.responseBox.add (bb); - - } - - } - -} diff --git a/src/com/quollwriter/editors/ui/EditorProjectViewer.java b/src/com/quollwriter/editors/ui/EditorProjectViewer.java deleted file mode 100644 index 8753a22e..00000000 --- a/src/com/quollwriter/editors/ui/EditorProjectViewer.java +++ /dev/null @@ -1,1724 +0,0 @@ -package com.quollwriter.editors.ui; - -import java.awt.Dimension; -import java.awt.Component; -import java.awt.dnd.*; -import java.awt.event.*; - -import java.net.*; - -import java.security.*; - -import java.text.*; - -import java.util.Arrays; -import java.util.ArrayList; -import java.util.Date; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedHashSet; -import java.util.TreeSet; -import java.util.Map; -import java.util.Set; -import java.util.StringTokenizer; -import java.util.Iterator; - -import javax.swing.*; -import javax.swing.border.*; -import javax.swing.event.*; -import javax.swing.text.*; -import javax.swing.tree.*; - -import com.gentlyweb.properties.*; - -import com.gentlyweb.utils.*; - -import com.jgoodies.forms.builder.*; -import com.jgoodies.forms.factories.*; -import com.jgoodies.forms.layout.*; - -import com.quollwriter.*; - -import com.quollwriter.data.*; - -import com.quollwriter.db.*; - -import com.quollwriter.events.*; -import com.quollwriter.data.comparators.*; -import com.quollwriter.text.*; -import com.quollwriter.editors.ui.sidebars.*; -import com.quollwriter.editors.ui.panels.*; -import com.quollwriter.ui.panels.*; -import com.quollwriter.ui.sidebars.*; -import com.quollwriter.ui.actionHandlers.*; -import com.quollwriter.ui.*; - -import com.quollwriter.ui.components.TabHeader; -import com.quollwriter.ui.components.ActionAdapter; -import com.quollwriter.ui.components.IconProvider; -import com.quollwriter.ui.components.QPopup; -import com.quollwriter.ui.events.*; -import com.quollwriter.ui.renderers.*; -import com.quollwriter.editors.*; -import com.quollwriter.editors.ui.*; - -import static com.quollwriter.LanguageStrings.*; -import static com.quollwriter.Environment.getUIString; - -import static com.quollwriter.LanguageStrings.*; -import static com.quollwriter.Environment.getUIString; - -public class EditorProjectViewer extends AbstractProjectViewer -{ - - public static final String TAB_OBJECT_TYPE = "tab"; - public static final int NEW_COMMENT_ACTION = 3002; // "newComment"; - public static final int VIEW_EDITOR_CHAPTER_INFO_ACTION = 105; // "viewEditorChapterInfo"; - - public static final int DELETE_COMMENT_ACTION = 3001; // "deleteComment"; - public static final int EDIT_COMMENT_ACTION = 3000; - public static final int COMPLETE_EDITING_ACTION = 3003; - - private Date sessionStart = new Date (); - private EditorProjectSideBar sideBar = null; - private DefaultChapterItemViewPopupProvider chapterItemViewPopupProvider = null; - private IconProvider iconProvider = null; - - public EditorProjectViewer() - { - - final EditorProjectViewer _this = this; - - this.chapterItemViewPopupProvider = new DefaultChapterItemViewPopupProvider () - { - - @Override - public boolean canEdit (ChapterItem it) - { - - if (it instanceof Note) - { - - Note n = (Note) it; - - return !n.isDealtWith (); - - } - - return true; - - } - - @Override - public boolean canDelete (ChapterItem it) - { - - if (it instanceof Note) - { - - Note n = (Note) it; - - return !n.isDealtWith (); - - } - - return true; - - } - - }; - - this.chapterItemViewPopupProvider.setShowLinks (false); - this.chapterItemViewPopupProvider.setFormatDetails (Note.OBJECT_TYPE, - new NoteFormatDetails () - { - - @Override - public String getTitle (Note item) - { - - return getUIString (objectnames,singular,comment); - //"{Comment}"; - - } - - @Override - public String getIcon (Note item) - { - - return Constants.COMMENT_ICON_NAME; - - } - - @Override - public String getItemDescription (Note item) - { - - return item.getDescription ().getMarkedUpText (); - - } - - @Override - public ActionListener getEditItemActionHandler (Note item, - ChapterItemViewer ep) - { - - return new CommentActionHandler (item, - ep); - - } - - @Override - public ActionListener getDeleteItemActionHandler (Note item, - ChapterItemViewer ep, - boolean showAtItem) - { - - // Should really add generics for this. - return new DeleteCommentActionHandler (item, - ep.getViewer (), - showAtItem); - - } - - }); - - this.iconProvider = new DefaultIconProvider () - { - - @Override - public ImageIcon getIcon (String name, - int type) - { - - name = Constants.COMMENT_ICON_NAME; - - return super.getIcon (name, - type); - - } - - }; - - this.sideBar = new EditorProjectSideBar (this); - - } - - public IconProvider getIconProvider () - { - - return this.iconProvider; - - } - - public ChapterItemViewPopupProvider getChapterItemViewPopupProvider () - { - - return this.chapterItemViewPopupProvider; - - } - - public void initActionMappings (ActionMap am) - { - - super.initActionMappings (am); - - } - - public void initKeyMappings (InputMap im) - { - - super.initKeyMappings (im); - - } - - public void showObjectInTree (String treeObjType, - NamedObject obj) - { - - this.sideBar.showObjectInTree (treeObjType, - obj); - - } - - public void reloadTreeForObjectType (String objType) - { - - this.sideBar.reloadTreeForObjectType (objType); - - } - - public void reloadTreeForObjectType (NamedObject obj) - { - - this.sideBar.reloadTreeForObjectType (obj.getObjectType ()); - - } - - public AbstractSideBar getMainSideBar () - { - - return this.sideBar; - - } - - public void fillFullScreenTitleToolbar (JToolBar toolbar) - { - - this.fillTitleToolbar (toolbar); - - WordCountTimerBox b = new WordCountTimerBox (this.getFullScreenFrame (), - Constants.ICON_FULL_SCREEN_ACTION, - this.getWordCountTimer ()); - - b.setBarHeight (20); - - toolbar.add (b); - - } - - public void fillTitleToolbar (JToolBar toolbar) - { - - } - - public void fillSettingsPopup (JPopupMenu titlePopup) - { - - final EditorProjectViewer _this = this; - - JMenuItem mi = null; - - // Open project. - java.util.List prefix = Arrays.asList (editors,project,settingsmenu,items); - - titlePopup.add (this.createMenuItem (getUIString (prefix,openproject), - //"Open {Project}", - Constants.OPEN_PROJECT_ICON_NAME, - EditorProjectViewer.OPEN_PROJECT_ACTION)); - - // Close Project - titlePopup.add (this.createMenuItem (getUIString (prefix,closeproject), - //"Close {Project}", - Constants.CLOSE_ICON_NAME, - EditorProjectViewer.CLOSE_PROJECT_ACTION)); - - // Delete Project - titlePopup.add (this.createMenuItem (getUIString (prefix,deleteproject), - //"Delete {Project}", - Constants.DELETE_ICON_NAME, - EditorProjectViewer.COMPLETE_EDITING_ACTION)); - - } - - public void switchToProjectVersion (ProjectVersion pv) - { - - if (pv == null) - { - - throw new IllegalArgumentException ("Expected a project version"); - - } - - Set chaps = null; - - try - { - - chaps = ((ChapterDataHandler) this.getObjectManager ().getHandler (Chapter.class)).getChaptersForVersion (pv, - null, - null, - true); - - } catch (Exception e) { - - Environment.logError ("Unable to get project at version: " + - pv, - e); - - UIUtils.showErrorMessage (this, - getUIString (editors,project,actions,switchtoversion,actionerror)); - //"Unable to open project at that version, please contact Quoll Writer support for assistance."); - - return; - - } - - // Close all the current panels and save the state. - this.closeAllTabs (true); - - // Remove all the chapters from the book. - this.proj.getBook (0).removeAllChapters (); - - for (Chapter c : chaps) - { - - this.proj.getBook (0).addChapter (c); - - } - - this.proj.setProjectVersion (pv); - - this.setViewerTitle (this.getViewerTitle ()); - - EditorProjectSideBar epb = null; - - try - { - - epb = new EditorProjectSideBar (this); - - epb.init (null); - - } catch (Exception e) { - - Environment.logError ("Unable to init new editor project side bar", - e); - - UIUtils.showErrorMessage (this, - getUIString (editors,project,actions,switchtoversion,actionerror)); - //"Unable to open project at that version, please contact Quoll Writer support for assistance."); - - // Need to close and reopen the project? - - return; - - } - - this.sideBar = epb; - - this.setMainSideBar (this.sideBar); - - this.restoreTabs (); - - } - -/* - public boolean viewEditors () - throws GeneralException - { - - // See if the user has an account or has already registered, if so show the sidebar - // otherwise show the register. - if (!EditorsEnvironment.hasRegistered ()) - { - - EditorsUIUtils.showRegister (this); - - return true; - - } - - EditorsSideBar sb = new EditorsSideBar (this); - - this.addSideBar ("editors", - sb); - - this.showSideBar ("editors"); - - return true; - - } - */ - - private void showCompleteEditing () - { - - final EditorProjectViewer _this = this; - - final Project _proj = this.proj; - - // Check for unsent comments. - - final ActionListener deleteProj = new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - java.util.List prefix = Arrays.asList (editors,project,actions,deleteproject,popup); - - final QPopup qp = UIUtils.createClosablePopup (getUIString (prefix,title), - //"Delete {Project}?", - Environment.getIcon (Constants.DELETE_ICON_NAME, - Constants.ICON_POPUP), - null); - - Box content = new Box (BoxLayout.Y_AXIS); - - JTextPane desc = UIUtils.createHelpTextPane (String.format (getUIString (prefix,LanguageStrings.text), - //"To delete {Project} %s please enter the word Yes into the box below.

    Warning! All information/{comments} associated with the {project} will be deleted.

    A message will also be sent to %s telling them you are no longer editing the {project}.", - _this.proj.getName (), - _this.proj.getForEditor ().getShortName ()), - _this); - - content.add (desc); - desc.setBorder (null); - desc.setSize (new Dimension (UIUtils.getPopupWidth () - 20, - desc.getPreferredSize ().height)); - - content.add (Box.createVerticalStrut (10)); - - final JLabel error = UIUtils.createErrorLabel (getUIString (form,errors,affirmativevalue)); - //"Please enter the word Yes."); - - error.setVisible (false); - error.setBorder (UIUtils.createPadding (0, - 0, - 5, - 0)); - - final JTextField text = UIUtils.createTextField (); - - text.setMinimumSize (new Dimension (300, - text.getPreferredSize ().height)); - text.setPreferredSize (new Dimension (300, - text.getPreferredSize ().height)); - text.setMaximumSize (new Dimension (Short.MAX_VALUE, - text.getPreferredSize ().height)); - text.setAlignmentX (Component.LEFT_ALIGNMENT); - - error.setAlignmentX (Component.LEFT_ALIGNMENT); - - content.add (error); - content.add (text); - - content.add (Box.createVerticalStrut (10)); - - // Blue pill/red pill? - ActionListener confirmAction = new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - if (!text.getText ().trim ().equalsIgnoreCase (getUIString (form,affirmativevalue))) - { - - error.setVisible (true); - - qp.resize (); - - return; - - } - - qp.removeFromParent (); - - EditorsEnvironment.sendProjectEditStopMessage (_proj, - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.close (true, - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - Environment.deleteProject (_proj, - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - java.util.List prefx = Arrays.asList (editors,project,actions,deleteproject,confirmpopup); - - // TODO: Really must sort this mess out. - UIUtils.showMessage ((Component) null, - getUIString (prefix,title), - //"{Project} deleted", - String.format (getUIString (prefix,LanguageStrings.text), - //"The {project} has been deleted and a message has been sent to %s to let them know.", - _proj.getForEditor ().getShortName ()), - null, - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - Environment.showLandingIfNoOpenProjects (); - - } - - }); - - } - - }); - - } - - }); - - } - - }); - - } - - }; - - JButton confirm = UIUtils.createButton (getUIString (prefix,buttons,LanguageStrings.confirm), - //"Yes, delete it", - confirmAction); - - UIUtils.addDoActionOnReturnPressed (text, - confirmAction); - - JButton cancel = UIUtils.createButton (getUIString (prefix,buttons,LanguageStrings.cancel), - //Constants.CANCEL_BUTTON_LABEL_ID, - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - qp.removeFromParent (); - - } - - }); - - JButton[] buts = new JButton[] { confirm, cancel }; - - JComponent bs = UIUtils.createButtonBar2 (buts, - Component.LEFT_ALIGNMENT); - bs.setAlignmentX (Component.LEFT_ALIGNMENT); - content.add (bs); - content.setBorder (UIUtils.createPadding (10, 10, 10, 10)); - qp.setContent (content); - - content.setPreferredSize (new Dimension (UIUtils.getPopupWidth (), - content.getPreferredSize ().height)); - - _this.showPopupAt (qp, - UIUtils.getCenterShowPosition (_this, - qp), - false); - - qp.setDraggable (_this); - - text.grabFocus (); - - } - - }; - - // Send project edit complete message. - - // Delete project. - - int count = 0; - - try - { - - count = this.getUnsentComments ().size (); - - } catch (Exception e) { - - Environment.logError ("Unable to get unsent comments for project: " + - this.proj, - e); - - UIUtils.showErrorMessage (this, - getUIString (editors,project,actions,unsentcomments,actionerror)); - //"Unable to check for unsent comments, please contact Quoll Writer support for assistance."); - - // Let things through. - - } - - if (count > 0) - { - - java.util.List prefix = Arrays.asList (editors,project,actions,deleteproject,unsentcommentspopup); - - UIUtils.createQuestionPopup (this, - getUIString (prefix,title), - //"Unsent comments", - Constants.ERROR_ICON_NAME, - String.format (getUIString (prefix,text), - //"There are %s comments that you have not yet sent to %s.

    Do you wish to send them now?", - count, - this.getProject ().getForEditor ().getShortName ()), - getUIString (prefix,buttons,confirm), - //"Yes, I'll send them now", - getUIString (prefix,buttons,cancel), - //"No, don't send them", - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - EditorsUIUtils.showSendUnsentComments (_this, - deleteProj); - - } - - }, - deleteProj, - null, - null); - - return; - - } - - deleteProj.actionPerformed (new ActionEvent ("call", 1, "call")); - - } - - @Override - public Action getAction (int name, - final NamedObject other) - { - - final EditorProjectViewer pv = this; - - if (name == COMPLETE_EDITING_ACTION) - { - - return new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - pv.showCompleteEditing (); - - } - - }; - - } - - if (name == EditorProjectViewer.DELETE_PROJECT_ACTION) - { - - return null; - - } - - Action a = super.getAction (name, - other); - - if (a != null) - { - - return a; - - } - - if (name == EditorProjectViewer.VIEW_EDITOR_CHAPTER_INFO_ACTION) - { - - return new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - pv.viewEditorChapterInformation ((Chapter) other); - - } - - }; - - } - - if (name == EditorProjectViewer.EDIT_COMMENT_ACTION) - { - - return new ActionAdapter () - { - - public void actionPerformed (final ActionEvent ev) - { - - final Chapter c = ((Note) other).getChapter (); - - pv.viewObject (c); - - UIUtils.doLater (new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - try - { - - EditorChapterPanel qep = (EditorChapterPanel) pv.getEditorForChapter (c); - - qep.editNote ((Note) other); - - } catch (Exception e) - { - - Environment.logError ("Unable to edit comment: " + - other, - e); - - UIUtils.showErrorMessage (pv, - getUIString (editors,project,actions,editcomment,actionerror)); - //"Unable to edit {Comment}"); - - } - - } - - }); - - } - - }; - - } - - if (name == EditorProjectViewer.DELETE_COMMENT_ACTION) - { - - return new DeleteCommentActionHandler ((Note) other, - this, - false); - - } - - if (name == EditorProjectViewer.NEW_COMMENT_ACTION) - { - - return new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - Chapter c = (Chapter) other; - - EditorChapterPanel qep = pv.getEditorForChapter (c); - - String text = qep.getEditor ().getText (); - - int pos = 0; - - if (text != null) - { - - pos = text.length (); - - } - - pv.scrollTo (c, - pos); - - new CommentActionHandler (c, - qep, - pos).actionPerformed (ev); - - } - - }; - - } - - throw new IllegalArgumentException ("Action: " + - name + - " not known."); - - } - - @Override - public void handleNewProject () - { - - Book b = this.proj.getBooks ().get (0); - - Chapter c = b.getFirstChapter (); - - // Create a new chapter for the book. - if (c == null) - { - - throw new IllegalArgumentException ("No chapter found."); - - } - - // Refresh the chapter tree. - this.reloadTreeForObjectType (c.getObjectType ()); - - this.handleOpenProject (); - - this.editChapter (c, - null); - - } - - @Override - public String getViewerIcon () - { - - return "editors";//this.proj.getObjectType (); - - } - - @Override - public String getViewerTitle () - { - - ProjectVersion pv = this.proj.getProjectVersion (); - - String suff = ""; - - if ((pv != null) - && - (pv.getName () != null) - ) - { - - suff = String.format (getUIString (editors,project,viewertitleversionwrapper), - //" (%s)", - pv.getName ()); - - } - - return String.format (getUIString (editors,project,viewertitle), - //"Editing%s: %s", - suff, - this.proj.getName ()); - - } - - @Override - public void handleHTMLPanelAction (String v) - { - - StringTokenizer t = new StringTokenizer (v, - ",;"); - - if (t.countTokens () > 1) - { - - while (t.hasMoreTokens ()) - { - - String tok = t.nextToken ().trim (); - - this.handleHTMLPanelAction (tok); - - } - - return; - - } - - if (v.equals ("find")) - { - - this.showFind (null); - - return; - - } - - super.handleHTMLPanelAction (v); - - } - - @Override - public void handleOpenProject () - { - - // TODO: Add achievements later. - Environment.removeFromAchievementsManager (this); - - // See if we have any state, if not then this is probably the first time we've opened the project - // then open the first chapter. - - if (this.getOpenTabsProperty () == null) - { - - // No state, open the first chapter. - Book b = this.proj.getBooks ().get (0); - - Chapter c = b.getFirstChapter (); - - // Create a new chapter for the book. - if (c != null) - { - - this.editChapter (c, - null); - - } - - } - - final EditorProjectViewer _this = this; - - if (this.getProject ().getForEditor ().isPrevious ()) - { - - UIUtils.doLater (new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - UIUtils.showMessage (_this, - getUIString (editors,project,actions,openproject,openerrors,previouscontact)); - //"Note: this is a {project} for a previous {contact}. You can no longer send {comments}."); - - } - - }); - - } - - } - - public void expandNoteTypeInNoteTree (String type) - { - - TreeParentNode tpn = new TreeParentNode (Note.OBJECT_TYPE, - type); - - DefaultTreeModel dtm = (DefaultTreeModel) this.getNoteTree ().getModel (); - - DefaultMutableTreeNode root = (DefaultMutableTreeNode) dtm.getRoot (); - - this.getNoteTree ().expandPath (UIUtils.getTreePathForUserObject (root, - tpn)); - - } -/* - private void initNoteTree (boolean restoreSavedOpenTypes) - { - - if (restoreSavedOpenTypes) - { - - String openTypes = this.proj.getProperty (Constants.NOTE_TREE_OPEN_TYPES_PROPERTY_NAME); - - if (openTypes != null) - { - - DefaultTreeModel dtm = (DefaultTreeModel) this.getNoteTree ().getModel (); - - DefaultMutableTreeNode root = (DefaultMutableTreeNode) dtm.getRoot (); - - // Split on : - StringTokenizer t = new StringTokenizer (openTypes, - "|"); - - while (t.hasMoreTokens ()) - { - - String tok = t.nextToken ().trim (); - - TreeParentNode tpn = new TreeParentNode (Note.OBJECT_TYPE, - tok); - - this.getNoteTree ().expandPath (UIUtils.getTreePathForUserObject (root, - tpn)); - - } - - } - - } - - } -*/ - public void handleItemChangedEvent (ItemChangedEvent ev) - { - - if (ev.getChangedObject () instanceof Chapter) - { - - this.sideBar.reloadTreeForObjectType (Chapter.OBJECT_TYPE); - - } - - if (ev.getChangedObject () instanceof Note) - { - - this.sideBar.reloadTreeForObjectType (Note.OBJECT_TYPE); - - } - - } - - public void reloadNoteTree () - { - - this.sideBar.reloadTreeForObjectType (Note.OBJECT_TYPE); - - } - - public void reloadChapterTree () - { - - this.sideBar.reloadTreeForObjectType (Chapter.OBJECT_TYPE); - - } - - @Override - public void doSaveState () - { - - } - - public EditorChapterPanel getEditorForChapter (Chapter c) - { - - for (QuollPanel qp : this.getAllQuollPanelsForObject (c)) - { - - if (qp instanceof FullScreenQuollPanel) - { - - qp = ((FullScreenQuollPanel) qp).getChild (); - - } - - if (qp instanceof EditorChapterPanel) - { - - return (EditorChapterPanel) qp; - - } - - } - - return null; - - } - - /** - * This is a top-level action so it can handle showing the user a message, it returns a boolean to indicate - * whether the chapter has been opened for editing. - */ - public boolean editChapter (Chapter c, - ActionListener doAfterView) - { - - // Check our tabs to see if we are already editing this chapter, if so then just switch to it instead. - EditorChapterPanel qep = (EditorChapterPanel) this.getQuollPanelForObject (c); - - if (qep != null) - { - - this.setPanelVisible (qep); - - this.getEditorForChapter (c).getEditor ().grabFocus (); - - if (doAfterView != null) - { - - UIUtils.doActionWhenPanelIsReady (qep, - doAfterView, - c, - "afterview"); - - } - - return true; - - } - - final EditorProjectViewer _this = this; - - try - { - - qep = new EditorChapterPanel (this, - c); - - qep.init (); - - } catch (Exception e) - { - - Environment.logError ("Unable to edit chapter: " + - c, - e); - - UIUtils.showErrorMessage (_this, - String.format (getUIString (project,actions,editchapter,actionerror), - //"Unable to edit {chapter}: " + - c.getName ())); - - return false; - - } - - final TabHeader th = this.addPanel (qep); - - qep.addActionListener (new ActionAdapter () - { - - - public void actionPerformed (ActionEvent ev) - { - - if (ev.getID () == QuollPanel.UNSAVED_CHANGES_ACTION_EVENT) - { - - th.setComponentChanged (true); - - } - - } - - }); - - this.addNameChangeListener (c, - qep); - - // Open the tab :) - return this.editChapter (c, - doAfterView); - - } - - public boolean viewObject (DataObject d, - ActionListener doAfterView) - { - - if (d instanceof Note) - { - - final Note n = (Note) d; - - if (n.getObject () != null) - { - - this.viewNote (n, - doAfterView); - - } - - return true; - - } - - if (d instanceof Chapter) - { - - Chapter c = (Chapter) d; - - return this.editChapter (c, - doAfterView); - - } - - // Record the error, then ignore. - Environment.logError ("Unable to open object: " + d); - - return false; - - } - - public boolean viewObject (DataObject d) - { - - return this.viewObject (d, - null); - - } - - public void viewNote (final Note n, - final ActionListener doAfterView) - { - - try - { - - // Need to change this. - if (n.getObject () instanceof Chapter) - { - - final Chapter c = (Chapter) n.getObject (); - - final EditorProjectViewer _this = this; - - this.editChapter (c, - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - EditorChapterPanel qep = _this.getEditorForChapter (c); - - try - { - - qep.showNote (n, - doAfterView); - - } catch (Exception e) { - - Environment.logError ("Unable to show note: " + - n, - e); - - UIUtils.showErrorMessage (_this, - getUIString (editors,project,actions,viewcomment,actionerror)); - //"Unable to show {comment}, please contact Quoll Writer support for assistance."); - - } - - } - - }); - - return; - - } - - } catch (Exception e) - { - - Environment.logError ("Unable to show note: " + - n, - e); - - UIUtils.showErrorMessage (this, - getUIString (editors,project,actions,viewcomment,actionerror)); - - } - - } - - public boolean openPanel (String id) - { - - return false; - - } - - protected void addNameChangeListener (final NamedObject n, - final ProjectObjectQuollPanel qp) - { - - final EditorProjectViewer _this = this; - - qp.addObjectPropertyChangedListener (new PropertyChangedListener () - { - - @Override - public void propertyChanged (PropertyChangedEvent ev) - { - - if (ev.getChangeType ().equals (NamedObject.NAME)) - { - - _this.setTabHeaderTitle (qp, - qp.getTitle ()); - - _this.informTreeOfNodeChange (n, - _this.getTreeForObjectType (n.getObjectType ())); - - } - - } - - }); - - } - - /** - * This is a top-level action so it can handle showing the user a message, it returns a boolean to indicate - * whether the chapter information is viewed. - */ - public boolean viewEditorChapterInformation (final Chapter c) - { -/* - ChapterInformationSideBar cb = new ChapterInformationSideBar (this, - c); - - this.addSideBar ("chapterinfo-" + c.getKey (), - cb); - - this.showSideBar ("chapterinfo-" + c.getKey ()); - */ - return true; - - } - - public JTree getTreeForObjectType (String objType) - { - - return this.sideBar.getTreeForObjectType (objType); - - } - - public void addChapterToTreeAfter (Chapter newChapter, - Chapter addAfter) - { - - DefaultTreeModel model = (DefaultTreeModel) this.getChapterTree ().getModel (); - - DefaultMutableTreeNode cNode = new DefaultMutableTreeNode (newChapter); - - if (addAfter == null) - { - - // Get the book node. - TreePath tp = UIUtils.getTreePathForUserObject ((DefaultMutableTreeNode) model.getRoot (), - newChapter.getBook ()); - - if (tp != null) - { - - DefaultMutableTreeNode node = (DefaultMutableTreeNode) tp.getLastPathComponent (); - - model.insertNodeInto (cNode, - (MutableTreeNode) node, - 0); - - } else - { - - DefaultMutableTreeNode root = (DefaultMutableTreeNode) model.getRoot (); - - model.insertNodeInto (cNode, - root, - root.getChildCount ()); - - } - - } else - { - - // Get the "addAfter" node. - DefaultMutableTreeNode node = (DefaultMutableTreeNode) UIUtils.getTreePathForUserObject ((DefaultMutableTreeNode) model.getRoot (), - addAfter).getLastPathComponent (); - - model.insertNodeInto (cNode, - (MutableTreeNode) node.getParent (), - node.getParent ().getIndex (node) + 1); - - } - - this.getChapterTree ().setSelectionPath (new TreePath (cNode.getPath ())); - - } - - public JTree getNoteTree () - { - - return this.getTreeForObjectType (Note.OBJECT_TYPE); - - } - - public JTree getChapterTree () - { - - return this.getTreeForObjectType (Chapter.OBJECT_TYPE); - - } - - public void deleteObject (NamedObject o, - boolean deleteChildObjects) - throws GeneralException - { - - if (o instanceof ChapterItem) - { - - this.deleteChapterItem ((ChapterItem) o, - deleteChildObjects, - true); - - return; - - } - - this.deleteObject (o); - - } - - public void deleteObject (NamedObject o) - throws GeneralException - { - - if (o instanceof Chapter) - { - - this.deleteChapter ((Chapter) o); - - } - - if (o instanceof ChapterItem) - { - - this.deleteChapterItem ((ChapterItem) o, - false, - false); - - } - - } - - public void deleteChapterItem (ChapterItem ci, - boolean deleteChildObjects, - boolean doInTransaction) - throws GeneralException - { - - if (ci.getObjectType ().equals (Note.OBJECT_TYPE)) - { - - this.deleteNote ((Note) ci, - doInTransaction); - - } - - } - - public void deleteNote (Note n, - boolean doInTransaction) - throws GeneralException - { - - java.util.Set otherObjects = n.getOtherObjectsInLinks (); - - NamedObject obj = n.getObject (); - - // Need to get the links, they may not be setup. - this.setLinks (n); - - this.dBMan.deleteObject (n, - false, - null); - - obj.removeNote (n); - - this.fireProjectEvent (n.getObjectType (), - ProjectEvent.DELETE, - n); - - this.refreshObjectPanels (otherObjects); - - if (obj instanceof Chapter) - { - - EditorChapterPanel qep = this.getEditorForChapter ((Chapter) obj); - - if (qep != null) - { - - qep.removeItem (n); - - } - - } - - this.reloadNoteTree (); - - this.reloadChapterTree (); - - } - - public void chapterTreeChanged (DataObject d) - { - - DefaultTreeModel model = (DefaultTreeModel) this.getChapterTree ().getModel (); - - DefaultMutableTreeNode node = (DefaultMutableTreeNode) UIUtils.getTreePathForUserObject ((DefaultMutableTreeNode) model.getRoot (), - d).getLastPathComponent (); - - model.nodeStructureChanged (node); - - } - - public void scrollTo (final Chapter c, - final int pos) - { - - final EditorProjectViewer _this = this; - - this.editChapter (c, - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - try - { - - _this.getEditorForChapter (c).scrollToPosition (pos); - - } catch (Exception e) - { - - Environment.logError ("Unable to show snippet at position: " + - pos, - e); - - } - - } - - }); - - } - - public Set getNotesForType (String t) - { - - Set notes = this.getAllNotes (); - - Set ret = new TreeSet (new ChapterItemSorter ()); - - for (Note n : notes) - { - - if (n.getType ().equals (t)) - { - - ret.add (n); - - } - - } - - return ret; - - } - - public Set getAllNotes () - { - - Set notes = new HashSet (); - - Book b = this.proj.getBooks ().get (0); - - java.util.List chapters = b.getChapters (); - - for (Chapter c : chapters) - { - - notes.addAll (c.getNotes ()); - - } - - return notes; - - } - - public TypesHandler getObjectTypesHandler (String objType) - { - - return null; - - } - - public void updateChapterIndexes (Book b) - throws GeneralException - { - - this.dBMan.updateChapterIndexes (b); - - } - - public String getChapterObjectName () - { - - return Environment.getObjectTypeName (Chapter.OBJECT_TYPE); - - } - - public void deleteChapter (Chapter c) - { - - throw new UnsupportedOperationException ("Not supported"); - - } - - public Set findText (String t) - { - - Set res = new LinkedHashSet (); - - // Get the snippets. - Map> snippets = this.getTextSnippets (t); - - if (snippets.size () > 0) - { - - res.add (new ChapterFindResultsBox (getUIString (objectnames,plural, Chapter.OBJECT_TYPE), - //Environment.getObjectTypeNamePlural (Chapter.OBJECT_TYPE), - Chapter.OBJECT_TYPE, - Chapter.OBJECT_TYPE, - this, - snippets)); - - } - - Set notes = this.proj.getNotesContaining (t); - - if (notes.size () > 0) - { - - res.add (new NamedObjectFindResultsBox (getUIString (objectnames,plural,comment), - //"{Comments}", - Constants.COMMENT_ICON_NAME, - Note.OBJECT_TYPE, - this, - notes)); - - } - - return res; - - } - - public Set getUnsentComments (ProjectVersion pv) - throws GeneralException - { - - return this.getDealtWithNotes (pv, - false); - - } - - public Set getUnsentComments () - throws GeneralException - { - - return this.getUnsentComments (this.proj.getProjectVersion ()); - - } - - @Override - public Set getTitleHeaderControlIds () - { - - Set ids = new LinkedHashSet (); - - ids.add (CONTACTS_HEADER_CONTROL_ID); - ids.add (FIND_HEADER_CONTROL_ID); - ids.add (FULL_SCREEN_HEADER_CONTROL_ID); - ids.add (SETTINGS_HEADER_CONTROL_ID); - - return ids; - - } - -} diff --git a/src/com/quollwriter/editors/ui/EditorRegister.java b/src/com/quollwriter/editors/ui/EditorRegister.java deleted file mode 100644 index 57de9f6e..00000000 --- a/src/com/quollwriter/editors/ui/EditorRegister.java +++ /dev/null @@ -1,1061 +0,0 @@ -package com.quollwriter.editors.ui; - -import java.awt.*; -import java.awt.event.*; - -import java.io.File; - -import java.net.*; - -import java.text.*; - -import java.util.Collections; -import java.util.Enumeration; -import java.util.Set; -import java.util.Map; -import java.util.LinkedHashSet; -import java.util.Arrays; - -import javax.swing.*; -import javax.swing.border.*; -import javax.swing.filechooser.*; -import javax.swing.tree.*; - -import org.bouncycastle.openpgp.*; - -import com.gentlyweb.xml.*; - -import com.jgoodies.forms.builder.*; -import com.jgoodies.forms.factories.*; -import com.jgoodies.forms.layout.*; - -import com.quollwriter.*; - -import com.quollwriter.data.*; - -import com.quollwriter.ui.*; -import com.quollwriter.ui.forms.*; -import com.quollwriter.events.*; -import com.quollwriter.ui.events.*; -import com.quollwriter.editors.*; - -import static com.quollwriter.LanguageStrings.*; -import static com.quollwriter.Environment.getUIString; - -public class EditorRegister extends Wizard -{ - - private JCheckBox tcAgreeField = null; - private JLabel tcError = null; - private JLabel loginError = null; - private FileFinder finder = null; - private JTextField emailField = null; - private JPasswordField passwordField = null; - private JPasswordField password2Field = null; - private JTextField nameField = null; - private ImageSelector avatar = null; - private JLabel saving = null; - private PGPKeyPair keyPair = null; - private String messagingUsername = null; - private String serviceName = null; - private boolean createCalled = false; - private boolean login = false; - private boolean tcsClicked = false; - - public EditorRegister (AbstractViewer viewer) - throws Exception - { - - super (viewer); - - final EditorRegister _this = this; - - Thread t = new Thread (new Runnable () - { - - public void run () - { - - // Create our public/private key. - try - { - - _this.keyPair = EditorsUtils.generateKeyPair (); - - } catch (Exception e) { - - Environment.logError ("Unable to generate key pair", - e); - - } - - } - - }); - - t.setPriority (Thread.MIN_PRIORITY); - t.start (); - - } -/* - public String getWindowTitle () - { - - return "Register for the Editor Service"; - - } - - public String getHeaderTitle () - { - - return this.getWindowTitle (); - - } - - public String getHeaderIconType () - { - - return "editors"; - - } -*/ - public String getFirstHelpText () - { - - return "Help!"; - - } - - public boolean handleFinish () - { - - // Init the editors db. - try - { - - EditorsEnvironment.initDB (this.finder.getSelectedFile ()); - - } catch (Exception e) { - - Environment.logError ("Unable to init editors database", - e); - - UIUtils.showErrorMessage (this.viewer, - getUIString (editors,user,register,actionerror)); - //"Unable to init editors database"); - - // Clean up db files? - - return true; - - } - - // Save the directory away for the editors db. (user property) - try - { - - EditorsEnvironment.setEditorsProperty (Constants.QW_EDITORS_DB_DIR_PROPERTY_NAME, - this.finder.getSelectedFile ().getPath ()); - - } catch (Exception e) { - - Environment.logError ("Unable to save editors database location", - e); - - UIUtils.showErrorMessage (this.viewer, - getUIString (editors,user,register,actionerror)); - //"Unable to save editors database location"); - - return true; - - } - - // Set the credentials. - if (!this.login) - { - - try - { - - EditorsEnvironment.initUserCredentials (this.emailField.getText ().trim ().toLowerCase (), - null, //new String (this.passwordField.getPassword ()), - this.serviceName, - this.messagingUsername, - this.keyPair.getPublicKey (), - this.keyPair.getPrivateKey ()); - - // Save the name/picture away. - String n = this.nameField.getText ().trim (); - - if (n.length () == 0) - { - - n = null; - - } - - EditorsEnvironment.setUserInformation (n, - this.avatar.getImage ()); - - } catch (Exception e) { - - Environment.logError ("Unable to save user information/credentials", - e); - - UIUtils.showErrorMessage (this.viewer, - getUIString (editors,user,register,actionerror)); - //"Unable to save your details"); - - return true; - - } - - } else { - - EditorsEnvironment.goOnline (null, - null, - null, - null); - - } - - try - { - - this.viewer.viewEditors (); - - } catch (Exception e) { - - Environment.logError ("Unable to show editors", - e); - - } - - return true; - - } - - public String getNextButtonLabel (String currStage) - { - - if ((currStage != null) - && - (currStage.equals ("existing")) - ) - { - - return getUIString (wizard,buttons,FINISH_BUTTON_ID); - //"Finish"; - - } - - if ((currStage != null) - && - (currStage.equals ("login-details")) - ) - { - - return getUIString (editors,user,register,buttons,register); - //"Register"; - - } - - return super.getNextButtonLabel (currStage); - - } - - public void handleCancel () - { - - } - - public String getNextStage (String currStage) - { - - if (currStage == null) - { - - return "start"; - - } - - if (currStage.equals ("start")) - { - - return "dir"; - - } - - if (currStage.equals ("dir")) - { - - return "about"; - - } - - if (currStage.equals ("login-details")) - { - - return "finish"; - - } - - if (currStage.equals ("about")) - { - - return "login-details"; - - } - - if (currStage.equals ("finish")) - { - - } - - return null; - - } - - public String getPreviousStage (String currStage) - { - - if (currStage == null) - { - - return null; - - } - - if (currStage.equals ("existing")) - { - - return "start"; - - } - - if (currStage.equals ("dir")) - { - - return "start"; - - } - - if (currStage.equals ("start")) - { - - return null; - - } - - if (currStage.equals ("login-details")) - { - - return "about"; - - } - - if (currStage.equals ("about")) - { - - return "dir"; - - } - - if (currStage.equals ("finish")) - { - - return null; - - } - - return null; - - } - - public boolean handleStageChange (String oldStage, - String newStage) - { - - if (oldStage == null) - { - - return true; - - } - - if ((newStage.equals ("finish")) - && - (this.createCalled) - ) - { - - return true; - - } - - if ((oldStage.equals ("start")) - && - (newStage.equals ("existing")) - ) - { - - return true; - - } - - if (oldStage.equals ("start")) - { - - if (!this.tcAgreeField.isSelected ()) - { - - this.tcError.setVisible (true); - - this.resize (); - - return false; - - } - - if (!this.tcsClicked) - { - - UIUtils.showMessage ((PopupsSupported) this.viewer, - getUIString (editors,user,register,stages,start,reminderpopup,title), - //"A gentle nudge", - getUIString (editors,user,register,stages,start,reminderpopup,text)); - //String.format ("The Terms and Conditions only take a couple of minutes to read. There is even a tl;dr of the impotant bits.

    It really is in your interests to give it a once over. Spare a couple of minutes and save yourself some hassle later.%s", - // "

    " + Environment.getQuollWriterHelpLink ("editor-mode/terms-and-conditions", - // "Click to view the Terms & Conditions"))); - - } - - } - - if (oldStage.equals ("dir")) - { - - if (newStage.equals ("start")) - { - - return true; - - } - - if (Utils.getQuollWriterDirFile (this.finder.getSelectedFile ()).exists ()) - { - - return false; - - } - - } - - if ((oldStage.equals ("login-details")) - && - (newStage.equals ("finish")) - ) - { - - final EditorRegister _this = this; - - String email = this.emailField.getText ().trim (); - - int atInd = email.indexOf ('@'); - - int dotInd = email.indexOf ('.', - atInd); - - if ((email.length () == 0) - || - (atInd == -1) - || - (dotInd == -1) - || - (email.length () - 1 == dotInd) - ) - { - - this.loginError.setText (getUIString (editors,user,register,stages,logindetails,errors,invalidemail)); - //"Please provide a valid email address."); - this.loginError.setVisible (true); - - this.resize (); - - return false; - - } - - String pwd = new String (this.passwordField.getPassword ()); - String pwd2 = new String (this.password2Field.getPassword ()); - - if (pwd.length () == 0) - { - - this.loginError.setText (getUIString (editors,user,register,stages,logindetails,errors,nopassword)); - //"Please provide a password."); - this.loginError.setVisible (true); - - this.resize (); - - return false; - - } - - if (pwd2.length () == 0) - { - - this.loginError.setText (getUIString (editors,user,register,stages,logindetails,errors,confirmpassword)); - //"Please confirm your password."); - this.loginError.setVisible (true); - - this.resize (); - - return false; - - } - - if (!pwd.equals (pwd2)) - { - - this.loginError.setText (getUIString (editors,user,register,stages,logindetails,errors,nomatch)); - //"Your passwords do not match."); - this.loginError.setVisible (true); - - this.resize (); - - return false; - - } - - if (pwd.length () < 8) - { - - this.loginError.setText (getUIString (editors,user,register,stages,logindetails,errors,minlength)); - //"Your password must be at least 8 characters long."); - this.loginError.setVisible (true); - - this.resize (); - - return false; - - } - - this.loginError.setVisible (false); - - // Create the account, show the saving. - this.enableButton ("finish", - false); - this.enableButton ("previous", - false); - this.enableButton ("cancel", - false); - - this.saving.setVisible (true); - - this.emailField.setEnabled (false); - this.passwordField.setEnabled (false); - this.password2Field.setEnabled (false); - - this.resize (); - - try - { - - EditorsEnvironment.getEditorsWebServiceHandler ().createAccount (email, - pwd, - this.keyPair.getPublicKey (), - new EditorsWebServiceAction () - { - - public void processResult (EditorsWebServiceResult res) - { - - Map d = (Map) res.getReturnObject (); - - _this.messagingUsername = (String) d.get ("username"); - _this.serviceName = (String) d.get ("servicename"); - - _this.createCalled = true; - - _this.showStage ("finish"); - - } - - }, - new EditorsWebServiceAction () - { - - public void processResult (EditorsWebServiceResult res) - { - - _this.enableButton ("finish", - true); - _this.enableButton ("previous", - true); - _this.enableButton ("cancel", - true); - - _this.saving.setVisible (false); - - // Handle parameter errors, then other error types. - - _this.emailField.setEnabled (true); - _this.passwordField.setEnabled (true); - _this.password2Field.setEnabled (true); - _this.loginError.setText (getUIString (editors,user,register,actionerror) + " " + res.getErrorMessage ()); - //"Unable to create account: " + res.getErrorMessage ()); - _this.loginError.setVisible (true); - - _this.resize (); - - } - - }); - - } catch (Exception e) { - - Environment.logError ("Unable to create account", - e); - - UIUtils.showErrorMessage (this.viewer, - getUIString (editors,user,register,actionerror)); - //"Unable to create account, please contact Quoll Writer support for assistance."); - - } - - return false; - - } - - return true; - - } - - public int getMaximumContentHeight () - { - - return 200; - - } - - public String getStartStage () - { - - return "start"; - - } - - public int getContentPreferredHeight () - { - - return 200; - - } - - public WizardStep getStage (String stage) - { - - final EditorRegister _this = this; - - WizardStep ws = new WizardStep (); - - if (stage.equals ("start")) - { - - java.util.List prefix = Arrays.asList (editors,user,register,stages,start); - - ws.title = getUIString (prefix,title); - //"Getting started"; - - ws.helpText = String.format (getUIString (prefix,text), - //"Welcome to the Quoll Writer Editors Service. The registration process only takes a minute and the service is free to use (no really).

    If you've already registered don't worry just use the link at the bottom to find your {editors} database.

    %s", - Environment.getQuollWriterHelpLink ("editor-mode/overview", - null)); - //"Find out more about the editor service.")); - - Box b = new Box (BoxLayout.Y_AXIS); - - JLabel tc = UIUtils.createClickableLabel (getUIString (prefix,labels,viewtandc), - //"View the Terms and Conditions for using the Editors service.", - Environment.getIcon (Constants.INFO_ICON_NAME, - Constants.ICON_CLICKABLE_LABEL), - Environment.getQuollWriterHelpLink ("editor-mode/terms-and-conditions", - null)); - - tc.addMouseListener (new MouseEventHandler () - { - - @Override - public void handlePress (MouseEvent ev) - { - - _this.tcsClicked = true; - - } - - }); - - tc.setBorder (UIUtils.createPadding (0, 0, 10, 5)); - - b.add (tc); - - this.tcError = UIUtils.createErrorLabel (getUIString (prefix,errors,agreetandc)); - //"You must agree to the Terms and Conditions to continue."); - - this.tcError.setVisible (false); - this.tcError.setBorder (new EmptyBorder (0, 0, 5, 0)); - - b.add (this.tcError); - - this.tcAgreeField = UIUtils.createCheckBox (getUIString (prefix,labels,agreetandc)); - //"I have read and agree to the Terms and Conditions of use"); - - this.tcAgreeField.addActionListener (new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - if (_this.tcAgreeField.isSelected ()) - { - - _this.tcError.setVisible (false); - _this.resize (); - - } - - } - - }); - - this.tcAgreeField.setMaximumSize (this.tcAgreeField.getPreferredSize ()); - - b.add (this.tcAgreeField); - - b.add (Box.createVerticalGlue ()); - - JLabel reg = UIUtils.createClickableLabel (getUIString (prefix,labels,alreadyregistered), - //"Already registered? Click here to find your {editors} database directory.", - Environment.getIcon (Constants.EDITORS_ICON_NAME, - Constants.ICON_CLICKABLE_LABEL), - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.showStage ("existing"); - - } - - }); - - reg.setBorder (UIUtils.createPadding (0, 5, 5, 5)); - - b.add (reg); - - b.setBorder (UIUtils.createPadding (0, 5, 0, 5)); - - ws.panel = b; - - } - - if (stage.equals ("existing")) - { - - java.util.List prefix = Arrays.asList (editors,user,register,stages,exists); - - this.login = true; - - ws.title = getUIString (prefix,title); - //"Find an existing {editors} database"; - - ws.helpText = getUIString (prefix,text); - //"Use the finder below to find your existing {editors} database."; - - final JLabel message = new JLabel (""); - - message.setVisible (false); - - message.setBorder (UIUtils.createPadding (0, 0, 5, 0)); - - this.finder = UIUtils.createFileFind (Environment.getUserQuollWriterDir ().getPath (), - getUIString (prefix,labels,LanguageStrings.finder,title), - //"Select a Directory", - JFileChooser.DIRECTORIES_ONLY, - getUIString (prefix,labels,LanguageStrings.finder,label), - //"Select", - null); - this.finder.setFindButtonToolTip (getUIString (prefix,labels,LanguageStrings.finder,tooltip)); - //,"Click to find a directory"); - - this.finder.setOnSelectHandler (new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - // See if it's an existing editors db, if so ask. - - if (!EditorsEnvironment.isEditorsDBDir (_this.finder.getSelectedFile ())) - { - - // Show an error - message.setText (String.format (getUIString (editors,user,register,stages,exists,errors,invalidvalue), - Constants.EDITORS_DB_FILE_NAME_PREFIX)); - //"" + Environment.replaceObjectNames ("Sorry, that doesn't look like {an editors} directory. There should be a file called: " + Constants.EDITORS_DB_FILE_NAME_PREFIX + ".h2.db in the directory.") + ""); - message.setForeground (UIUtils.getColor (Constants.ERROR_TEXT_COLOR)); - message.setIcon (Environment.getIcon (Constants.ERROR_RED_ICON_NAME, - Constants.ICON_MENU)); - - _this.enableButton ("finish", - false); - - } else { - - // See if the project is already in their project list. - - message.setText (getUIString (editors,user,register,stages,exists,labels,confirm)); - //"That looks like {an editors} directory.")); - message.setForeground (UIUtils.getColor ("#558631")); - message.setIcon (Environment.getIcon ("ok-green", - Constants.ICON_MENU)); - - // Set the seen sidebar property to ensure the welcome tab doesn't display. - try - { - - EditorsEnvironment.setEditorsProperty (Constants.QW_EDITORS_SERVICE_EDITORS_SIDEBAR_SEEN_PROPERTY_NAME, - true); - - } catch (Exception e) { - - Environment.logError ("Unable to set editors sidebar seen property", - e); - - } - - _this.enableButton ("finish", - true); - - } - - message.setVisible (true); - - // Open the database and show the information? - - _this.resize (); - - } - - }); - - Box b = new Box (BoxLayout.Y_AXIS); - - b.add (message); - b.add (this.finder); - b.setBorder (UIUtils.createPadding (0, 5, 0, 5)); - - ws.panel = b; - - } - - if (stage.equals ("dir")) - { - - java.util.List prefix = Arrays.asList (editors,user,register,stages,selectfolder); - - ws.title = getUIString (prefix,title); - //"Where to store editor information?"; - - ws.helpText = getUIString (prefix,text); - //"Information about your editors and chat messages is stored in a database on your local machine. Please select the directory where the information should be stored."; - - final JLabel finderError = UIUtils.createErrorLabel (getUIString (prefix,errors,invalidvalue)); - //"Sorry, that looks like an existing Quoll Writer project directory."); - - finderError.setVisible (false); - finderError.setBorder (new EmptyBorder (0, 0, 5, 0)); - - this.finder = UIUtils.createFileFind (Environment.getUserQuollWriterDir ().getPath () + "/editors", - getUIString (prefix,LanguageStrings.finder,title), - //"Select a Directory", - JFileChooser.DIRECTORIES_ONLY, - getUIString (prefix,LanguageStrings.finder,button), - //"Select", - null); - this.finder.setFindButtonToolTip (getUIString (prefix,LanguageStrings.finder,tooltip)); - //"Click to find a directory"); - - this.finder.setOnSelectHandler (new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - finderError.setVisible (false); - - // See if it's an existing editors db, if so ask. - - if (Utils.getQuollWriterDirFile (_this.finder.getSelectedFile ()).exists ()) - { - - finderError.setVisible (true); - - } - - _this.resize (); - - } - - }); - - // Support encryption? - - Box b = new Box (BoxLayout.Y_AXIS); - - b.add (finderError); - b.add (this.finder); - b.setBorder (UIUtils.createPadding (0, 5, 0, 5)); - - ws.panel = b; - - } - - if (stage.equals ("finish")) - { - - java.util.List prefix = Arrays.asList (editors,user,register,stages,finish); - - ws.title = getUIString (prefix,title); - //"Account created, just one more step"; - - ws.helpText = String.format (getUIString (prefix,text), - this.emailField.getText ().trim ()); - //"Your account has been created. But there is one final step to complete the process. A confirmation email has been sent to " + this.emailField.getText ().trim () + ". Please click on the link to complete the process."; - - ws.panel = new JLabel (getUIString (prefix,labels,check)); - //"Check your email and have fun!"); - - } - - if (stage.equals ("about")) - { - - java.util.List prefix = Arrays.asList (editors,user,register,stages,about); - - ws.title = getUIString (prefix,title); - //"About you"; - - ws.helpText = getUIString (prefix,text); - //"Here you can provide some information about yourself. This will be sent to editors to let them know about you. The information is optional."; - - this.nameField = UIUtils.createTextField (); - this.nameField.setPreferredSize (new Dimension (200, - this.nameField.getPreferredSize ().height)); - - java.util.List fileTypes = new java.util.ArrayList (); - fileTypes.add ("jpg"); - fileTypes.add ("jpeg"); - fileTypes.add ("png"); - fileTypes.add ("gif"); - - Box b = new Box (BoxLayout.X_AXIS); - - java.awt.image.BufferedImage noImage = null; - - this.avatar = new ImageSelector (noImage, - fileTypes, - new Dimension (75, 75)); - this.avatar.setBorder (UIUtils.createLineBorder ()); - - b.add (this.avatar); - - Set items = new LinkedHashSet (); - - items.add (new AnyFormItem (getUIString (prefix,labels,name), - //"Your name", - this.nameField)); - - items.add (new AnyFormItem (getUIString (prefix,labels,LanguageStrings.avatar), - //"Your picture/Avatar", - b)); - - JComponent p = UIUtils.createForm (items); - - ws.panel = p; - - } - - if (stage.equals ("login-details")) - { - - java.util.List prefix = Arrays.asList (editors,user,register,stages,logindetails); - - ws.title = getUIString (prefix,title); - //"Your login details"; - - ws.helpText = getUIString (prefix,text); - //"And finally. To access the Editors service you will need to login. Please provide an email address/password below. Note: it is recommended that you create a separate email account for use with this service."; - - this.saving= new JLabel (Environment.getLoadingIcon ()); - this.saving.setText (getUIString (prefix,LanguageStrings.saving)); - //"Creating account, please wait..."); - this.saving.setBorder (new EmptyBorder (5, 10, 5, 5)); - - this.saving.setVisible (false); - - this.loginError = UIUtils.createErrorLabel ("___bogus"); - this.loginError.setVisible (false); - this.loginError.setBorder (new EmptyBorder (0, 0, 5, 0)); - - this.emailField = UIUtils.createTextField (); - this.passwordField = new JPasswordField (); - this.password2Field = new JPasswordField (); - - Set items = new LinkedHashSet (); - - items.add (new AnyFormItem (getUIString (prefix,labels,email), - //"Email", - this.emailField)); - - items.add (new AnyFormItem (getUIString (prefix,labels,password), - //"Password", - this.passwordField)); - - items.add (new AnyFormItem (getUIString (prefix,labels,confirmpassword), - //"Confirm Password", - this.password2Field)); - - Box b = new Box (BoxLayout.Y_AXIS); - - b.add (this.saving); - b.add (this.loginError); - b.add (UIUtils.createForm (items)); - - ws.panel = b; - - } - - return ws; - - } - - @Override - protected void enableButtons (String currentStage) - { - - super.enableButtons (currentStage); - - if (currentStage.equals ("existing")) - { - - this.enableButton ("finish", - false); - - } - - } - -} diff --git a/src/com/quollwriter/editors/ui/EditorRemovedMessageBox.java b/src/com/quollwriter/editors/ui/EditorRemovedMessageBox.java deleted file mode 100644 index 83152a2c..00000000 --- a/src/com/quollwriter/editors/ui/EditorRemovedMessageBox.java +++ /dev/null @@ -1,210 +0,0 @@ -package com.quollwriter.editors.ui; - -import java.util.Date; -import java.util.List; -import java.util.ArrayList; -import java.util.Map; -import java.util.LinkedHashMap; - -import java.awt.event.*; -import java.awt.Component; -import java.awt.Dimension; -import javax.swing.*; -import javax.swing.border.*; - -import com.jgoodies.forms.builder.*; -import com.jgoodies.forms.factories.*; -import com.jgoodies.forms.layout.*; - -import com.quollwriter.*; -import com.quollwriter.ui.*; -import com.quollwriter.data.*; -import com.quollwriter.data.editors.*; -import com.quollwriter.ui.components.ImagePanel; -import com.quollwriter.editors.messages.*; -import com.quollwriter.editors.*; - -import static com.quollwriter.LanguageStrings.*; -import static com.quollwriter.Environment.getUIString; - -public class EditorRemovedMessageBox extends MessageBox -{ - - private Box responseBox = null; - - public EditorRemovedMessageBox (EditorRemovedMessage mess, - AbstractViewer viewer) - { - - super (mess, - viewer); - - } - - public boolean isAutoDealtWith () - { - - return false; - - } - - public void doUpdate () - { - - if (this.message.isDealtWith ()) - { - - if (this.responseBox != null) - { - - this.responseBox.setVisible (false); - - } - - } - - } - - public void doInit () - { - - final EditorRemovedMessageBox _this = this; - - String title = null; - String text = null; - - if (this.message.isSentByMe ()) - { - - title = getUIString (editors,messages,contactremoved,sent,LanguageStrings.title); - text = String.format (getUIString (editors,messages,contactremoved,sent,LanguageStrings.text), - //"You removed %s as a {contact}. You will no longer receive any messages from them or be able to send them messages.", - this.message.getEditor ().getShortName ()); - - } else { - - title = getUIString (editors,messages,contactremoved,received,LanguageStrings.title); - text = String.format (getUIString (editors,messages,contactremoved,received,LanguageStrings.text), - //"You removed %s as a {contact}. You will no longer receive any messages from them or be able to send them messages.", - this.message.getEditor ().getShortName ()); - - } - - JComponent h = UIUtils.createBoldSubHeader (title, - //String.format ("Removed %sas {a contact}", - // (this.message.isSentByMe () ? "" : "you ")), - Constants.DELETE_ICON_NAME); - - this.add (h); - - JTextPane desc = UIUtils.createHelpTextPane (text, - this.viewer); - - this.add (Box.createVerticalStrut (5)); - - Box descb = new Box (BoxLayout.Y_AXIS); - descb.setBorder (UIUtils.createPadding (0, 5, 0, 0)); - descb.add (desc); - descb.setAlignmentX (Component.LEFT_ALIGNMENT); - this.add (descb); - - desc.setBorder (null); - desc.setSize (new Dimension (UIUtils.getPopupWidth () - 20, - desc.getPreferredSize ().height)); - - if (!this.message.isDealtWith ()) - { - - // Show the response. - this.responseBox = new Box (BoxLayout.Y_AXIS); - - this.add (this.responseBox); - - JTextPane rdesc = UIUtils.createHelpTextPane (String.format (getUIString (editors,messages,contactremoved,received,undealtwith,LanguageStrings.text), - //"Clicking on the button below will remove %s from your list of current {contacts}. You can still get access to them in the options menu of the {Contacts} sidebar via the View the previous {contacts} item.", - this.message.getEditor ().getShortName ()), - this.viewer); - - this.responseBox.add (Box.createVerticalStrut (5)); - - Box rdescb = new Box (BoxLayout.Y_AXIS); - rdescb.setBorder (UIUtils.createPadding (0, 5, 0, 0)); - rdescb.add (rdesc); - rdescb.setAlignmentX (Component.LEFT_ALIGNMENT); - this.responseBox.add (rdescb); - - rdesc.setBorder (null); - rdesc.setSize (new Dimension (UIUtils.getPopupWidth () - 20, - rdesc.getPreferredSize ().height)); - - final EditorEditor ed = this.message.getEditor (); - - this.responseBox.setBorder (UIUtils.createPadding (5, 0, 0, 0)); - - JButton ok = UIUtils.createButton (getUIString (editors,messages,contactremoved,received,undealtwith,buttons,confirm)); - //"Ok, got it"); - - ok.addActionListener (new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - try - { - - // Unsubscribe. - EditorsEnvironment.getMessageHandler ().unsubscribeFromEditor (ed); - - // For all projects, if they are a project editor then set them as previous. - EditorsEnvironment.removeEditorAsProjectEditorForAllProjects (ed); - - // Uupdate the editor to be previous. - ed.setEditorStatus (EditorEditor.EditorStatus.previous); - - EditorsEnvironment.updateEditor (ed); - - _this.responseBox.setVisible (false); - - _this.message.setDealtWith (true); - - EditorsEnvironment.updateMessage (_this.message); - - // Offer to remove any projects we are editing for them. - EditorsUIUtils.showDeleteProjectsForEditor (_this.viewer, - _this.message.getEditor (), - null); - - } catch (Exception e) { - - Environment.logError ("Unable to update editor: " + - ed, - e); - - UIUtils.showErrorMessage (_this.viewer, - getUIString (editors,messages,update,actionerror)); - //"Unable to update {contact}, please contact Quoll Writer support for assistance."); - - return; - - } - - } - - }); - - JButton[] buts = new JButton[] { ok }; - - JPanel bb = UIUtils.createButtonBar2 (buts, - Component.LEFT_ALIGNMENT); - bb.setOpaque (false); - bb.setAlignmentX (Component.LEFT_ALIGNMENT); - bb.setBorder (UIUtils.createPadding (5, 0, 0, 0)); - - this.responseBox.add (bb); - - } - - } - -} diff --git a/src/com/quollwriter/editors/ui/EditorsUIUtils.java b/src/com/quollwriter/editors/ui/EditorsUIUtils.java deleted file mode 100644 index 0e7df852..00000000 --- a/src/com/quollwriter/editors/ui/EditorsUIUtils.java +++ /dev/null @@ -1,6407 +0,0 @@ -package com.quollwriter.editors.ui; - -import java.util.*; -import java.net.*; -import java.io.*; - -import java.awt.Color; -import java.awt.Point; -import java.awt.Dimension; -import java.awt.Component; -import java.awt.event.*; -import java.awt.image.*; -import javax.swing.*; -import javax.swing.event.*; -import javax.swing.tree.*; -import javax.swing.border.*; - -import com.jgoodies.forms.builder.*; -import com.jgoodies.forms.factories.*; -import com.jgoodies.forms.layout.*; - -import org.josql.*; - -import com.toedter.calendar.*; - -import com.quollwriter.*; -import com.quollwriter.events.*; -import com.quollwriter.data.comparators.*; -import com.quollwriter.editors.ui.sidebars.*; -import com.quollwriter.data.*; -import com.quollwriter.data.editors.*; -import com.quollwriter.ui.*; -import com.quollwriter.ui.forms.*; -import com.quollwriter.ui.panels.*; -import com.quollwriter.ui.renderers.*; -import com.quollwriter.ui.components.QPopup; -import com.quollwriter.ui.components.ImagePanel; -import com.quollwriter.ui.components.ScrollableBox; -import com.quollwriter.ui.components.ActionAdapter; -import com.quollwriter.editors.*; -import com.quollwriter.editors.messages.*; -import com.quollwriter.text.*; - -import static com.quollwriter.LanguageStrings.*; -import static com.quollwriter.Environment.getUIString; - -public class EditorsUIUtils -{ - - private static EditorLogin editorLogin = null; - private static EditorMessageFilter defaultViewableMessageFilter = null; - private static EditorMessageFilter importantMessageFilter = null; - - static - { - - //EditorsUIUtils.editorLogin = new EditorLogin (); - - // Defines the messages that can be "viewed" by the user. - Project np = null; - - EditorsUIUtils.defaultViewableMessageFilter = new DefaultEditorMessageFilter (np, - EditorChatMessage.MESSAGE_TYPE, - EditorInfoMessage.MESSAGE_TYPE, - NewProjectMessage.MESSAGE_TYPE, - NewProjectResponseMessage.MESSAGE_TYPE, - ProjectCommentsMessage.MESSAGE_TYPE, - InviteMessage.MESSAGE_TYPE, - InviteResponseMessage.MESSAGE_TYPE, - ProjectEditStopMessage.MESSAGE_TYPE, - UpdateProjectMessage.MESSAGE_TYPE, - EditorRemovedMessage.MESSAGE_TYPE); - - EditorsUIUtils.importantMessageFilter = new EditorMessageFilter () - { - - @Override - public boolean accept (EditorMessage m) - { - - if (!EditorsUIUtils.getDefaultViewableMessageFilter ().accept (m)) - { - - return false; - - } - - if (m.isDealtWith ()) - { - - return false; - - } - /* - if (m.getMessageType ().equals (EditorChatMessage.MESSAGE_TYPE)) - { - - return false; - - } - */ - /* - if (m.getMessageType ().equals (ProjectCommentsMessage.MESSAGE_TYPE)) - { - - return false; - - } -*/ - return true; - - } - - }; - - }; - - public static EditorMessageFilter getImportantMessageFilter () - { - - return EditorsUIUtils.importantMessageFilter; - - } - - public static EditorMessageFilter getDefaultViewableMessageFilter () - { - - return EditorsUIUtils.defaultViewableMessageFilter; - - } - - public static void showDeleteAccount (final AbstractViewer viewer) - { - - // Remove all editors. - - // Send project edit stop for all projects they are editing. - - // Remove account. - - java.util.List prefix = Arrays.asList (editors,user,deleteaccount,popup); - - //String s = "To delete your account please enter the word Yes in the box below.

    Note: Your {contacts} database will not be deleted allowing you to keep a record of what you have sent and received. If you create another account you will not be able to use your current database.

    Warning: deleting your account means you will no longer be able to send messages to any of your {contacts} or receive messages from them. A message will be sent to each of them telling them you have removed them.

    "; - - UIUtils.createTextInputPopup (viewer, - getUIString (prefix,title), - //"Delete your account", - Constants.DELETE_ICON_NAME, - getUIString (prefix,text), - //s, - getUIString (prefix,buttons,confirm), - //"Yes, delete it", - getUIString (prefix,buttons,cancel), - //"No, keep it", - null, - UIUtils.getYesValueValidator (), - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - final String dbDir = EditorsEnvironment.getEditorsProperty (Constants.QW_EDITORS_DB_DIR_PROPERTY_NAME); - - final Notification notify = viewer.addNotification (getUIString (editors,user,deleteaccount,notification), - //"Deleting your Editors Service account, please wait. This sometimes takes a little while...", - Constants.LOADING_GIF_NAME, - -1); - - EditorsEnvironment.deleteUserAccount (new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - // Remove the editors sidebar. - Environment.removeSideBarFromAllProjectViewers (EditorsSideBar.ID); - - viewer.removeNotification (notify); - - AbstractViewer viewer = Environment.getFocusedViewer (); - - String url = ""; - - try - { - - url = new File (dbDir).toURI ().toURL ().toString (); - - } catch (Exception e) { - - Environment.logError ("Unable to convert file: " + - dbDir + - " to a url", - e); - - } - - UIUtils.showMessage ((PopupsSupported) viewer, - getUIString (editors,user,deleteaccount,confirmpopup,title), - //"Account deleted", - String.format (getUIString (editors,user,deleteaccount,confirmpopup,text), - //"Your Editors Service account has been deleted.

    Your {contacts} database has not been deleted.
    Click to view the folder containing the database", - url)); - - } - - }, - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - AbstractViewer viewer = Environment.getFocusedViewer (); - - UIUtils.showErrorMessage (viewer, - getUIString (editors,user,deleteaccount,actionerror)); - //"Unable to delete your account, please contact Quoll Writer support for assistance."); - - } - - }); - - } - - }, - null, - null); - - } - - /** - * If we are editing any projects for any editors then show a popup offering to delete - * the projects. Once the delete is complete (or there are no projects) call onRemoveComplete. - * If any of the projects are open then they are force closed first. - * - */ - public static void showDeleteProjectsForAllEditors (final AbstractViewer viewer, - final ActionListener onRemoveComplete) - { - - Set eds = new HashSet (); - - Set edProjs = null; - - try - { - - edProjs = Environment.getAllProjectInfos (Project.EDITOR_PROJECT_TYPE); - - } catch (Exception e) { - - Environment.logError ("Unable to get all editor projects", - e); - - UIUtils.showErrorMessage (viewer, - getUIString (editors,user,deletealleditorprojects,actionerror)); - //"Unable to get all {projects}, please contact Quoll Support for assistance."); - - if (onRemoveComplete != null) - { - - onRemoveComplete.actionPerformed (new ActionEvent (viewer, 1, "complete")); - - } - - return; - - } - - for (ProjectInfo p : edProjs) - { - - eds.add (p.getForEditor ()); - - } - - if (edProjs.size () > 0) - { - - final ActionListener deleteEditorProjs = new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - Set edProjs = new LinkedHashSet (); - - try - { - - edProjs = Environment.getAllProjectInfos (Project.EDITOR_PROJECT_TYPE); - - } catch (Exception e) { - - Environment.logError ("Unable to get all editor projects", - e); - - UIUtils.showErrorMessage (viewer, - getUIString (editors,user,deletealleditorprojects,actionerror)); - //"Unable to get all {projects}, please contact Quoll Support for assistance."); - - if (onRemoveComplete != null) - { - - onRemoveComplete.actionPerformed (new ActionEvent (viewer, 1, "complete")); - - } - - return; - - } - - for (ProjectInfo p : edProjs) - { - - try - { - - Environment.deleteProject (p, - null); - - } catch (Exception e) { - - Environment.logError ("Unable to delete project: " + - p, - e); - - UIUtils.showErrorMessage (viewer, - getUIString (editors,user,deletealleditorprojects,actionerror)); - - } - - } - - if (onRemoveComplete != null) - { - - onRemoveComplete.actionPerformed (ev); - - } - - } - - }; - - java.util.List prefix = Arrays.asList (editors,user,deletealleditorprojects,popup); - - String sb = String.format (getUIString (prefix,text), - //"You are currently editing %s {project%s} for %s {contact%s}. To remove them enter the word Yes below.", - Environment.formatNumber (edProjs.size ()), - Environment.formatNumber (eds.size ())); - - UIUtils.createTextInputPopup (viewer, - getUIString (prefix,title), - //"Delete all {projects} for {contact}", - Constants.DELETE_ICON_NAME, - sb, - getUIString (prefix,buttons,confirm), - //"Yes, delete them", - getUIString (prefix,buttons,cancel), - //"No, keep them", - null, - UIUtils.getYesValueValidator (), - deleteEditorProjs, - onRemoveComplete, - null); - - } else { - - if (onRemoveComplete != null) - { - - onRemoveComplete.actionPerformed (new ActionEvent (viewer, 1, "complete")); - - } - - } - - } - - /** - * If we are editing any projects for the specified editor then show a popup offering to delete - * the projects. Once the delete is complete (or there are no projects) call onRemoveComplete. - * If any of the projects are open then they are force closed first. - * - */ - public static void showDeleteProjectsForEditor (final AbstractViewer viewer, - final EditorEditor ed, - final ActionListener onRemoveComplete) - { - - // Remove all projects for the editor. - Set edProjs = null; - - try - { - - edProjs = EditorsEnvironment.getProjectsForEditor (ed); - - } catch (Exception e) { - - Environment.logError ("Unable to get projects for editor: " + - ed, - e); - - UIUtils.showErrorMessage (viewer, - getUIString (editors,user,deleteprojectsforeditor,actionerror)); - //"Unable to get {projects} for {editor}, please contact Quoll Writer support for assistance."); - - return; - - } - - if (edProjs.size () > 0) - { - - final ActionListener deleteEditorProjs = new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - Set edProjs = null; - - try - { - - edProjs = EditorsEnvironment.getProjectsForEditor (ed); - - } catch (Exception e) { - - Environment.logError ("Unable to get projects for editor: " + - ed, - e); - - UIUtils.showErrorMessage (viewer, - getUIString (editors,user,deleteprojectsforeditor,actionerror)); - //"Unable to get {projects} for {contact}, please contact Quoll Writer support for assistance."); - - return; - - } - - for (ProjectInfo p : edProjs) - { - - // Just to be sure. - if (!p.getType ().equals (Project.EDITOR_PROJECT_TYPE)) - { - - continue; - - } - - Environment.deleteProject (p, - null); - - } - - if (onRemoveComplete != null) - { - - onRemoveComplete.actionPerformed (ev); - - } - - } - - }; - - java.util.List prefix = Arrays.asList (editors,user,deleteprojectsforeditor,popup); - - String sb = String.format (getUIString (prefix,text), - //"You are currently editing %s {project%s} for %s. To remove them enter the word Yes below.", - Environment.formatNumber (edProjs.size ()), - ed.getShortName ()); - - UIUtils.createTextInputPopup (viewer, - getUIString (prefix,title), - //"Delete {projects} for {contact}", - Constants.DELETE_ICON_NAME, - sb, - getUIString (prefix,buttons,confirm), - //"Yes, delete them", - getUIString (prefix,buttons,cancel), - //"No, keep them", - null, - UIUtils.getYesValueValidator (), - deleteEditorProjs, - onRemoveComplete, - null); - - } else { - - if (onRemoveComplete != null) - { - - onRemoveComplete.actionPerformed (new ActionEvent (ed, 1, "complete")); - - } - - } - - } - - public static void showRemoveEditor (final AbstractViewer viewer, - final EditorEditor ed, - final ActionListener onRemoveComplete) - { - - // If the editor is pending then just remove them and remove the invite. - if (ed.isPending ()) - { - - java.util.List prefix = Arrays.asList (editors,editor,remove,popup); - - UIUtils.createTextInputPopup (viewer, - getUIString (prefix,title), - //"Remove {contact}", - Constants.DELETE_ICON_NAME, - String.format (getUIString (prefix,text), - //"To confirm removal of %s as {a contact} please enter the word Yes in the box below.", - ed.getShortName ()), - getUIString (prefix,buttons,confirm), - //"Yes, remove them", - getUIString (prefix,buttons,cancel), - //"No, keep them", - null, - UIUtils.getYesValueValidator (), - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - EditorsEnvironment.removePendingEditor (ed, - onRemoveComplete); - - } - - }, - null, - null); - - return; - - } - - final ActionListener onComplete = new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - AbstractViewer viewer = Environment.getFocusedViewer (); - - java.util.List prefix = Arrays.asList (editors,editor,remove,confirmpopup); - - UIUtils.showMessage ((PopupsSupported) viewer, - getUIString (prefix,title), - //"{Contact} removed", - String.format (getUIString (prefix,text), - //"%s has been removed as a {contact}.", - ed.getMainName ())); - - } - - }; - - final ActionListener removeEditor = new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - EditorsEnvironment.removeEditor (ed, - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - EditorsUIUtils.showDeleteProjectsForEditor (Environment.getFocusedViewer (), - ed, - onComplete); - - } - - }); - - } - - }; - - java.util.List prefix = Arrays.asList (editors,editor,remove,popup); - - String sb = String.format (getUIString (prefix,text), - //"Please confirm you wish to remove %s as {a contact}.

    A message will be sent to %s informing them of your decision.

    Enter Yes below to remove them.

    Warning: you will no longer be able to receive messages from %s or send messages to them.

    ", - ed.getMainName ()); - - UIUtils.createTextInputPopup (viewer, - getUIString (prefix,title), - //"Remove {contact}", - Constants.DELETE_ICON_NAME, - sb, - getUIString (prefix,buttons,confirm), - //"Yes, remove them", - getUIString (prefix,buttons,cancel), - //"No, keep them", - null, - UIUtils.getYesValueValidator (), - removeEditor, - null, - null); - - } - - /* - * Maybe move this to be a Form. - */ - public static void updateYourInfo (final AbstractViewer viewer) - { - - java.util.List prefix = Arrays.asList (editors,user,edit,info,popup); - - final QPopup qp = UIUtils.createClosablePopup (getUIString (prefix,title), - //"Update your name/avatar", - Environment.getIcon (Constants.EDIT_ICON_NAME, - Constants.ICON_POPUP), - null); - - Box content = new Box (BoxLayout.Y_AXIS); - - JTextPane desc = UIUtils.createHelpTextPane (getUIString (prefix,text), - //"Change your name/avatar below. Note: clicking Save below will send any changes to your {editors}.", - viewer); - - content.add (desc); - desc.setBorder (null); - desc.setSize (new Dimension (UIUtils.getPopupWidth () - 20, - desc.getPreferredSize ().height)); - - final JLabel error = UIUtils.createErrorLabel (""); - - error.setBorder (new EmptyBorder (10, 0, 0, 0)); - error.setVisible (false); - - content.add (error); - - EditorAccount acc = EditorsEnvironment.getUserAccount (); - - final String accName = (acc.getName ()); - - final JTextField nameF = new JTextField (accName); - - java.util.List fileTypes = new java.util.ArrayList (); - fileTypes.add ("jpg"); - fileTypes.add ("jpeg"); - fileTypes.add ("png"); - fileTypes.add ("gif"); - - Box b = new Box (BoxLayout.X_AXIS); - - BufferedImage im = acc.getAvatar (); - - final ImageSelector avatar = new ImageSelector (im, - fileTypes, - new Dimension (75, 75)); - avatar.setBorder (UIUtils.createLineBorder ()); - - avatar.addChangeListener (new ChangeListener () - { - - public void stateChanged (ChangeEvent ev) - { - - qp.resize (); - - } - - }); - - b.add (avatar); - - Set items = new LinkedHashSet (); - - items.add (new AnyFormItem (getUIString (prefix,labels,name), - //"Your Name", - nameF)); - - items.add (new AnyFormItem (getUIString (prefix,labels,LanguageStrings.avatar), - //"Your picture/Avatar", - b)); - - final JButton updateB = UIUtils.createButton (getUIString (prefix,buttons,confirm), - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - error.setVisible (false); - - // Update the user data. - String newName = nameF.getText ().trim (); - - if (newName.length () == 0) - { - - error.setText (getUIString (prefix,errors,noname));//"Please provide your name."); - error.setVisible (true); - - qp.resize (); - - return; - - } - - try - { - - EditorsEnvironment.setUserInformation (newName, - avatar.getImage ()); - - EditorsEnvironment.sendUserInformationToAllEditors (new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - if (EditorsEnvironment.getEditors ().size () > 0) - { - - java.util.List prefix = Arrays.asList (editors,user,edit,info,confirmpopup); - - UIUtils.showMessage ((PopupsSupported) viewer, - getUIString (prefix,title), - //"Details sent", - getUIString (prefix,text)); - //"Your updated details have been sent to your {editors}"); - - } - - } - - }, - null, - null); - - } catch (Exception e) { - - Environment.logError ("Unable to update user information", - e); - - UIUtils.showErrorMessage (viewer, - getUIString (editors,user,edit,info,actionerror)); - //"Unable to update user information, please contact Quoll Writer support for assistance."); - - } - - qp.removeFromParent (); - - } - - }); - - final JButton cancelB = UIUtils.createButton (getUIString (prefix,buttons,cancel), - //Environment.getButtonLabel (Constants.CANCEL_BUTTON_LABEL_ID), - qp.getCloseAction ()); - - Set buttons = new LinkedHashSet (); - buttons.add (updateB); - buttons.add (cancelB); - - Form f = UIUtils.createForm (items, - buttons); - - f.setBorder (UIUtils.createPadding (10, 5, 0, 5)); - - content.add (f); - - content.setBorder (UIUtils.createPadding (10, 10, 10, 10)); - content.setPreferredSize (new Dimension (UIUtils.getPopupWidth (), - content.getPreferredSize ().height)); - - qp.setContent (content); - - viewer.showPopupAt (qp, - UIUtils.getCenterShowPosition (viewer, - qp), - false); - - qp.setDraggable (viewer); - qp.resize (); - - } - - /* - * Maybe move this to be a Form. - */ - public static void updateEditorInfo (final AbstractViewer viewer, - final EditorEditor ed) - { - - java.util.List prefix = Arrays.asList (editors,editor,edit,popup); - - final QPopup qp = UIUtils.createClosablePopup (getUIString (prefix,title), - //"Update the {contact} information", - Environment.getIcon (Constants.EDIT_ICON_NAME, - Constants.ICON_POPUP), - null); - - Box content = new Box (BoxLayout.Y_AXIS); - - JTextPane desc = UIUtils.createHelpTextPane (String.format (getUIString (prefix,text), - ed.getMainName ()), - //"Change the name/avatar for " + ed.getMainName () + " below.", - viewer); - - content.add (desc); - desc.setBorder (null); - desc.setSize (new Dimension (UIUtils.getPopupWidth () - 20, - desc.getPreferredSize ().height)); - - final JLabel error = UIUtils.createErrorLabel (""); - - error.setBorder (new EmptyBorder (10, 0, 0, 0)); - error.setVisible (false); - - content.add (error); - - FormLayout fl = new FormLayout ("6px, right:p, 6px, fill:200px:grow", - "10px, p, 6px, top:p, 10px, p"); - - fl.setHonorsVisibility (true); - PanelBuilder builder = new PanelBuilder (fl); - - CellConstraints cc = new CellConstraints (); - - int row = 2; - - builder.addLabel (getUIString (prefix,labels,name), - //"Name", - cc.xy (2, - row)); - - String name = ed.getMyNameForEditor (); - - if (name == null) - { - - name = ed.getMainName (); - - } - - final String edOrigName = (ed.getName () != null ? ed.getName () : ed.getEmail ()); - - final JTextField nameF = new JTextField (name); - - Box nameB = new Box (BoxLayout.X_AXIS); - nameB.add (nameF); - nameB.add (Box.createHorizontalStrut (3)); - nameB.add (UIUtils.createButton (Constants.RESET_ICON_NAME, - Constants.ICON_MENU, - String.format (getUIString (prefix,labels,reset,tooltip), - edOrigName), - //"Click to reset the name to " + edOrigName, - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - nameF.setText (edOrigName); - - } - - })); - - builder.add (nameB, - cc.xy (4, - row)); - - row += 2; - - builder.addLabel (getUIString (prefix,labels,avatar), - //"Avatar", - cc.xy (2, - row)); - - java.util.List fileTypes = new java.util.ArrayList (); - fileTypes.add ("jpg"); - fileTypes.add ("jpeg"); - fileTypes.add ("png"); - fileTypes.add ("gif"); - - Box b = new Box (BoxLayout.X_AXIS); - - BufferedImage im = ed.getMyAvatarForEditor (); - - if (im == null) - { - - im = ed.getAvatar (); - - } - - final ImageSelector avatar = new ImageSelector (im, - fileTypes, - new Dimension (75, 75)); - avatar.setBorder (UIUtils.createLineBorder ()); - - avatar.addChangeListener (new ChangeListener () - { - - public void stateChanged (ChangeEvent ev) - { - - qp.resize (); - - } - - }); - - b.add (avatar); - - builder.add (b, - cc.xy (4, - row)); - - final JButton updateB = UIUtils.createButton (getUIString (prefix,buttons,confirm), - //Environment.getButtonLabel (Constants.UPDATE_BUTTON_LABEL_ID), - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - error.setVisible (false); - - // Update "my" data for the editor. - String newName = nameF.getText ().trim (); - - if (newName.length () == 0) - { - - error.setText (getUIString (editors,editor,edit,popup,errors,noname)); - //"A name must be specified."); - error.setVisible (true); - - qp.resize (); - - return; - - } - - BufferedImage avIm = UIUtils.getScaledImage (avatar.getImage (), - 300); - - ed.setMyAvatarForEditor (avIm); - ed.setMyNameForEditor (nameF.getText ().trim ()); - - try - { - - EditorsEnvironment.updateEditor (ed); - - } catch (Exception e) { - - Environment.logError ("Unable to update editor: " + ed, - e); - - UIUtils.showErrorMessage (viewer, - getUIString (editors,editor,edit,actionerror)); - //"Unable to update {editor}, please contact Quoll Writer support for assistance."); - - } - - qp.removeFromParent (); - - } - - }); - - final JButton cancelB = UIUtils.createButton (getUIString (prefix,buttons,cancel), - //Environment.getButtonLabel (Constants.CANCEL_BUTTON_LABEL_ID), - qp.getCloseAction ()); - - row += 2; - - JComponent bs = UIUtils.createButtonBar2 (new JButton[] {updateB, cancelB}, - Component.LEFT_ALIGNMENT); - - builder.add (bs, - cc.xy (4, - row)); - - JPanel p = builder.getPanel (); - p.setOpaque (false); - p.setAlignmentX (JComponent.LEFT_ALIGNMENT); - - content.add (p); - - content.setBorder (new EmptyBorder (10, 10, 10, 10)); - content.setPreferredSize (new Dimension (UIUtils.getPopupWidth (), - content.getPreferredSize ().height)); - - qp.setContent (content); - - viewer.showPopupAt (qp, - UIUtils.getCenterShowPosition (viewer, - qp), - false); - - qp.setDraggable (viewer); - qp.resize (); - } - -/* -Not used. - public static void showEditorInfoReceived (final EditorInfoMessage info) - { - - UIUtils.doLater (new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - java.util.List prefix = Arrays.asList (editors,editor,updated,popup); - - final EditorEditor ed = info.getEditor (); - - Box content = new Box (BoxLayout.Y_AXIS); - - AbstractViewer viewer = Environment.getFocusedViewer (); - - JTextPane desc = UIUtils.createHelpTextPane (String.format (getUIString (prefix,text), - ed.getMainName ()), - //"" + ed.getMainName () + " has updated their information. To accept the changes click on the Update button below, to keep the current name and avatar click Reject.", - viewer); - - content.add (desc); - desc.setBorder (null); - desc.setSize (new Dimension (UIUtils.getPopupWidth () - 20, - desc.getPreferredSize ().height)); - - content.add (Box.createVerticalStrut (10)); - - FormLayout fl = new FormLayout ("6px, right:p, 6px, fill:200px:grow", - "10px, p, 6px, p"); - - fl.setHonorsVisibility (true); - PanelBuilder builder = new PanelBuilder (fl); - - CellConstraints cc = new CellConstraints (); - - int row = 2; - - builder.addLabel (getUIString (prefix,labels,name), - //"Their New Name", - cc.xy (2, - row)); - - builder.addLabel (info.getName (), - cc.xy (4, - row)); - - row += 2; - - builder.addLabel (getUIString (prefix,labels,avatar), - //"Their New Avatar", - cc.xy (2, - row)); - - Box b = new Box (BoxLayout.X_AXIS); - - ImagePanel avatar = new ImagePanel (UIUtils.getScaledImage (info.getAvatar (), - 100), - null); - avatar.setBorder (UIUtils.createLineBorder ()); - - b.add (avatar); - - builder.add (b, - cc.xy (4, - row)); - - JPanel p = builder.getPanel (); - p.setOpaque (false); - p.setAlignmentX (JComponent.LEFT_ALIGNMENT); - - content.add (p); - - Map buttons = new LinkedHashMap (); - - buttons.put (getUIString (prefix,LanguageStrings.buttons,accept), - //"Update", - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - try - { - - BufferedImage avIm = UIUtils.getScaledImage (info.getAvatar (), - 300); - - ed.setMyAvatarForEditor (avIm); - ed.setMyNameForEditor (info.getName ()); - ed.setAvatar (avIm); - ed.setName (info.getName ()); - - EditorsEnvironment.updateEditor (ed); - - info.setDealtWith (true); - - EditorsEnvironment.updateMessage (info); - - } catch (Exception e) { - - // We reget the viewer here since there is no guarantee that the old one is still - // valid. - AbstractViewer viewer = Environment.getFocusedViewer (); - - Environment.logError ("Unable to update editor: " + - ed + - " with information: " + - info, - e); - - UIUtils.showErrorMessage (viewer, - getUIString (editors,editor,edit,actionerror)); - //"Unable to update {editor} information, please contact Quoll Writer support for assistance."); - - } - - } - - }); - - buttons.put (getUIString (prefix,LanguageStrings.buttons,reject), - //"Reject", - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - try - { - - info.setDealtWith (true); - - EditorsEnvironment.updateMessage (info); - - } catch (Exception e) { - - // We reget the viewer here since there is no guarantee that the old one is still - // valid. - AbstractViewer viewer = Environment.getFocusedViewer (); - - Environment.logError ("Unable to save editor info message for editor: " + - ed + - " with information: " + - info, - e); - - UIUtils.showErrorMessage (viewer, - getUIString (editors,editor,edit,actionerror)); - //"Unable to update {editor} information, please contact Quoll Writer support for assistance."); - - } - - } - - }); - - buttons.put (getUIString (prefix,LanguageStrings.buttons,cancel), - //"I'll decide later", - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - } - - }); - - UIUtils.createQuestionPopup (viewer, - getUIString (prefix,title), - //"{An editor} has updated their information", - "edit", - content, - buttons, - null, - null); - - } - - }); - - } -*/ - public static JComponent createSendProjectPanel (final AbstractProjectViewer viewer, - final EditorEditor ed, - final ActionListener onSend) - { - - // See what the last send/update message was, if any. - try - { - - EditorsEnvironment.loadMessagesForEditor (ed); - - } catch (Exception e) { - - Environment.logError ("Unable to load messages for editor: " + - ed, - e); - - UIUtils.showErrorMessage (viewer, - getUIString (editors,user,sendorupdateproject,actionerror)); - //"Unable to show send {project} window, please contact Quoll Writer support for assistance."); - - return null; - - } - - Project p = viewer.getProject (); - - String updateText = ""; - - SortedSet messages = ed.getMessages (p.getId (), - NewProjectMessage.MESSAGE_TYPE, - UpdateProjectMessage.MESSAGE_TYPE); - - SortedSet projRes = ed.getMessages (p.getId (), - NewProjectResponseMessage.MESSAGE_TYPE); - - boolean update = false; - - Set chapterIds = new HashSet (); - - if ((messages != null) - && - (messages.size () > 0) - ) - { - - java.util.List prefix2 = Arrays.asList (editors,user,updateproject,popup,labels); - - // Get the last one. - EditorMessage last = messages.last (); - - update = (projRes.size () > 0); - - AbstractProjectMessage pm = (AbstractProjectMessage) last; - - Set chaps = pm.getChapters (); - String verName = pm.getProjectVersion ().getName (); - - if (last instanceof NewProjectMessage) - { - - if (verName != null) - { - - updateText = String.format (getUIString (prefix2,firstupdatewithversion), - verName, - Environment.formatDate (last.getWhen ())); - //"You sent version %s of the {project} on %s."; - - } else { - - updateText = String.format (getUIString (prefix2,firstupdate), - Environment.formatDate (last.getWhen ())); - //)"You sent the {project} on %s."; - - } - - // TODO: Add link to view what was sent. - - } - - if (last instanceof UpdateProjectMessage) - { - - if (verName != null) - { - - updateText = String.format (getUIString (prefix2,lastupdatewithversion), - verName, - Environment.formatDate (last.getWhen ())); - //"You last sent version %s of the {project} on %s."; - - } else { - - updateText = String.format (getUIString (prefix2,lastupdate), - Environment.formatDate (last.getWhen ())); - //"You last sent the {project} on %s."; - - } - - } - - updateText = "

    " + updateText + getUIString (prefix2,updatesuffix); - //" The {chapters} you previously sent have been pre-selected."; - - for (Chapter c : chaps) - { - - chapterIds.add (c.getId ()); - - } - - } else { - - // Add all chapters, first send. - Book b = (Book) p.getBooks ().get (0); - - List chaps = b.getChapters (); - - for (Chapter c : chaps) - { - - chapterIds.add (c.getId ()); - - } - - } - - // Check to see if we should be sending the project as new. - if (update) - { - - messages = ed.getMessages (p.getId (), - ProjectEditStopMessage.MESSAGE_TYPE); - - if ((messages != null) - && - (messages.size () > 0) - ) - { - - // Send a new project. Even though the editor has stopped editing this project - // in the past. - update = false; - - } - - } - - java.util.List prefix = Arrays.asList (editors,user,sendorupdateproject,popup); - - final boolean fupdate = update; - - final Box content = new Box (BoxLayout.Y_AXIS); - - JTextPane desc = UIUtils.createHelpTextPane (String.format (getUIString (prefix,text), - ed.getMainName (), - //"Select the {chapters} you wish to send to " + ed.getMainName () + ". You can also select a date indicating when you would like the editing to be completed, remember to be reasonable, {editors} have lives too!

    It is recommended that you provide a Version such as 1st Draft or Final edit so that when you get comments back you know what they relate to.%s", - updateText), - viewer); - desc.setBorder (null); - - content.add (desc); - - final JLabel error = UIUtils.createErrorLabel (""); - error.setBorder (UIUtils.createPadding (10, 10, 0, 10)); - error.setVisible (false); - - content.add (error); - - JLabel sending = UIUtils.createLoadingLabel (getUIString (prefix,loading)); - //"Sending {project}..."); - sending.setBorder (UIUtils.createPadding (10, 10, 0, 10)); - - content.add (sending); - - final JTextField version = new JTextField (); - - final TextArea notes = new TextArea (String.format (getUIString (prefix,labels,LanguageStrings.notes,tooltip), - //"Tell %s about your {project}/book/story here. Also add instructions/hints on what you are wanting them to do, what to look at specifically and so on.", - ed.getMainName ()), - 5, - 5000); - notes.setAutoGrabFocus (false); - - Calendar cal = new GregorianCalendar (); - cal.add (Calendar.DATE, - 7); - - final JDateChooser jcal = new JDateChooser (cal.getTime ()); - - jcal.setMinSelectableDate (new Date ()); - jcal.getCalendarButton ().setMargin (new java.awt.Insets (3, 3, 3, 3)); - jcal.setIcon (Environment.getIcon ("date", - 16)); - - JTree tree = UIUtils.createSelectableTree (); - - final DefaultMutableTreeNode root = UIUtils.createTreeNode (p, - null, - null, - true); - - Book b = (Book) p.getBooks ().get (0); - - // Get the chapters. - List chaps = b.getChapters (); - - for (Chapter c : chaps) - { - - DefaultMutableTreeNode node = UIUtils.createTreeNode (c, - null, - null, - true); - - SelectableDataObject s = (SelectableDataObject) node.getUserObject (); - - s.selected = chapterIds.contains (c.getId ()); - - if (node == null) - { - - continue; - - } - - root.add (node); - - } - - tree.setModel (new DefaultTreeModel (root)); - - UIUtils.expandAllNodesWithChildren (tree); - - JComponent t = tree; - - if (tree.getPreferredSize ().height > 150) - { - - JScrollPane sp = UIUtils.createScrollPane (tree, - 150); - sp.setOpaque (false); - - t = sp; - - } - - Set items = new LinkedHashSet (); - - items.add (new AnyFormItem (getUIString (prefix,labels,project), - //"{Project}", - new JLabel (p.getName ()))); - - items.add (new AnyFormItem (getUIString (prefix,labels,LanguageStrings.version), - //"Version", - version)); - - items.add (new AnyFormItem (getUIString (prefix,labels,LanguageStrings.notes,text), - //"Notes", - notes)); - - items.add (new AnyFormItem (getUIString (prefix,labels,dueby), - //"Due by", - jcal)); - - items.add (new AnyFormItem (getUIString (prefix,labels,chapters), - //"{Chapters}", - t)); - - final JButton send = UIUtils.createButton (getUIString (prefix,LanguageStrings.buttons,LanguageStrings.send)); - //"Send"); - - ActionListener sendAction = new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - Set chapters = new LinkedHashSet (); - - UIUtils.getSelectedObjects (root, - chapters); - - String err = null; - - if (chapters.size () == 0) - { - - // Show the error. - err = getUIString (editors,user,sendorupdateproject,popup,errors,nochapters); - //"Please select at least 1 {chapter}."; - - } - - for (Chapter c : chapters) - { - - AbstractEditorPanel qp = viewer.getEditorForChapter (c); - - if (qp != null) - { - - if (qp.hasUnsavedChanges ()) - { - - err = getUIString (editors,user,sendorupdateproject,popup,errors,unsavedchanges); - //"One of the selected {chapters} has unsaved changes, please save your work before sending the {project}."; - - break; - - } - - } - - } - - if (notes.getText ().trim ().length () > 5000) - { - - err = getUIString (editors,user,sendorupdateproject,popup,errors,maxchars); - //"Notes can be a maximum of 5000 characters."; - - } - - if (err != null) - { - - error.setText (err); - error.setVisible (true); - - UIUtils.doLater (new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - UIUtils.resizeParent (content); - - } - - }); - - UIUtils.resizeParent (content); - - return; - - } - - send.setEnabled (false); - error.setVisible (false); - - // Show the sending. - sending.setVisible (true); - - UIUtils.resizeParent (content); - - String n = null; - - if (!notes.getForeground ().equals (UIUtils.getHintTextColor ())) - { - - n = notes.getText ().trim (); - - } - - if (n.length () == 0) - { - - n = null; - - } - - String verName = version.getText ().trim (); - - if (verName.length () == 0) - { - - verName = null; - - } - - ProjectVersion pv = new ProjectVersion (); - pv.setName (verName); - pv.setDueDate (jcal.getDate ()); - pv.setDescription (new StringWithMarkup (n)); - - // Need to snapshot the chapters. - Set nchapters = null; - - try - { - - nchapters = viewer.snapshotChapters (chapters, - pv); - - } catch (Exception e) { - - Environment.logError ("Unable to snapshot chapters: " + - chapters, - e); - - UIUtils.showErrorMessage (viewer, - getUIString (editors,user,sendorupdateproject,actionerror)); - //"Unable to send new project to {editor}, please contact Quoll Writer support for assistance."); - - return; - - } - - EditorMessage mess = null; - - if (fupdate) - { - - mess = new UpdateProjectMessage (viewer.getProject (), - nchapters, - pv, - ed); - - } else { - - mess = new NewProjectMessage (viewer.getProject (), - nchapters, - pv, - ed, - ed.getEditorStatus () == EditorEditor.EditorStatus.pending ? EditorsEnvironment.getUserAccount () : null); - - } - - // Since we are sending the message we have dealt with it. - mess.setDealtWith (true); - - EditorsEnvironment.sendMessageToEditor (mess, - // On send. - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - // See if we already have the project editor, this can happen if we have previously - // sent the project but they deleted it and we are re-sending. - ProjectEditor pe = null; - - try - { - - pe = EditorsEnvironment.getProjectEditor (viewer.getProject (), - ed); - - } catch (Exception e) { - - Environment.logError ("Unable to get project editor for project: " + - viewer.getProject () + - " and editor: " + - ed, - e); - - // Oh bugger... - - } - - if (pe == null) - { - - pe = new ProjectEditor (viewer.getProject (), - ed); - - pe.setStatus (ProjectEditor.Status.invited); - - pe.setStatusMessage (String.format (getUIString (editors,user,sendproject,editorstatus), - //"{Project} sent: %s", - Environment.formatDate (new Date ()))); - - // Add the editor to the list of editors - // for the project. A little dangerous to do it here - // since it's not in the same transaction as the message. - // TODO: Maybe have the message have a "side-effect" or "after save" - // TODO: that will add the editor to the project in the same transaction. - try - { - - EditorsEnvironment.addProjectEditor (pe); - - viewer.getProject ().addProjectEditor (pe); - - } catch (Exception e) { - - // Goddamn it! - // Nothing worse than having to show an error and success at the same time. - Environment.logError ("Unable to add editor: " + - ed + - " to project: " + - viewer.getProject (), - e); - - UIUtils.showErrorMessage (viewer, - getUIString (editors,user,sendorupdateproject,actionerror)); - //"Unable to add {editor} " + ed.getMainName () + " to the {project}. Please contact Quoll Writer support for assistance."); - - } - - } else { - - try - { - - // Update them to be current. - pe.setCurrent (true); - pe.setEditorFrom (new Date ()); - pe.setEditorTo (null); - - pe.setStatusMessage (String.format (getUIString (editors,user,updateproject,editorstatus), - //"{Project} updated: %s", - Environment.formatDate (new Date ()))); - - EditorsEnvironment.updateProjectEditor (pe); - - } catch (Exception e) { - - // Goddamn it! - // Nothing worse than having to show an error and success at the same time. - Environment.logError ("Unable to add editor: " + - ed + - " to project: " + - viewer.getProject (), - e); - - UIUtils.showErrorMessage (viewer, - getUIString (editors,user,sendorupdateproject,actionerror)); - //"Unable to add {editor} " + ed.getMainName () + " to the {project}. Please contact Quoll Writer support for assistance."); - - } - - } - - UIUtils.showMessage ((PopupsSupported) viewer, - getUIString (editors,user,sendorupdateproject,confirmpopup,title), - //"Your {project} has been sent", - String.format (getUIString (editors,user,sendorupdateproject,confirmpopup,text), - //"Your {project} %s has been sent to %s", - viewer.getProject ().getName (), - ed.getMainName ())); - - UIUtils.closePopupParent (content); - - } - - }, - // On cancel of login. - null, - null); - - } - - }; - - send.addActionListener (sendAction); - UIUtils.addDoActionOnReturnPressed (version, - sendAction); - UIUtils.addDoActionOnReturnPressed (notes, - sendAction); - - JButton cancel = UIUtils.createButton (getUIString (prefix,LanguageStrings.buttons,LanguageStrings.cancel), - //Environment.getButtonLabel (Constants.CANCEL_BUTTON_LABEL_ID), - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - // Check to see if we are sending to a pending editor. - if (ed.isPending ()) - { - - InviteMessage invite = new InviteMessage (EditorsEnvironment.getUserAccount ()); - - invite.setEditor (ed); - - // Send an invite. - EditorsEnvironment.sendMessageToEditor (invite, - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - AbstractViewer viewer = Environment.getFocusedViewer (); - - UIUtils.showMessage ((PopupsSupported) viewer, - getUIString (editors,user,invitesent,popup,title), - //"Invite sent", - String.format (getUIString (editors,user,invitesent,popup,text), - //"An invite has been sent to: %s.", - ed.getEmail ())); - - } - - }, - null, - null); - - } - - UIUtils.closePopupParent (content); - - } - - }); - - Set buttons = new LinkedHashSet (); - - buttons.add (send); - buttons.add (cancel); - - Form f = UIUtils.createForm (items, - buttons); - - f.setBorder (UIUtils.createPadding (10, 0, 0, 0)); - content.add (f); - - content.addAncestorListener (new AncestorListener () - { - - @Override - public void ancestorAdded (AncestorEvent ev) - { - - if (version.isShowing ()) - { - - version.grabFocus (); - - } - - } - - @Override - public void ancestorMoved (AncestorEvent ev) - { - - } - - @Override - public void ancestorRemoved (AncestorEvent ev) - { - - } - - }); - - return content; - - } - - public static void showSendProject (final AbstractProjectViewer viewer, - final EditorEditor ed, - final ActionListener onSend) - { - - java.util.List prefix = Arrays.asList (editors,user,sendproject,popup); - - final QPopup popup = UIUtils.createClosablePopup (getUIString (prefix,title), - //"Send {project}", - Environment.getIcon (Constants.SEND_ICON_NAME, - Constants.ICON_POPUP), - null); - - if (ed.isPending ()) - { - - // If the editor is not pending then we make the popup non-closable since we have to send a message and - // don't want it being sent multiple times. - popup.getHeader ().getControls ().setVisible (false); - - } - - JComponent content = EditorsUIUtils.createSendProjectPanel (viewer, - ed, - onSend); - content.setBorder (UIUtils.createPadding (10, 10, 10, 10)); - - content.setPreferredSize (new Dimension (UIUtils.getPopupWidth (), - content.getPreferredSize ().height + 20)); - - popup.setContent (content); - - viewer.showPopupAt (popup, - UIUtils.getCenterShowPosition (viewer, - popup), - false); - - popup.resize (); - - popup.setDraggable (viewer); - - UIUtils.doLater (new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - popup.resize (); - - } - - }); - - } - - public static void showUpdateProject (final AbstractProjectViewer viewer, - final EditorEditor ed, - final ActionListener onSend) - { - - if (ed.isPending ()) - { - - throw new IllegalStateException ("Can only update a project for a non-pending editor."); - - } - - final QPopup popup = UIUtils.createClosablePopup (getUIString (editors,user,updateproject,LanguageStrings.popup,title), - //"Update {project}", - Environment.getIcon (Constants.SEND_ICON_NAME, - Constants.ICON_POPUP), - null); - - JComponent content = EditorsUIUtils.createSendProjectPanel (viewer, - ed, - onSend); - content.setBorder (UIUtils.createPadding (10, 10, 10, 10)); - - content.setPreferredSize (new Dimension (UIUtils.getPopupWidth (), - content.getPreferredSize ().height + 20)); - - popup.setContent (content); - - viewer.showPopupAt (popup, - UIUtils.getCenterShowPosition (viewer, - popup), - false); - popup.setDraggable (viewer); - - UIUtils.doLater (new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - popup.resize (); - - } - - }); - - } - -/* -Not used. - public static void showNewProjectResponseNotification (final NewProjectResponseMessage mess) - { - - UIUtils.doLater (new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - ProjectInfo proj = null; - - try - { - - proj = Environment.getProjectById (mess.getForProjectId (), - Project.NORMAL_PROJECT_TYPE); - - } catch (Exception e) { - - Environment.logError ("Unable to get project by id: " + - mess.getForProjectId (), - e); - - return; - - } - - if (proj == null) - { - - // Should probably send an error message back. - EditorsEnvironment.sendError (mess, - ErrorMessage.ErrorType.projectnotexists, - "Unknown project : " + - mess.getForProjectId ()); - - Environment.logError ("Unable to find project by id: " + - mess.getForProjectId () + - ", project doesn't exist."); - - return; - - } - - final EditorEditor ed = mess.getEditor (); - - String title = "Editing your {project}"; - - final boolean accepted = mess.isAccepted (); - - String acceptedText = (accepted ? "accepted" : "rejected"); - - Box content = new Box (BoxLayout.Y_AXIS); - - final AbstractViewer viewer = Environment.getFocusedViewer (); - - JTextPane desc = UIUtils.createHelpTextPane (String.format ("%s has %s your offer to edit your {project} %s.", - ed.getMainName (), - acceptedText, - proj.getName ()), - viewer); - - content.add (desc); - desc.setBorder (null); - desc.setSize (new Dimension (UIUtils.getPopupWidth () - 20, - desc.getPreferredSize ().height)); - - content.add (Box.createVerticalStrut (10)); - - if (mess.getResponseMessage () != null) - { - - content.add (UIUtils.createBoldSubHeader ("Response from " + ed.getMainName (), - null)); - - JTextPane res = UIUtils.createHelpTextPane (mess.getResponseMessage (), - viewer); - - content.add (res); - res.setBorder (new EmptyBorder (5, 5, 0, 5)); - res.setSize (new Dimension (UIUtils.getPopupWidth () - 20, - res.getPreferredSize ().height)); - - content.add (Box.createVerticalStrut (10)); - - } - - final ProjectInfo fproj = proj; - - UIUtils.showMessage ((PopupsSupported) viewer, - title, - content, - Environment.getButtonLabel (Constants.CONFIRM_BUTTON_LABEL_ID), - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - mess.setDealtWith (true); - - try - { - - EditorsEnvironment.updateMessage (mess); - - } catch (Exception e) { - - Environment.logError ("Unable to update message: " + - mess, - e); - - } - - if (ed.isPending ()) - { - - ed.setEditorStatus ((accepted ? EditorEditor.EditorStatus.current : EditorEditor.EditorStatus.rejected)); - - try - { - - EditorsEnvironment.updateEditor (ed); - - } catch (Exception e) { - - Environment.logError ("Unable to update editor: " + - ed, - e); - - } - - } - - // Remove them as a project editor. - ProjectEditor pe = null; - - try - { - - pe = EditorsEnvironment.getProjectEditor (fproj, - ed); - - if (pe != null) - { - - if (!accepted) - { - - try - { - - EditorsEnvironment.removeProjectEditor (pe); - - } catch (Exception e) { - - Environment.logError ("Unable to remove project editor: " + - pe, - e); - - } - - } else { - - try - { - - pe.setStatus (ProjectEditor.Status.accepted); - - } catch (Exception e) { - - Environment.logError ("Unable to accept project editor: " + - pe, - e); - - } - - } - - } - - } catch (Exception e) { - - Environment.logError ("Unable to get project editor for project: " + - fproj + - ", and editor: " + - ed, - e); - - } - - } - - }); - - } - - }); - - } -*/ - - public static void showSendUnsentComments (final AbstractProjectViewer viewer, - final ActionListener onSend) - { - - UIUtils.doLater (new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - java.util.List prefix = Arrays.asList (editors,user,sendunsentcomments,popup); - - final EditorEditor ed = viewer.getProject ().getForEditor (); - - final QPopup popup = UIUtils.createClosablePopup (getUIString (prefix,title), - //"Send {comments} to {editor}", - Environment.getIcon (Constants.SEND_ICON_NAME, - Constants.ICON_POPUP), - null); - - Box content = new Box (BoxLayout.Y_AXIS); - - JTextPane desc = UIUtils.createHelpTextPane (String.format (getUIString (prefix,text), - //"Select the {comments} you wish to send to %s below.", - ed.getMainName ()), - viewer); - - content.add (desc); - desc.setBorder (null); - desc.setSize (new Dimension (UIUtils.getPopupWidth () - 20, - desc.getPreferredSize ().height)); - - final JLabel error = UIUtils.createErrorLabel (getUIString (prefix,errors,novalue)); - //"Please select at least 1 {comment}."); - error.setBorder (UIUtils.createPadding (10, 0, 0, 0)); - error.setVisible (false); - content.add (error); - - JLabel sending = UIUtils.createLoadingLabel (getUIString (prefix,loading)); - //"Sending {comments}..."); - sending.setBorder (UIUtils.createPadding (10, 0, 0, 0)); - sending.setVisible (false); - - final TextArea genComments = new TextArea (getUIString (prefix,labels,notes,tooltip), - //"Optionally, you can provide some general thoughts/comments about the {project} here.", - 5, - 5000); - - Set exclude = new HashSet (); - Set init = new HashSet (); - - Set notes = viewer.getProject ().getAllNamedChildObjects (Note.class); - - for (NamedObject d : notes) - { - - if (!(d instanceof Note)) - { - - Environment.logError ("Found an object of type: " + - d.getClass ().getName () + - " when looking for: " + - Note.class.getName ()); - - continue; - - } - - Note n = (Note) d; - - if (n.isDealtWith ()) - { - - exclude.add (n); - - } else { - - init.add (n); - - // Also add the chapter. - init.add (n.getChapter ()); - - } - - } - - Set chaps = viewer.getProject ().getAllNamedChildObjects (Chapter.class); - - for (NamedObject d : chaps) - { - - if (init.contains (d)) - { - - continue; - - } - - exclude.add (d); - - } - - JTree tree = UIUtils.createSelectableTree (); - - SelectableProjectTreeCellRenderer cr = (SelectableProjectTreeCellRenderer) tree.getCellRenderer (); - - cr.setIconType (Note.OBJECT_TYPE, - Constants.COMMENT_ICON_NAME); - - final DefaultMutableTreeNode root = EditorsUIUtils.createTree (viewer.getProject (), - exclude, - init, - true); - - ((DefaultTreeModel) tree.getModel ()).setRoot (root); - - for (Object o : init) - { - - tree.expandPath (UIUtils.getTreePathForUserObject (root, - o)); - - } - - JScrollPane sp = UIUtils.createScrollPane (tree, - 400); - - Set items = new LinkedHashSet (); - - items.add (new AnyFormItem (getUIString (prefix,labels,LanguageStrings.notes,text), - //"Notes", - genComments)); - - items.add (new AnyFormItem (getUIString (prefix,labels,comments), - //"{Comments}", - sp)); - - ActionListener onShow = null; - - ActionListener sendAction = new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - // Get a count. - error.setVisible (false); - - Set selected = new LinkedHashSet (); - - UIUtils.getSelectedObjects (root, - selected); - - final Set comments = new LinkedHashSet (); - - for (NamedObject n : selected) - { - - if (n instanceof Note) - { - - comments.add ((Note) n); - - } - - } - - String err = null; - - if (comments.size () == 0) - { - - error.setVisible (true); - - popup.resize (); - - return; - - } - - String gc = genComments.getText ().trim (); - - if (gc.length () == 0) - { - - gc = null; - - } - - ProjectCommentsMessage mess = new ProjectCommentsMessage (viewer.getProject (), - gc, - comments, - viewer.getProject ().getProjectVersion (), - ed); - - // Since we are sending the message we have dealt with it. - mess.setDealtWith (true); - - // Do this here because we don't know how long it will take to actually send. - final Date sentDate = new Date (); - - EditorsEnvironment.sendMessageToEditor (mess, - // On send. - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - // Update the comments to be dealt with. - for (Note n : comments) - { - - n.setDealtWith (sentDate); - - } - - try - { - - // Should really change the underlying method - // but can't be bothered at the moment! - // TODO - viewer.saveObjects (new ArrayList (comments), - true); - - } catch (Exception e) { - - Environment.logError ("Unable to update comments", - e); - - UIUtils.showErrorMessage (viewer, - getUIString (editors,user,sendunsentcomments,actionerror)); - //"Your comments have been sent but Quoll Writer is unable to update the comments in your local db, please contact Quoll Writer support for assistance."); - - return; - - } - - // Fire an event for each note. - for (Note n : comments) - { - - viewer.fireProjectEvent (n.getObjectType (), - ProjectEvent.EDIT, - n); - - } - - UIUtils.showMessage ((PopupsSupported) viewer, - getUIString (editors,user,sendunsentcomments,confirmpopup,title), - String.format (getUIString (editors,user,sendunsentcomments,confirmpopup,text), - ed.getMainName ())); - - popup.removeFromParent (); - - if (onSend != null) - { - - onSend.actionPerformed (new ActionEvent ("sent", 1, "sent")); - - } - - } - - }, - // On cancel of login. - null, - null); - - - sending.setVisible (true); - - popup.resize (); - - } - - }; - - final JButton send = UIUtils.createButton (getUIString (prefix,buttons,LanguageStrings.send), - //"Send", - sendAction); - - UIUtils.addDoActionOnReturnPressed (genComments, - sendAction); - - final JButton cancel = UIUtils.createButton (getUIString (prefix,buttons,LanguageStrings.cancel), - //"Cancel", - popup.getCloseAction ()); - - Set buttons = new LinkedHashSet (); - buttons.add (send); - buttons.add (cancel); - - Form f = UIUtils.createForm (items, - buttons); - - f.setBorder (UIUtils.createPadding (10, 0, 0, 0)); - - content.add (f); - - //content.add (buttons); - content.setBorder (UIUtils.createPadding (10, 10, 10, 10)); - - content.setPreferredSize (new Dimension (UIUtils.getPopupWidth (), - content.getPreferredSize ().height)); - - popup.setContent (content); - - viewer.showPopupAt (popup, - UIUtils.getCenterShowPosition (viewer, - popup), - false); - popup.setDraggable (viewer); - - } - - }); - - } - -/* -Not used. - public static void showNewProjectReceived (final NewProjectMessage mess) - { - - UIUtils.doLater (new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - final EditorEditor ed = mess.getEditor (); - - Box content = new Box (BoxLayout.Y_AXIS); - - final AbstractViewer viewer = Environment.getFocusedViewer (); - - JTextPane desc = UIUtils.createHelpTextPane (String.format ("%s has sent you the following {project} to edit. Please respond below.", - mess.getEditor ().getMainName ()), - viewer); - - content.add (desc); - desc.setBorder (null); - desc.setSize (new Dimension (UIUtils.getPopupWidth () - 20, - desc.getPreferredSize ().height)); - - content.add (Box.createVerticalStrut (10)); - - String rows = "p, 6px, top:p, 6px, p, 6px, p"; - String cols = "right:p, 6px, fill:200px:grow"; - - FormLayout fl = new FormLayout (cols, - rows); - PanelBuilder b = new PanelBuilder (fl); - - Project _proj = null; - - try - { - - _proj = mess.createProject (); - - } catch (Exception e) { - - Environment.logError ("Unable to create project from message: " + - mess, - e); - - UIUtils.showErrorMessage (viewer, - "Unable to send {project}, please contact Quoll Writer support for assistance."); - - return; - - } - - final Project proj = _proj; - - ProjectVersion projVer = proj.getProjectVersion (); - - CellConstraints cc = new CellConstraints (); - - int row = 1; - - b.addLabel (EditorsUIUtils.createFormLabel ("{Project}"), - cc.xy (1, row)); - - b.addLabel (proj.getName (), - cc.xy (3, row)); - - row += 2; - - b.addLabel (Environment.formatNumber (proj.getWordCount ()) + " words, " + Environment.replaceObjectNames (proj.getBook (0).getChapters ().size () + " {chapters}"), - cc.xy (3, row)); - - row += 2; - - b.addLabel (EditorsUIUtils.createFormLabel ("Due by"), - cc.xy (1, row)); - - b.addLabel ((projVer.getDueDate () != null ? Environment.formatDate (projVer.getDueDate ()) : "Not specified."), - cc.xy (3, row)); - - row += 2; - - b.addLabel (EditorsUIUtils.createFormLabel ("Notes"), - cc.xy (1, row)); - - ActionListener onShow = null; - - JComponent notes = null; - - StringWithMarkup verNotes = projVer.getDescription (); - - if (verNotes != null) - { - - JComponent t = UIUtils.createHelpTextPane (verNotes, - viewer); - - t.setBorder (null); - t.setOpaque (false); - - if (t.getPreferredSize ().height > 100) - { - - final JScrollPane sp = UIUtils.createScrollPane (t); - - onShow = new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - sp.getVerticalScrollBar ().setValue (0); - - } - - }; - - notes = sp; - - notes.setPreferredSize (new Dimension (500, - 100)); - - } else { - - notes = t; - - } - - notes.setOpaque (false); - notes.setBorder (null); - - } else { - - notes = new JLabel ("No notes provided."); - - } - - b.add (notes, - cc.xy (3, row)); - - row += 2; - - JPanel p = b.getPanel (); - p.setOpaque (false); - p.setAlignmentX (Component.LEFT_ALIGNMENT); - p.setBorder (new EmptyBorder (0, 5, 10, 5)); - - content.add (p); - - Map buttons = new LinkedHashMap (); - - buttons.put ("Yes, I'll edit the {project}", - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - //final String fromEmail = mess.getEditor ().getEmail (); - - // We may not have the editor here, this could be the first message from them. - // If not then we accept the invite first. - //EditorEditor ed = EditorsEnvironment.getEditorByEmail (fromEmail); - - if (ed.isPending ()) - { - - // Accepts, so update and then process the message. - EditorsEnvironment.updateInvite (ed.getEmail (), - Invite.Status.accepted, - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - ed.setName (mess.getEditorName ()); - ed.setAvatar (mess.getEditorAvatar ()); - - try - { - - EditorsEnvironment.updateEditor (ed); - - } catch (Exception e) { - - Environment.logError ("Unable to update editor: " + - ed, - e); - - return; - - } - - EditorsEnvironment.getMessageHandler ().subscribeToEditor (ed); - - try - { - - EditorsEnvironment.addMessage (mess); - - } catch (Exception e) { - - Environment.logError ("Unable to save message for editor: " + - ed, - e); - - return; - - } - - EditorsUIUtils.handleNewProjectResponse (null, - mess, - true); - - } - - }); - - return; - - } else { - - try - { - - EditorsEnvironment.addMessage (mess); - - } catch (Exception e) { - - UIUtils.showErrorMessage (null, - "Unable to save message from {editor}, please contact Quoll Writer support for assistance."); - - Environment.logError ("Unable to save message for editor: " + - ed, - e); - - return; - - } - - EditorsUIUtils.handleNewProjectResponse (null, - mess, - true); - - } - - } - - }); - - buttons.put ("No thanks", - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - if (ed.isPending ()) - { - - // Accepts, so update and then process the message. - EditorsEnvironment.updateInvite (ed.getEmail (), - Invite.Status.rejected, - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - EditorsUIUtils.handleNewProjectResponse (null, - mess, - false); - - } - - }); - - } else { - - try - { - - EditorsEnvironment.addMessage (mess); - - } catch (Exception e) { - - UIUtils.showErrorMessage (null, - "Unable to save message from {editor}, please contact Quoll Writer support for assistance."); - - Environment.logError ("Unable to save message for editor: " + - ed, - e); - - return; - - } - - EditorsUIUtils.handleNewProjectResponse (null, - mess, - false); - - } - - } - - }); - - buttons.put ("I'll decide later", - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - try - { - - EditorsEnvironment.addMessage (mess); - - } catch (Exception e) { - - UIUtils.showErrorMessage (null, - "Unable to save message from {editor}, please contact Quoll Writer support for assistance."); - - Environment.logError ("Unable to save message for editor: " + - ed, - e); - - return; - - } - - } - - }); - - UIUtils.createQuestionPopup (viewer, - "You've been sent a {project} to edit", - "edit", - content, - buttons, - null, - null); - - if (onShow != null) - { - - // And this is why I hate you Swing... - UIUtils.doLater (onShow); - - } - - } - - }); - - } -*/ -/* - public static void showProjectUpdateReceived (final UpdateProjectMessage mess) - { - - UIUtils.doLater (new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - ProjectInfo _proj = null; - - try - { - - _proj = Environment.getProjectById (mess.getForProjectId (), - Project.EDITOR_PROJECT_TYPE); - - } catch (Exception e) { - - Environment.logError ("Unable to get project for id: " + - mess.getForProjectId (), - e); - - return; - - } - - if (_proj == null) - { - - return; - - } - - final ProjectInfo proj = _proj; - - final EditorEditor ed = mess.getEditor (); - - final Box content = new Box (BoxLayout.Y_AXIS); - - final AbstractViewer viewer = Environment.getFocusedViewer (); - - JTextPane desc = UIUtils.createHelpTextPane (String.format ("%s has sent an update for the following {project}.", - mess.getEditor ().getMainName ()), - viewer); - - content.add (desc); - desc.setBorder (null); - desc.setSize (new Dimension (UIUtils.getPopupWidth () - 20, - desc.getPreferredSize ().height)); - - content.add (Box.createVerticalStrut (10)); - - String rows = "p, 6px, top:p, 6px, p, 6px, p"; - String cols = "right:p, 6px, fill:200px:grow"; - - FormLayout fl = new FormLayout (cols, - rows); - PanelBuilder b = new PanelBuilder (fl); - - CellConstraints cc = new CellConstraints (); - - int row = 1; - - b.addLabel (EditorsUIUtils.createFormLabel ("{Project}"), - cc.xy (1, row)); - - b.addLabel (proj.getName (), - cc.xy (3, row)); - - row += 2; - - b.addLabel (Environment.replaceObjectNames (String.format ("%s words, %s {chapters}", - Environment.formatNumber (proj.getChapterCount ()), - Environment.formatNumber (proj.getWordCount ()))), - cc.xy (3, row)); - - row += 2; - - b.addLabel (EditorsUIUtils.createFormLabel ("Due by"), - cc.xy (1, row)); - - ProjectVersion projVer = mess.getProjectVersion (); - - b.addLabel ((projVer.getDueDate () != null ? Environment.formatDate (projVer.getDueDate ()) : "Not specified."), - cc.xy (3, row)); - - row += 2; - - b.addLabel (EditorsUIUtils.createFormLabel ("Notes"), - cc.xy (1, row)); - - ActionListener onShow = null; - - JComponent notes = null; - - StringWithMarkup verNotes = projVer.getDescription (); - - if (verNotes != null) - { - - JComponent t = UIUtils.createHelpTextPane (verNotes, - viewer); - - t.setBorder (null); - t.setOpaque (false); - - if (t.getPreferredSize ().height > 100) - { - - final JScrollPane sp = UIUtils.createScrollPane (t); - - onShow = new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - sp.getVerticalScrollBar ().setValue (0); - - } - - }; - - notes = sp; - - notes.setPreferredSize (new Dimension (500, - 100)); - - } else { - - notes = t; - - } - - notes.setOpaque (false); - notes.setBorder (null); - - } else { - - notes = new JLabel ("No notes provided."); - - } - - b.add (notes, - cc.xy (3, row)); - - row += 2; - - JPanel p = b.getPanel (); - p.setOpaque (false); - p.setAlignmentX (Component.LEFT_ALIGNMENT); - p.setBorder (new EmptyBorder (0, 5, 10, 5)); - - content.add (p); - - Map buttons = new LinkedHashMap (); - - buttons.put ("View the update", - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - EditorsUIUtils.showProjectUpdate (mess, - viewer, - null); - - } - - }); - - buttons.put ("I'll check the update later", - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - } - - }); - - UIUtils.createQuestionPopup (viewer, - "A {project} you're editing has been updated", - "edit", - content, - buttons, - null, - null); - - if (onShow != null) - { - - // And this is why I hate you Swing... - UIUtils.doLater (onShow); - - } - - } - - }); - - } -*/ -/* - public static void showInviteAcceptance (final EditorEditor ed) - { - - UIUtils.doLater (new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - AbstractViewer viewer = Environment.getFocusedViewer (); - - Box content = new Box (BoxLayout.Y_AXIS); - - String title = "Invitation accepted"; - String message = "Your invite to " + ed.getMainName () + " to become {an editor} has been accepted. You can now send messages and/or your {project}(s) to them."; - - JTextPane desc = UIUtils.createHelpTextPane (message, - viewer); - desc.setBorder (null); - desc.setSize (new Dimension (UIUtils.getPopupWidth () - 20, - desc.getPreferredSize ().height)); - - content.add (desc); - content.add (Box.createVerticalStrut (10)); - - UIUtils.showMessage (viewer, - title, - content, - Environment.getButtonLabel (Constants.CONFIRM_BUTTON_LABEL_ID), - null); - - } - - }); - - } -*/ -/* - public static void showInviteRejection (final EditorEditor ed) - { - - UIUtils.doLater (new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - AbstractViewer viewer = Environment.getFocusedViewer (); - - Box content = new Box (BoxLayout.Y_AXIS); - - String title = "Invitation rejected"; - String message = "Your invitation to " + ed.getMainName () + " has been rejected."; - - JTextPane desc = UIUtils.createHelpTextPane (message, - viewer); - desc.setBorder (null); - desc.setSize (new Dimension (UIUtils.getPopupWidth () - 20, - desc.getPreferredSize ().height)); - - content.add (desc); - content.add (Box.createVerticalStrut (10)); - - UIUtils.showMessage (viewer, - title, - content, - Environment.getButtonLabel (Constants.CONFIRM_BUTTON_LABEL_ID), - null); - - } - - }); - - } -*/ -/* - public static void showAcceptance (final EditorEditor ed) - { - - UIUtils.doLater (new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - AbstractViewer viewer = Environment.getFocusedViewer (); - - if (viewer == null) - { - - return; - - } - - Box content = new Box (BoxLayout.Y_AXIS); - - String text = "" + ed.getMainName () + " has accepted your invitation. You can now send messages and/or your project(s) to them."; - - if (!ed.isInvitedByMe ()) - { - - text = "Your acceptance of the invitation from " + ed.getMainName () + " has been acknowledged. You can now send messages and/or your project(s) to them."; - - } - - UIUtils.showMessage ((PopupsSupported) viewer, - "Your invites", - text, - Environment.getButtonLabel (Constants.CONFIRM_BUTTON_LABEL_ID), - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - EditorsEnvironment.fireEditorChangedEvent (ed, - EditorChangedEvent.EDITOR_CHANGED); - - } - - }); - - } - - }); - - } -*/ - public static void showReportMessage (final MessageBox mess, - final AbstractViewer viewer) - { - - URL url = null; - - try - { - - url = EditorsEnvironment.getReportMessageURL (); - - } catch (Exception e) { - - Environment.logError ("Unable to get report message url", - e); - - UIUtils.showErrorMessage (viewer, - getUIString (editors,user,reportmessage,actionerror)); - //"Unable to show report message popup, please contact Quoll Writer support for assistance."); - - return; - - } - - final URL reportURL = url; - - final java.util.List prefix = Arrays.asList (editors,user,reportmessage,popup); - - final QPopup qp = UIUtils.createClosablePopup (getUIString (prefix,title), - //"Report a message", - Environment.getIcon (Constants.ERROR_ICON_NAME, - Constants.ICON_POPUP), - null); - - Box content = new Box (BoxLayout.Y_AXIS); - - JTextPane desc = UIUtils.createHelpTextPane (getUIString (prefix,text), - //"Please describe why you are reporting the message.

    Note: when reporting a message all information known about the message, such as the text received by you, will be sent to the Quoll Writer server.

    Warning: falsely reporting messages can lead to you being banned from the Editors Service.

    ", - viewer); - - content.add (desc); - desc.setBorder (null); - desc.setSize (new Dimension (UIUtils.getPopupWidth () - 20, - desc.getPreferredSize ().height)); - - content.add (Box.createVerticalStrut (10)); - - content.add (UIUtils.createBoldSubHeader (getUIString (prefix,sectiontitles,message), - //"Message you are reporting", - null)); - - BufferedImage im = null; - - try - { - - mess.setOpaque (true); - mess.setBackground (UIUtils.getComponentColor ()); - - im = UIUtils.getImageOfComponent (mess, - UIUtils.getPopupWidth () - 40, - 0); - - mess.setOpaque (false); - - } catch (Exception e) { - - Environment.logError ("Unable to create message box for: " + - mess, - e); - - UIUtils.showErrorMessage (viewer, - getUIString (editors,user,reportmessage,actionerror)); - //"Unable to show report message popup, please contact Quoll Writer support for assistance."); - - return; - - } - - JLabel imL = new JLabel (new ImageIcon (im)); - - imL.setBorder (new CompoundBorder (UIUtils.createPadding (5, 5, 0, 5), - new CompoundBorder (new LineBorder (UIUtils.getInnerBorderColor (), - 1),//UIUtils.createLineBorder (), - UIUtils.createPadding (5, 5, 5, 5)))); - - content.add (imL); - - content.add (Box.createVerticalStrut (10)); - - content.add (UIUtils.createBoldSubHeader (getUIString (prefix,sectiontitles,from), - //"From {Editor}", - null)); - - EditorInfoBox edB = null; - - try - { - - edB = new EditorInfoBox (mess.getMessage ().getEditor (), - viewer, - false); - - } catch (Exception e) { - - Environment.logError ("Unable to create editor box for: " + - mess.getMessage ().getEditor (), - e); - - UIUtils.showErrorMessage (viewer, - getUIString (editors,user,reportmessage,actionerror)); - //"Unable to show report message popup, please contact Quoll Writer support for assistance."); - - return; - - } - - edB.init (); - - edB.setBorder (UIUtils.createPadding (0, 5, 0, 5)); - - content.add (edB); - - content.add (Box.createVerticalStrut (10)); - - content.add (UIUtils.createBoldSubHeader (getUIString (prefix,sectiontitles,reason), - //"Reason", - null)); - - final JLabel error = UIUtils.createErrorLabel (""); - - error.setBorder (UIUtils.createPadding (5, 5, 5, 5)); - error.setVisible (false); - - content.add (error); - - final TextArea notes = new TextArea (getUIString (prefix,labels,reason,tooltip), - //"Please describe why you are reporting the message, for example does it contain inappropriate language or suggestions?"), - 4, - 5000); - - notes.setBorder (UIUtils.createPadding (0, 5, 0, 5)); - - content.add (notes); - - final JLabel sending = UIUtils.createLoadingLabel (getUIString (prefix,loading)); - //"Sending report..."); - sending.setVisible (false); - sending.setBorder (UIUtils.createPadding (10, 5, 0, 5)); - - content.add (sending); - - final JButton reportB = UIUtils.createButton (getUIString (prefix,buttons,send), - //"Report", - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - error.setVisible (false); - - notes.setAutoGrabFocus (false); - - if (notes.getText ().trim ().length () == 0) - { - - error.setText (getUIString (prefix,errors,novalue)); - //"Please provide a reason for the report."); - error.setVisible (true); - - qp.resize (); - - return; - - } - - sending.setVisible (true); - qp.resize (); - - EditorsEnvironment.goOnline (getUIString (editors,login,reasons,reportmessage), - //"To report a message you must first login.", - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - Map data = new HashMap (); - data.put ("message", - mess.getMessage ()); - data.put ("editor", - mess.getMessage ().getEditor ()); - data.put ("user", - EditorsEnvironment.getUserAccount ()); - data.put ("reason", - notes.getText ().trim ()); - - Map headers = new HashMap (); - headers.put ("Authorization", - EditorsEnvironment.getUserAccount ().getWebServiceSessionId ()); - - try - { - - Utils.postToURL (reportURL, - headers, - JSONEncoder.encode (data, - true, - ""), - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - qp.removeFromParent (); - - UIUtils.showMessage ((PopupsSupported) viewer, - getUIString (editors,user,reportmessage,confirmpopup,title), - //"Message reported", - getUIString (editors,user,reportmessage,confirmpopup,text)); - //"The message has been reported to Quoll Writer support. Please note that you may be contacted to get other information about the message, for example if you have received an inappropriate image or text in a {chapter}."); - - } - - }, - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - qp.removeFromParent (); - - Environment.logError ("Unable to report message:" + - ev); - - UIUtils.showErrorMessage (viewer, - getUIString (editors,user,reportmessage,actionerror)); - //"Unable to report the message, please contact Quoll Writer support for assistance."); - - } - - }, - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - qp.removeFromParent (); - - Environment.logError ("Unable to report message, got fail", - (Exception) ev.getSource ()); - - UIUtils.showErrorMessage (viewer, - getUIString (editors,user,reportmessage,actionerror)); - //"Unable to report the message, please contact Quoll Writer support for assistance."); - - } - - }); - - } catch (Exception e) { - - qp.removeFromParent (); - - Environment.logError ("Unable to report message", - e); - - UIUtils.showErrorMessage (viewer, - getUIString (editors,user,reportmessage,actionerror)); - //"Unable to report the message, please contact Quoll Writer support for assistance."); - - } - - } - - }, - null, - null); - - } - - }); - - final JButton cancelB = UIUtils.createButton (getUIString (prefix,buttons,cancel), - //Environment.getButtonLabel (Constants.CANCEL_BUTTON_LABEL_ID), - qp.getCloseAction ()); - - JComponent bs = UIUtils.createButtonBar2 (new JButton[] {reportB, cancelB}, - Component.LEFT_ALIGNMENT); - - bs.setBorder (UIUtils.createPadding (5, 5, 0, 5)); - - content.add (bs); - - content.setBorder (UIUtils.createPadding (10, 10, 10, 10)); - content.setPreferredSize (new Dimension (UIUtils.getPopupWidth (), - content.getPreferredSize ().height)); - - qp.setContent (content); - - qp.setDraggable (viewer); - - qp.resize (); - - viewer.showPopupAt (qp, - UIUtils.getCenterShowPosition (viewer, - qp), - false); - - } - - public static void showRegister (final AbstractViewer viewer) - throws Exception - { - - final QPopup popup = UIUtils.createWizardPopup (getUIString (editors,user,register,LanguageStrings.popup,title), - //"Register for the Editors service", - Constants.EDITORS_ICON_NAME, - null, - new EditorRegister (viewer)); - - popup.setDraggable (viewer); - - popup.resize (); - - viewer.showPopupAt (popup, - UIUtils.getCenterShowPosition (viewer, - popup), - false); - - } - - public static void hideLogin () - { - - if (EditorsUIUtils.editorLogin == null) - { - - return; - - } - - EditorsUIUtils.editorLogin.removeFromParent (); - - } - - public static void showChangePassword (final AbstractViewer viewer) - { - - java.util.List prefix = Arrays.asList (editors,user,changepassword,popup); - - final QPopup qp = UIUtils.createClosablePopup (getUIString (prefix,title), - //"Change your password", - Environment.getIcon (Constants.EDIT_ICON_NAME, - Constants.ICON_POPUP), - null); - - Box content = new Box (BoxLayout.Y_AXIS); - - JTextPane desc = UIUtils.createHelpTextPane (getUIString (prefix,text), - //"Enter your new password below.", - viewer); - - content.add (desc); - desc.setBorder (null); - desc.setSize (new Dimension (UIUtils.getPopupWidth () - 20, - desc.getPreferredSize ().height)); - - final JLabel error = UIUtils.createErrorLabel (""); - - error.setBorder (new EmptyBorder (10, 0, 0, 0)); - error.setVisible (false); - - content.add (error); - - FormLayout fl = new FormLayout ("6px, right:p, 6px, fill:200px:grow", - "10px, p, 6px, top:p, 10px, p"); - - fl.setHonorsVisibility (true); - PanelBuilder builder = new PanelBuilder (fl); - - CellConstraints cc = new CellConstraints (); - - int row = 2; - - builder.addLabel (getUIString (prefix,labels,newpassword), - //"New Password", - cc.xy (2, - row)); - - final JPasswordField pass1 = new JPasswordField (); - - builder.add (pass1, - cc.xy (4, - row)); - - row += 2; - - builder.addLabel (getUIString (prefix,labels,confirmpassword), - //"Confirm Password", - cc.xy (2, - row)); - - final JPasswordField pass2 = new JPasswordField (); - - builder.add (pass2, - cc.xy (4, - row)); - - final JButton updateB = UIUtils.createButton (getUIString (prefix,buttons,confirm), - //Environment.getButtonLabel (Constants.UPDATE_BUTTON_LABEL_ID), - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - java.util.List prefix = Arrays.asList (editors,user,changepassword,popup,errors); - - error.setVisible (false); - - // Update the user data. - String pwd = new String (pass1.getPassword ()); - - if (pwd.length () == 0) - { - - error.setText (getUIString (prefix,nopassword)); - //"Please provide a new password."); - error.setVisible (true); - - qp.resize (); - - return; - - } - - String pwd2 = new String (pass2.getPassword ()); - - if (pwd2.length () == 0) - { - - error.setText (getUIString (prefix,confirmpassword)); - //error.setText ("Please confirm your new password."); - error.setVisible (true); - - qp.resize (); - - return; - - } - - if (!pwd.equals (pwd2)) - { - - error.setText (getUIString (prefix,nomatch)); - //error.setText ("The passwords do not match."); - error.setVisible (true); - - qp.resize (); - - return; - - } - - EditorsEnvironment.updateUserPassword (pwd); - - qp.removeFromParent (); - - } - - }); - - final JButton cancelB = UIUtils.createButton (getUIString (prefix,buttons,cancel), - //Environment.getButtonLabel (Constants.CANCEL_BUTTON_LABEL_ID), - qp.getCloseAction ()); - - row += 2; - - JComponent bs = UIUtils.createButtonBar2 (new JButton[] {updateB, cancelB}, - Component.LEFT_ALIGNMENT); - - builder.add (bs, - cc.xy (4, - row)); - - JPanel p = builder.getPanel (); - p.setOpaque (false); - p.setAlignmentX (JComponent.LEFT_ALIGNMENT); - - content.add (p); - - content.setBorder (UIUtils.createPadding (10, 10, 10, 10)); - content.setPreferredSize (new Dimension (UIUtils.getPopupWidth (), - content.getPreferredSize ().height)); - - qp.setContent (content); - - viewer.showPopupAt (qp, - UIUtils.getCenterShowPosition (viewer, - qp), - false); - - qp.setDraggable (viewer); - qp.resize (); - - } - - public static void showLogin (final AbstractViewer viewer, - final String loginReason, - final ActionListener onLogin, - final ActionListener onCancel) - { - - UIUtils.doActionLater (new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - if (EditorsUIUtils.editorLogin == null) - { - - EditorsUIUtils.editorLogin = new EditorLogin (); - - } - - EditorsUIUtils.editorLogin.setLoginReason (loginReason); - EditorsUIUtils.editorLogin.setOnLogin (onLogin); - - EditorsUIUtils.editorLogin.setOnCancel (onCancel); - EditorsUIUtils.editorLogin.setOnClose (onCancel); - - EditorsUIUtils.editorLogin.show (viewer); - - } - - }); - - } - - public static void showLoginError (EditorsWebServiceResult res) - { - - String reason = ""; - //"Please contact Quoll Writer support for assistance, quoting error code: " + res.getReturnCode () + (res.getReturnCode () == 401 ? ("/" + res.getErrorType ()) : ""); - - if (res.getReturnCode () == 401) - { - - String errType = res.getErrorType (); - - if (errType != null) - { - - if (errType.equals ("InvalidCredentials")) - { - - reason = getUIString (editors,login,errors,invalidcredentials); - //"Please check your email/password and try again."; - - } - - } - - } else { - - reason = String.format (getUIString (editors,login,errors,general), - res.getReturnCode () + "/" + res.getErrorType ()); - - } - - EditorsUIUtils.showLoginError (reason); - //"Unable to login to the Editors service.
    " + reason); - - } - - public static void showLoginError (String error) - { - - EditorsUIUtils.showLoginError (error, - null, - null); - - } - - public static void showLoginError (String error, - ActionListener onLogin, - ActionListener onCancel) - { - /* - if (EditorsUIUtils.editorLogin.getParent () == null) - { - - AbstractProjectViewer viewer = Environment.getFocusedProjectViewer (); - - UIUtils.showErrorMessage (viewer, - "Unable to show login form, please contact Quoll Writer support for assistance."); - - return; - - } - */ - - AbstractViewer viewer = Environment.getFocusedViewer (); - - EditorsUIUtils.editorLogin.show (viewer); - - EditorsUIUtils.editorLogin.showError (error); - - if (onLogin != null) - { - - EditorsUIUtils.editorLogin.setOnLogin (onLogin); - - } - - if (onCancel != null) - { - - EditorsUIUtils.editorLogin.setOnCancel (onCancel); - EditorsUIUtils.editorLogin.setOnClose (onCancel); - - } - - EditorsUIUtils.editorLogin.resize (); - - } - - public static void showContacts ( Set editors, - String title, - final AbstractProjectViewer viewer, - ActionListener onSelect, - JComponent extra) - { - - UIUtils.showObjectSelectPopup (editors, - viewer, - title, - new DefaultListCellRenderer () - { - - @Override - public Component getListCellRendererComponent (JList list, - Object value, - int index, - boolean isSelected, - boolean cellHasFocus) - { - - EditorEditor obj = (EditorEditor) value; - - JLabel l = (JLabel) super.getListCellRendererComponent (list, - value, - index, - isSelected, - cellHasFocus); - - l.setText (obj.getMainName ()); - l.setFont (l.getFont ().deriveFont ((float) UIUtils.getScaledFontSize (14)).deriveFont (java.awt.Font.PLAIN)); - //l.setFont (l.getFont ().deriveFont (14f)); - - if (obj.getAvatar () != null) - { - - l.setIcon (new ImageIcon (UIUtils.getScaledImage (obj.getMainAvatar (), - 50))); - - } - - l.setBorder (UIUtils.createBottomLineWithPadding (5, 5, 5, 5)); - - if (cellHasFocus) - { - - l.setBackground (Environment.getHighlightColor ()); - - } - - return l; - - } - - }, - onSelect, - true, - extra, - null); - - } - - public static void showInviteEditor (final AbstractViewer viewer) - { - - UIUtils.doActionLater (new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - final java.util.List prefix = Arrays.asList (editors,user,inviteeditor,popup); - - UIUtils.createTextInputPopup (viewer, - getUIString (prefix,title), - //"Send an invite", //Invite {an editor}", - Constants.NEW_ICON_NAME, - getUIString (prefix,text), - //"Enter the email address of the person to invite.", - getUIString (prefix,buttons,invite), - //"Invite", - getUIString (prefix,buttons,cancel), - //null, - null, - new ValueValidator () - { - - public String isValid (String v) - { - - if ((v == null) - || - (v.trim ().equals ("")) - ) - { - - return getUIString (prefix,errors,noemail); - //"The email address must be specified."; - - } - - if (v.indexOf ("@") < 0) - { - - return getUIString (prefix,errors,invalidemail); - //"Please provide a valid email address."; - - } - - if (v.equals (EditorsEnvironment.getUserAccount ().getEmail ())) - { - - return getUIString (prefix,errors,self); - //"Inviting yourself? O_o"; - - } - - EditorEditor ed = EditorsEnvironment.getEditorByEmail (v); - - // Check to see if we already have the editor. - if (ed != null) - { - - String other = getUIString (prefix,errors,alreadyinvited); - //"You have already invited %s (%s)."; - - if (ed.getEditorStatus () == EditorEditor.EditorStatus.rejected) - { - - other = getUIString (prefix,errors,previousrejected); - //"You have already invited: %s (%s). Your invitation was rejected."; - - } - - if (ed.isPrevious ()) - { - - other = getUIString (prefix,errors,previous); - //"%s (%s) is a previous {contact}."; - - } - - return String.format (other, - ed.getShortName (), - ed.getEmail ()); - - } - - return null; - - } - - }, - new ActionListener () - { - - public void actionPerformed (final ActionEvent ev) - { - - // Send the invite. - EditorsEnvironment.sendInvite (ev.getActionCommand ()); - - } - - }, - null, - null); - - } - - }); - - } - -/* - public static void showNewEditorChatMessageNotification (final EditorChatMessage mess) - { - - UIUtils.doLater (new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - final EditorEditor ed = mess.getEditor (); - - String title = "New chat message"; - - AbstractViewer viewer = Environment.getFocusedViewer (); - - Map buttons = new LinkedHashMap (); - - buttons.put ("Reply", - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - AbstractViewer viewer = Environment.getFocusedViewer (); - - try - { - - viewer.sendMessageToEditor (ed); - - } catch (Exception e) { - - Environment.logError ("Unable to show editors side bar for editor: " + - ed, - e); - - UIUtils.showErrorMessage (viewer, - "Unable to display {editors} side bar, please contact Quoll Writer support for assistance."); - - } - - } - - }); - - buttons.put ("Close", - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - } - - }); - - Box content = new Box (BoxLayout.Y_AXIS); - - JTextPane desc = UIUtils.createHelpTextPane (String.format ("Message received from %s.", - ed.getMainName ()), - viewer); - - content.add (desc); - desc.setBorder (null); - desc.setSize (new Dimension (UIUtils.getPopupWidth () - 20, - desc.getPreferredSize ().height)); - - content.add (Box.createVerticalStrut (10)); - - ChatMessageBox mb = new ChatMessageBox (mess, - viewer); - - mb.setShowAttentionBorder (false); - - try - { - - mb.init (); - - } catch (Exception e) { - - Environment.logError ("Unable to init chat message box for message: " + - mess, - e); - - return; - - } - - mess.setDealtWith (true); - - try - { - - EditorsEnvironment.updateMessage (mess); - - } catch (Exception e) { - - Environment.logError ("Unable to update message: " + - mess, - e); - - } - - content.add (mb); - - UIUtils.createQuestionPopup (viewer, - "New chat message", - Constants.MESSAGE_ICON_NAME, - content, - buttons, - null, - null); - - try - { - - EditorsEnvironment.updateMessage (mess); - - } catch (Exception e) { - - Environment.logError ("Unable to update message: " + - mess, - e); - - } - - } - - }); - - } -*/ -/* - public static void showInviteFromEditor (final String from, - final ActionListener onAccept, - final ActionListener onReject) - { - - UIUtils.doActionLater (new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - AbstractViewer viewer = Environment.getFocusedViewer (); - - UIUtils.createQuestionPopup (viewer, - "Invitation to be {an editor}", - "invite", - "You have been invited to be {an editor} for:

    " + from + "

    Would you like to accept this invitation?", - "Yes, accept", - "No, decline", - onAccept, - onReject, - null, - null); - - } - - }); - - } -*/ - public static void showResultError (final EditorsWebServiceResult res) - { - - AbstractViewer viewer = Environment.getFocusedViewer (); - - UIUtils.showErrorMessage (viewer, - res.getErrorMessage ()); - - } - - /** - * Create a tree + model that is suitable for viewing a set of chapter. - * It adds a listener that will open the associated object. - */ - public static JTree createViewTree (final Set chapters, - final AbstractProjectViewer viewer) - { - - final JTree tree = UIUtils.createTree (); - - tree.setCellRenderer (new ProjectTreeCellRenderer (true) - { - - @Override - public String getIconType (DataObject d, - DefaultMutableTreeNode par) - { - - if (d instanceof Note) - { - - return Constants.COMMENT_ICON_NAME; - - } - - return super.getIconType (d, - par); - - } - - }); - - tree.setEditable (false); - tree.setToolTipText (getUIString (actions,clicktoview)); - //"Click to view"); - tree.addMouseListener (new MouseEventHandler () - { - - @Override - public void handlePress (MouseEvent ev) - { - - // Edit the chapter. - TreePath tp = tree.getPathForLocation (ev.getX (), - ev.getY ()); - - if (tp == null) - { - - return; - - } - - Object d = ((DefaultMutableTreeNode) tp.getLastPathComponent ()).getUserObject (); - - if (d instanceof TreeParentNode) - { - - if (tree.isCollapsed (tp)) - { - - tree.expandPath (tp); - - } else { - - tree.collapsePath (tp); - - } - - return; - - } - - if ((ev.getClickCount () == 1) - && - (!ev.isPopupTrigger ()) - ) - { - - // Check to see if the key is null, if so then this a "fake" object - // and we need to get the real one. - DataObject obj = (DataObject) d; - - if (obj.getKey () == null) - { - - DataObject oobj = viewer.getProject ().getObjectById (obj.getClass (), - obj.getId ()); - - if (oobj == null) - { - - // The object isn't in this project. - Chapter c = null; - - // If a note, just show a standard popup with the message. - if (obj instanceof Note) - { - - obj = ((Note) obj); - - c = ((Note) obj).getChapter (); - - } - - if (obj instanceof Chapter) - { - - obj = ((Chapter) obj); - - c = ((Chapter) obj); - - } - - final DataObject dobj = obj; - - if (c.getBook () == null) - { - - return; - - } - - String projId = c.getBook ().getProject ().getId (); - - ProjectInfo p = null; - - try - { - - p = Environment.getProjectById (projId, - Project.EDITOR_PROJECT_TYPE); - - } catch (Exception e) { - - Environment.logError ("Unable to get project for id: " + - projId, - e); - - UIUtils.showErrorMessage (viewer, - String.format (getUIString (project,actions,openproject,openerrors,general), - projId, - getUIString (project,actions,openproject,openerrors,unspecified))); - //"Unable to open project."); - - return; - - } - - if (p != null) - { - - // We potentially get the project twice here but that's ok. - try - { - - Environment.openObjectInProject (p, - c); - - } catch (Exception e) { - - Environment.logError ("Unable to open project: " + - p, - e); - - UIUtils.showErrorMessage (viewer, - String.format (getUIString (project,actions,openproject,openerrors,general), - p.getName (), - getUIString (project,actions,openproject,openerrors,unspecified))); - //"Unable to open {project}."); - - return; - - } - - return; - - } - - // If this is a chapter and the project no longer exists then - // output a message to that effect. - - // If this is a note and the project no longer exists, output - // a message with the note but also saying the project doesn't exist. - - return; - - } else { - - viewer.viewObject (oobj); - - } - - } - - return; - - } - - } - - }); - - Project p = new Project (); - p.setName ("___bogus"); - - DefaultMutableTreeNode root = UIUtils.createTreeNode (p, - null, - null, - false); - - for (Chapter c : chapters) - { - - DefaultMutableTreeNode cnode = EditorsUIUtils.createTree (c, - null, - null, - false); - - if (cnode == null) - { - - continue; - - } - - root.add (cnode); - - } - - ((DefaultTreeModel) tree.getModel ()).setRoot (root); - - return tree; - - } - - public static DefaultMutableTreeNode createTree (Chapter c, - Collection exclude, - Collection init, - boolean selectable) - - { - - DefaultMutableTreeNode root = UIUtils.createTreeNode (c, - exclude, - init, - selectable); - - if (root == null) - { - - return null; - - } - - for (Note n : c.getNotes ()) - { - - DefaultMutableTreeNode node = UIUtils.createTreeNode (n, - exclude, - init, - selectable); - - if (node == null) - { - - continue; - - } - - root.add (node); - - } - - return root; - - } - - public static DefaultMutableTreeNode createTree (Project p, - Collection exclude, - Collection init, - boolean selectable) - - { - - DefaultMutableTreeNode root = UIUtils.createTreeNode (p, - exclude, - init, - selectable); - - if (p.getBooks ().size () == 1) - { - - Book b = (Book) p.getBooks ().get (0); - - // Get the chapters. - List chaps = b.getChapters (); - - for (Chapter c : chaps) - { - - DefaultMutableTreeNode node = EditorsUIUtils.createTree (c, - exclude, - init, - selectable); - - if (node == null) - { - - continue; - - } - - root.add (node); - - } - - } - - return root; - - } - - public static void showProjectComments (final ProjectCommentsMessage message, - final AbstractViewer parentViewer, - final ActionListener onShow) - { - - // Load up the project with the specific text. - // See if we have a project viewer for the project. - ProjectInfo proj = null; - - try - { - - proj = Environment.getProjectById (message.getForProjectId (), - (message.isSentByMe () ? Project.EDITOR_PROJECT_TYPE : Project.NORMAL_PROJECT_TYPE)); - - } catch (Exception e) { - - Environment.logError ("Unable to get project for: " + - message.getForProjectId (), - e); - - UIUtils.showErrorMessage (parentViewer, - getUIString (project,actions,openproject,openerrors,comments)); - //"Unable to show {comments}, please contact Quoll Writer support for assistance."); - - return; - - } - - if (proj == null) - { - - Environment.logError ("No project for: " + - message.getForProjectId ()); - - UIUtils.showErrorMessage (parentViewer, - getUIString (project,actions,openproject,openerrors,comments)); - //"Unable to show {comments}, please contact Quoll Writer support for assistance."); - - return; - - } - - final ProjectInfo _proj = proj; - - ActionListener open = new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - String pwd = _proj.getFilePassword (); - - if ((pwd != null) - && - (pwd.equals ("")) - ) - { - - pwd = null; - - } - - Set chaps = null; - - try - { - - chaps = Environment.getVersionedChapters (_proj, - message.getChapters (), - pwd); - - } catch (Exception e) { - - Environment.logError ("Unable to get versioned chapters for project: " + - _proj, - e); - - UIUtils.showErrorMessage (parentViewer, - getUIString (project,actions,openproject,openerrors,comments)); - //"Unable to show {comments}, please contact Quoll Writer support for assistance."); - - return; - - } - - ProjectVersion pv = null; - - try - { - - pv = Environment.getProjectVersionById (_proj, - message.getProjectVersion ().getId (), - pwd); - - } catch (Exception e) { - - Environment.logError ("Unable to get project version: " + - message.getProjectVersion ().getId () + - " for project: " + - _proj, - e); - - UIUtils.showErrorMessage (parentViewer, - getUIString (project,actions,openproject,openerrors,comments)); - //"Unable to show {comments}, please contact Quoll Writer support for assistance."); - - return; - - } - - if (pv == null) - { - - Environment.logError ("Unable to find project version: " + - message.getProjectVersion ().getId () + - " for project: " + - _proj); - - UIUtils.showErrorMessage (parentViewer, - getUIString (project,actions,openproject,openerrors,comments)); - //"Unable to show {comments}, please contact Quoll Writer support for assistance."); - - return; - - - } - - try - { - - // Need to "fill up" the project with the chapters and comments. - // Create a new project object just to be safe (in case the getProjectById call changes in the future). - Project np = new Project (); - np.setName (_proj.getName ()); - np.setProjectVersion (pv); - - np.setType (Project.EDITOR_PROJECT_TYPE); - np.setId (message.getForProjectId ()); - np.setName (message.getForProjectName ()); - - Book b = new Book (np, - np.getName ()); - - np.addBook (b); - - // Need to prevent an O^n performance hit here. - - Map kchaps = new HashMap (); - - for (Chapter c : chaps) - { - - b.addChapter (c); - - kchaps.put (c.getId (), - c); - - c.setEditPosition (-1); - c.setEditComplete (false); - - } - - long k = 1; - - for (Note n : message.getComments ()) - { - - // Need to give it a fake key. - n.setKey (k++); - - // Get the fake chapter. - Chapter fakec = n.getChapter (); - - // Get the real chapter. - Chapter realc = kchaps.get (fakec.getId ()); - - if (realc == null) - { - - // God damnit... - // TODO: Handle when a chapter no longer exists but have comments for it. - - } - - realc.addNote (n); - - } - - ProjectCommentsViewer pcv = new ProjectCommentsViewer (np, - message); - - pcv.init (); - - pcv.showViewer (); - - if (onShow != null) - { - - onShow.actionPerformed (new ActionEvent (pcv, 1, "show")); - - } - - } catch (Exception e) { - - Environment.logError ("Unable to view comments for project: " + - _proj, - e); - - UIUtils.showErrorMessage (parentViewer, - getUIString (project,actions,openproject,openerrors,comments)); - //"Unable to show {comments}, please contact Quoll Writer support for assistance."); - - return; - - } - - } - - }; - - UIUtils.askForPasswordForProject (proj, - null, - open, - parentViewer); - - } - - public static void showProjectUpdate (final UpdateProjectMessage message, - final AbstractViewer parentViewer, - final ActionListener onShow) - { - - // Load up the project with the specific text. - // See if we have a project viewer for the project. - ProjectInfo proj = null; - - try - { - - proj = Environment.getProjectById (message.getForProjectId (), - Project.EDITOR_PROJECT_TYPE); - - } catch (Exception e) { - - Environment.logError ("Unable to get project for: " + - message.getForProjectId (), - e); - - UIUtils.showErrorMessage (parentViewer, - getUIString (editors,messages,projectupdated,actionerror)); - //"Unable to show {project} update, please contact Quoll Writer support for assistance."); - - return; - - } - - final ProjectInfo _proj = proj; - - if (proj == null) - { - - UIUtils.showMessage (parentViewer, - getUIString (editors,messages,projectupdated,errors,novalue)); - //"The {project} for this update no longer exists."); - - message.setDealtWith (true); - - try - { - - EditorsEnvironment.updateMessage (message); - - } catch (Exception e) { - - Environment.logError ("Unable to update project message: " + - message, - e); - - } - - return; - - } - - ActionListener open = new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - String pwd = ev.getActionCommand (); - - if (pwd.equals ("")) - { - - pwd = null; - - } - - try - { - - Environment.updateToNewVersions (_proj, - message.getProjectVersion (), - message.getChapters (), - pwd); - - message.setDealtWith (true); - - EditorsEnvironment.updateMessage (message); - - } catch (Exception e) { - - Environment.logError ("Unable to update project to new versions of chapters: " + - _proj, - e); - - UIUtils.showErrorMessage (parentViewer, - getUIString (editors,messages,projectupdated,actionerror)); - //"Unable to update {project}, please contact Quoll Writer support for assistance."); - - return; - - } - - try - { - - Environment.openProject (_proj); - - AbstractProjectViewer pv = Environment.getProjectViewer (_proj); - - if (!(pv instanceof EditorProjectViewer)) - { - - Environment.logError ("Unable to open project at version: " + - message.getProjectVersion () + - ", project: " + - _proj); - - UIUtils.showErrorMessage (parentViewer, - getUIString (editors,messages,projectupdated,actionerror)); - //"Unable to view updated {project}, please contact Quoll Writer support for assistance."); - - return; - - } - - EditorProjectViewer epv = (EditorProjectViewer) pv; - - epv.switchToProjectVersion (message.getProjectVersion ()); - - if (onShow != null) - { - - onShow.actionPerformed (new ActionEvent (_proj, 1, "show")); - - } - - } catch (Exception e) { - - Environment.logError ("Unable to for project: " + - _proj, - e); - - UIUtils.showErrorMessage (parentViewer, - getUIString (editors,messages,projectupdated,actionerror)); - //"Unable to show {comments}, please contact Quoll Writer support for assistance."); - - return; - - } - - } - - }; - - UIUtils.askForPasswordForProject (proj, - null, - open, - parentViewer); - - } - - public static JComponent getProjectVersionPanel (final ProjectVersion pv, - final AbstractProjectViewer viewer) - { - - if (pv == null) - { - - return null; - - } - - String rows = ""; - - String ver = pv.getName (); - final String genComments = (pv.getDescription () != null ? pv.getDescription ().getText () : null); - Date due = pv.getDueDate (); - - if (ver != null) - { - - rows += "p"; - - } - - if (due != null) - { - - if (rows.length () > 0) - { - - rows += ", 6px, "; - - } - - rows += "p"; - - } - - if (genComments != null) - { - - if (rows.length () > 0) - { - - rows += ", 6px, "; - - } - - rows += "top:p"; - - } - - java.util.List prefix = Arrays.asList (editors,project,sidebar,comments,labels); - - FormLayout fl = new FormLayout ("right:p, 6px, fill:100px:grow", - rows); - - fl.setHonorsVisibility (true); - PanelBuilder builder = new PanelBuilder (fl); - - CellConstraints cc = new CellConstraints (); - - int row = 1; - - if (ver != null) - { - - builder.addLabel (String.format ("%s", - getUIString (prefix,version)), - //Environment.replaceObjectNames ("{Version}"), - cc.xy (1, - row)); - - String latest = ""; - - if (pv.isLatest ()) - { - - latest = getUIString (prefix,LanguageStrings.latest); - //" (latest)"; - - } - - builder.addLabel (String.format ("%s%s", - ver, - latest), - cc.xy (3, - row)); - - row += 2; - - } - - if (due != null) - { - - builder.addLabel (String.format ("%s", - getUIString (prefix,LanguageStrings.due)), - //Environment.replaceObjectNames ("{Due}"), - cc.xy (1, - row)); - - builder.addLabel (String.format ("%s", - Environment.formatDate (due)), - cc.xy (3, - row)); - - row += 2; - - } - - if (genComments != null) - { - - builder.addLabel (String.format ("%s", - getUIString (prefix,notes)), - //Environment.replaceObjectNames ("{Notes}"), - cc.xy (1, - row)); - - String commText = genComments; - - TextIterator ti = new TextIterator (commText); - - if (ti.getSentenceCount () > 1) - { - - commText = ti.getFirstSentence ().getText (); - - commText += getUIString (prefix,more); - //"
    More, click to view all."; - - } - - JComponent mess = UIUtils.createHelpTextPane (commText, - viewer); - - mess.addMouseListener (new MouseEventHandler () - { - - public void handlePress (MouseEvent ev) - { - - UIUtils.showMessage ((PopupsSupported) viewer, - getUIString (editors,project,sidebar,comments,notes,popup,title), - //"Notes", - genComments); - - } - - }); - - mess.setBorder (null); - - builder.add (mess, - cc.xy (3, - row)); - - } - - JPanel bp = builder.getPanel (); - - bp.setAlignmentX (Component.LEFT_ALIGNMENT); - bp.setMaximumSize (new Dimension (Short.MAX_VALUE, - bp.getPreferredSize ().height)); - - return bp; - - } - - public static void showMessagesInPopup (String title, - String iconType, - String help, - Set messages, - boolean showAttentionBorder, - AbstractViewer viewer, - Component showAt) - { - - final QPopup qp = UIUtils.createClosablePopup (title, - Environment.getIcon (iconType, - Constants.ICON_POPUP), - null); - - Box content = new Box (BoxLayout.Y_AXIS); - - JTextPane desc = UIUtils.createHelpTextPane (help + getUIString (editors,LanguageStrings.messages,show,suffix), - //"

    Messages with a red border require an acknowledgement or action from you.", - viewer); - - content.add (desc); - desc.setBorder (null); - desc.setSize (new Dimension (UIUtils.getPopupWidth () - 20, - desc.getPreferredSize ().height)); - - content.add (Box.createVerticalStrut (5)); - - try - { - - // Sort the messages in descending when order or newest first. - Query q = new Query (); - q.parse (String.format ("SELECT * FROM %s ORDER BY when DESC", - EditorMessage.class.getName ())); - - QueryResults qr = q.execute (messages); - - messages = new LinkedHashSet (qr.getResults ()); - - } catch (Exception e) { - - Environment.logError ("Unable to sort messages", - e); - - } - - Box b = new ScrollableBox (BoxLayout.Y_AXIS); - b.setAlignmentX (Component.LEFT_ALIGNMENT); - b.setAlignmentY (Component.TOP_ALIGNMENT); - - Box lastB = null; - - for (EditorMessage m : messages) - { - - MessageBox mb = null; - - try - { - - mb = MessageBoxFactory.getMessageBoxInstance (m, - viewer); - mb.setShowAttentionBorder (true);//showAttentionBorder); - - mb.init (); - - } catch (Exception e) { - - Environment.logError ("Unable to get message box for message: " + - m, - e); - - } - - mb.setAlignmentX (Component.LEFT_ALIGNMENT); - - Box wb = new Box (BoxLayout.Y_AXIS); - wb.setAlignmentX (Component.LEFT_ALIGNMENT); - wb.setAlignmentY (Component.TOP_ALIGNMENT); - wb.setBorder (UIUtils.createBottomLineWithPadding (5, 0, 10, 0)); - wb.add (mb); - - b.add (wb); - - lastB = wb; - - } - - if (lastB != null) - { - - //lastB.setBorder (UIUtils.createPadding (5, 0, 0, 0)); - - } - - final JScrollPane sp = UIUtils.createScrollPane (b); - - if (b.getPreferredSize ().height < 350) - { - - sp.setPreferredSize (new Dimension (500, b.getPreferredSize ().height + 1)); - - } else { - - sp.setPreferredSize (new Dimension (500, 350)); - - } - - sp.setBorder (null); - sp.setAlignmentX (Component.LEFT_ALIGNMENT); - sp.setBorder (new EmptyBorder (1, 0, 0, 0)); - - sp.getVerticalScrollBar ().addAdjustmentListener (new AdjustmentListener () - { - - public void adjustmentValueChanged (AdjustmentEvent ev) - { - - if (sp.getVerticalScrollBar ().getValue () > 0) - { - - sp.setBorder (new MatteBorder (1, 0, 0, 0, - UIUtils.getInnerBorderColor ())); - - } else { - - sp.setBorder (new EmptyBorder (1, 0, 0, 0)); - - } - - } - - }); - - content.add (sp); - - content.setBorder (new EmptyBorder (10, 10, 10, 10)); - - JButton finish = new JButton (getUIString (buttons,close)); - //"Close"); - - finish.addActionListener (new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - qp.removeFromParent (); - - } - - }); - - JButton[] buts = new JButton[] { finish }; - - JPanel bp = UIUtils.createButtonBar2 (buts, - Component.CENTER_ALIGNMENT); - bp.setOpaque (false); - - bp.setAlignmentX (Component.LEFT_ALIGNMENT); - bp.setBorder (UIUtils.createPadding (10, 0, 0, 0)); - - content.add (bp); - - content.setPreferredSize (new Dimension (UIUtils.getPopupWidth (), - content.getPreferredSize ().height)); - - qp.setContent (content); - - if (showAt != null) - { - - viewer.showPopupAt (qp, - showAt, - false); - - } else { - - viewer.showPopupAt (qp, - UIUtils.getCenterShowPosition (viewer, - qp), - false); - - } - - qp.setDraggable (viewer); - qp.resize (); - - UIUtils.doLater (new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - sp.getVerticalScrollBar ().setValue (0); - qp.resize (); - - } - - }); - - } - - public static void showAllMessagesForEditor (EditorEditor ed, - AbstractViewer viewer, - Component showAt) - { - - Project np = null; - - Set messages = ed.getMessages (new DefaultEditorMessageFilter (np, - EditorInfoMessage.MESSAGE_TYPE, - NewProjectMessage.MESSAGE_TYPE, - NewProjectResponseMessage.MESSAGE_TYPE, - ProjectCommentsMessage.MESSAGE_TYPE, - InviteResponseMessage.MESSAGE_TYPE, - ProjectEditStopMessage.MESSAGE_TYPE, - UpdateProjectMessage.MESSAGE_TYPE, - EditorRemovedMessage.MESSAGE_TYPE)); - - java.util.List prefix = Arrays.asList (editors,LanguageStrings.messages,show,all,popup); - - EditorsUIUtils.showMessagesInPopup (getUIString (prefix,title), - //"All messages", - Constants.FIND_ICON_NAME, - String.format (getUIString (prefix,text), - //"All messages you've sent to and/or received from %s.", - ed.getShortName ()), - messages, - false, - viewer, - showAt); - - } - - public static void showImportantMessagesForEditor (EditorEditor ed, - AbstractViewer viewer, - Component showAt) - { - - // Get undealt with messages that are not chat. - // If there is just one then show it, otherwise show a link that will display a popup of them. - Set undealtWith = ed.getMessages (EditorsUIUtils.importantMessageFilter); - - java.util.List prefix = Arrays.asList (editors,messages,show,important,popup); - - EditorsUIUtils.showMessagesInPopup (getUIString (prefix,title), - //"Important messages", - Constants.ERROR_ICON_NAME, - String.format (getUIString (prefix,text), - //"New and important messages from %s that require your attention.", - ed.getShortName ()), - undealtWith, - false, - viewer, - showAt); - - } - - public static void showProjectMessagesForEditor (EditorEditor ed, - AbstractProjectViewer viewer, - Component showAt) - { - - Set messages = ed.getMessages (new DefaultEditorMessageFilter (viewer.getProject (), - NewProjectMessage.MESSAGE_TYPE, - UpdateProjectMessage.MESSAGE_TYPE, - NewProjectResponseMessage.MESSAGE_TYPE, - ProjectEditStopMessage.MESSAGE_TYPE)); - - ProjectEditor pe = viewer.getProject ().getProjectEditor (ed); - - java.util.List prefix = Arrays.asList (editors,LanguageStrings.messages,show,project,popup); - - EditorsUIUtils.showMessagesInPopup (getUIString (prefix,title), - //"{Project} updates sent/received", - Project.OBJECT_TYPE, - String.format (getUIString (prefix,text), - //"All {project} updates you have sent to or received from %s for {project} %s. The latest update is shown first.", - ed.getShortName (), - viewer.getProject ().getName ()), - messages, - true, - viewer, - showAt); - - } - - public static void showAllCommentsForEditor (EditorEditor ed, - AbstractProjectViewer viewer, - Component showAt) - { - - Set comments = ed.getMessages (new DefaultEditorMessageFilter (viewer.getProject (), - ProjectCommentsMessage.MESSAGE_TYPE)); -/* - if (comments.size () == 0) - { - - UIUtils.showMessage ((PopupsSupported) viewer, - "No comments sent/received", - "No comments have been sent or received yet."); - - return; - - } -*/ - boolean sentByMe = comments.iterator ().next ().isSentByMe (); - - java.util.List prefix = Arrays.asList (editors,messages,show,(sentByMe ? commentssent : commentsreceived),popup); - - //String suffix = (sentByMe ? "sent" : "received"); - //String suffix2 = (sentByMe ? "sent to" : "received from"); - - EditorsUIUtils.showMessagesInPopup (getUIString (prefix,title), - //String.format ("{Comments} %s", - // suffix), - Constants.COMMENT_ICON_NAME, - String.format (getUIString (prefix,text), - //"All {comments} you have %s %s for {project} %s. The latest {comments} are shown first.", - // suffix2, - ed.getShortName (), - viewer.getProject ().getName ()), - comments, - true, - viewer, - showAt); - - } - - public static void showProjectsUserIsEditingForEditor (EditorEditor editor, - AbstractViewer viewer) - { - - Set projs = new LinkedHashSet (); - - try - { - - Set allProjs = Environment.getAllProjectInfos (); - - for (ProjectInfo p : allProjs) - { - - if (p.isEditorProject ()) - { - - EditorEditor ed = EditorsEnvironment.getEditorByEmail (p.getForEditor ().getEmail ()); - - if (ed == editor) - { - - projs.add (p); - - } - - } - - } - - } catch (Exception e) { - - Environment.logError ("Unable to get all projects", - e); - - UIUtils.showErrorMessage (viewer, - getUIString (editors,LanguageStrings.editor,showprojectseditingforcontact,actionerror)); - //String.format ("Unable to show {projects} you are editing for %s.", - // editor.getShortName ())); - - return; - - } - - java.util.List prefix = Arrays.asList (editors,LanguageStrings.editor,showprojectseditingforcontact,popup); - - final QPopup qp = UIUtils.createClosablePopup (getUIString (prefix,title), - //"{Projects} you are editing", - Environment.getIcon (Constants.EDIT_ICON_NAME, - Constants.ICON_POPUP), - null); - - Box content = new Box (BoxLayout.Y_AXIS); - - JTextPane desc = UIUtils.createHelpTextPane (String.format (getUIString (prefix,text), - //"All {projects} you are editing for %s.", - editor.getShortName ()), - viewer); - - content.add (desc); - desc.setBorder (null); - desc.setSize (new Dimension (UIUtils.getPopupWidth () - 20, - desc.getPreferredSize ().height)); - - content.add (Box.createVerticalStrut (5)); - - Box b = new ScrollableBox (BoxLayout.Y_AXIS); - b.setAlignmentX (Component.LEFT_ALIGNMENT); - - Box lastB = null; - - for (ProjectInfo p : projs) - { - - Box pb = new Box (BoxLayout.Y_AXIS); - pb.setAlignmentX (Component.LEFT_ALIGNMENT); - - JComponent h = UIUtils.createBoldSubHeader (p.getName (), - null); - pb.add (h); - - // TODO: Finish this. - - b.add (pb); - - lastB = pb; - - } - - if (lastB != null) - { - - lastB.setBorder (UIUtils.createPadding (0, 0, 0, 0)); - - } - - final JScrollPane sp = UIUtils.createScrollPane (b); - - if (b.getPreferredSize ().height < 350) - { - - sp.setPreferredSize (new Dimension (500, b.getPreferredSize ().height + 1)); - - } else { - - sp.setPreferredSize (new Dimension (500, 350)); - - } - - sp.setBorder (null); - sp.setAlignmentX (Component.LEFT_ALIGNMENT); - sp.setBorder (new EmptyBorder (1, 0, 0, 0)); - - sp.getVerticalScrollBar ().addAdjustmentListener (new AdjustmentListener () - { - - public void adjustmentValueChanged (AdjustmentEvent ev) - { - - if (sp.getVerticalScrollBar ().getValue () > 0) - { - - sp.setBorder (new MatteBorder (1, 0, 0, 0, - UIUtils.getInnerBorderColor ())); - - } else { - - sp.setBorder (new EmptyBorder (1, 0, 0, 0)); - - } - - } - - }); - - content.add (sp); - - content.setBorder (new EmptyBorder (10, 10, 10, 10)); - - JButton finish = UIUtils.createButton (getUIString (buttons,close)); - //"Close"); - - finish.addActionListener (new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - qp.removeFromParent (); - - } - - }); - - JButton[] buts = new JButton[] { finish }; - - JPanel bp = UIUtils.createButtonBar2 (buts, - Component.CENTER_ALIGNMENT); - bp.setOpaque (false); - - bp.setAlignmentX (Component.LEFT_ALIGNMENT); - bp.setBorder (UIUtils.createPadding (10, 0, 0, 0)); - - content.add (bp); - - content.setPreferredSize (new Dimension (UIUtils.getPopupWidth (), - content.getPreferredSize ().height)); - - qp.setContent (content); - - viewer.showPopupAt (qp, - UIUtils.getCenterShowPosition (viewer, - qp), - false); - - qp.setDraggable (viewer); - qp.resize (); - - UIUtils.doLater (new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - sp.getVerticalScrollBar ().setValue (0); - - } - - }); - - } - - public static void showProjectsEditorIsEditingForUser (EditorEditor editor, - AbstractViewer viewer) - { - - final Set projs = new LinkedHashSet (); - - Set messages = editor.getMessages (new EditorMessageFilter () - { - - public boolean accept (EditorMessage m) - { - - if (m.isSentByMe ()) - { - - return false; - - } - - if (!m.getMessageType ().equals (NewProjectResponseMessage.MESSAGE_TYPE)) - { - - return false; - - } - - NewProjectResponseMessage nprm = (NewProjectResponseMessage) m; - - if (!nprm.isAccepted ()) - { - - return false; - - } - - try - { - - projs.add (Environment.getProjectById (nprm.getForProjectId (), - Project.NORMAL_PROJECT_TYPE)); - - } catch (Exception e) { - - Environment.logError ("Unable to get normal project with id: " + - nprm.getForProjectId (), - e); - - } - - return true; - - } - - }); - - java.util.List prefix = Arrays.asList (editors,LanguageStrings.editor,showprojectscontactisediting,popup); - - final QPopup qp = UIUtils.createClosablePopup (getUIString (prefix,title), - //"{Projects} being edited", - Environment.getIcon (Constants.EDIT_ICON_NAME, - Constants.ICON_POPUP), - null); - - Box content = new Box (BoxLayout.Y_AXIS); - - JTextPane desc = UIUtils.createHelpTextPane (String.format (getUIString (prefix,text), - //"All {projects} %s is editing for you.", - editor.getShortName ()), - viewer); - - content.add (desc); - desc.setBorder (null); - desc.setSize (new Dimension (UIUtils.getPopupWidth () - 20, - desc.getPreferredSize ().height)); - - content.add (Box.createVerticalStrut (5)); - - Box b = new ScrollableBox (BoxLayout.Y_AXIS); - b.setAlignmentX (Component.LEFT_ALIGNMENT); - - Box lastB = null; - - for (ProjectInfo p : projs) - { - - } - - if (lastB != null) - { - - lastB.setBorder (UIUtils.createPadding (0, 0, 0, 0)); - - } - - final JScrollPane sp = UIUtils.createScrollPane (b); - - if (b.getPreferredSize ().height < 350) - { - - sp.setPreferredSize (new Dimension (500, b.getPreferredSize ().height + 1)); - - } else { - - sp.setPreferredSize (new Dimension (500, 350)); - - } - - sp.setBorder (null); - sp.setAlignmentX (Component.LEFT_ALIGNMENT); - sp.setBorder (new EmptyBorder (1, 0, 0, 0)); - - sp.getVerticalScrollBar ().addAdjustmentListener (new AdjustmentListener () - { - - public void adjustmentValueChanged (AdjustmentEvent ev) - { - - if (sp.getVerticalScrollBar ().getValue () > 0) - { - - sp.setBorder (new MatteBorder (1, 0, 0, 0, - UIUtils.getInnerBorderColor ())); - - } else { - - sp.setBorder (new EmptyBorder (1, 0, 0, 0)); - - } - - } - - }); - - content.add (sp); - - content.setBorder (new EmptyBorder (10, 10, 10, 10)); - - JButton finish = new JButton (getUIString (buttons,close)); - //"Close"); - - finish.addActionListener (new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - qp.removeFromParent (); - - } - - }); - - JButton[] buts = new JButton[] { finish }; - - JPanel bp = UIUtils.createButtonBar2 (buts, - Component.CENTER_ALIGNMENT); - bp.setOpaque (false); - - bp.setAlignmentX (Component.LEFT_ALIGNMENT); - bp.setBorder (UIUtils.createPadding (10, 0, 0, 0)); - - content.add (bp); - - content.setPreferredSize (new Dimension (UIUtils.getPopupWidth (), - content.getPreferredSize ().height)); - - qp.setContent (content); - - viewer.showPopupAt (qp, - UIUtils.getCenterShowPosition (viewer, - qp), - false); - - qp.setDraggable (viewer); - qp.resize (); - - UIUtils.doLater (new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - sp.getVerticalScrollBar ().setValue (0); - - } - - }); - - } - - - public static JComponent getProjectMessageDetails (final AbstractProjectMessage message, - final AbstractViewer viewer, - final MessageBox parentMessageBox) - { - - String plural = ""; - - java.util.List prefix = Arrays.asList (editors,messages,newupdateproject,labels); - - if (message.getChapters ().size () > 1) - { - - plural = "s"; - - } - - ProjectVersion projVer = message.getProjectVersion (); - Date dueDate = projVer.getDueDate (); - - String notes = ((projVer.getDescription () != null) ? projVer.getDescription ().getText () : null); - String verName = projVer.getName (); - - ProjectInfo proj = null; - - try - { - - proj = Environment.getProjectById (message.getForProjectId (), - (message.isSentByMe () ? Project.NORMAL_PROJECT_TYPE : Project.EDITOR_PROJECT_TYPE)); - - } catch (Exception e) { - - Environment.logError ("Unable to get project for id: " + - message.getForProjectId (), - e); - - } - - final ProjectInfo fproj = proj; - - // Show: - // * Project - // * Sent - // * Version (optional) - // * Word/chapter count - // * Due by - // * Notes (optional) - // * View link - - String rows = "p, 6px, p"; - - if (verName != null) - { - - rows += ", 6px, p"; - - } - - // Word count, due by - rows += ", 6px, p, 6px, p"; - - if (notes != null) - { - - rows += ", 6px, top:p"; - - } - - rows += ", 6px, p"; - - FormLayout fl = new FormLayout ("right:p, 6px, fill:100px:grow", - rows); - - fl.setHonorsVisibility (true); - PanelBuilder builder = new PanelBuilder (fl); - - CellConstraints cc = new CellConstraints (); - - int row = 1; - - builder.addLabel (String.format ("%s", - getUIString (prefix,Project.OBJECT_TYPE)), - //Environment.replaceObjectNames ("{Project}"), - cc.xy (1, - row)); - - if (proj != null) - { - - JLabel openProj = UIUtils.createClickableLabel (message.getForProjectName (), - null, - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - if (fproj != null) - { - - try - { - - Environment.openProject (fproj); - - } catch (Exception e) { - - Environment.logError ("Unable to open project: " + - fproj, - e); - - } - - } - - } - - }); - - openProj.setToolTipText (getUIString (prefix,open)); - //Environment.replaceObjectNames ("Click to open the {project}")); - - builder.add (openProj, - cc.xy (3, - row)); - - } else { - - builder.addLabel (String.format ("%s", - message.getForProjectName ()), - cc.xy (3, - row)); - - } - - row += 2; - - builder.addLabel (String.format ("%s", - getUIString (prefix,(message.isSentByMe () ? sent : received))), - //Environment.replaceObjectNames (String.format ("%s", - // message.isSentByMe () ? "Sent" : "Received")), - cc.xy (1, - row)); - - builder.addLabel (Environment.formatDateTime (message.getWhen ()), - cc.xy (3, - row)); - - row += 2; - - if (verName != null) - { - - builder.addLabel (String.format ("%s", - getUIString (prefix,version)), - //Environment.replaceObjectNames ("Version"), - cc.xy (1, - row)); - - builder.addLabel (verName, - cc.xy (3, - row)); - - row += 2; - - } - - builder.addLabel (String.format (getUIString (prefix,detail), - Environment.formatNumber (message.getWordCount ()), - Environment.formatNumber (message.getChapters ().size ())), - //Environment.replaceObjectNames (String.format ("%s words, %s {chapter%s}", - // Environment.formatNumber (message.getWordCount ()), - // message.getChapters ().size (), - // plural)), - cc.xy (3, - row)); - - row += 2; - - builder.addLabel (String.format ("%s", - getUIString (prefix,dueby)), - //Environment.replaceObjectNames ("Due by"), - cc.xy (1, - row)); - - builder.addLabel ("" + (dueDate != null ? Environment.formatDate (dueDate) : getUIString (prefix,notspecified) /*"Not specified."*/) + "", - cc.xy (3, - row)); - - row += 2; - - if (notes != null) - { - - builder.addLabel (String.format ("%s", - getUIString (prefix,LanguageStrings.notes)), - //Environment.replaceObjectNames ("Notes"), - cc.xy (1, - row)); - - JComponent nc = UIUtils.createHelpTextPane (notes, - viewer); - nc.setBorder (null); - - builder.add (nc, - cc.xy (3, - row)); - - row += 2; - - } - - if (message.isSentByMe ()) - { - - JLabel viewProj = null; - - if (proj == null) - { - - viewProj = UIUtils.createErrorLabel (getUIString (editors,messages,newupdateproject,sent,labels,projectdeleted)); - //"{Project} has been deleted"); - - } else { - - viewProj = UIUtils.createClickableLabel (getUIString (editors,messages,newupdateproject,sent,labels,clicktoview), - //"Click to view what you sent", - Environment.getIcon (Constants.VIEW_ICON_NAME, - Constants.ICON_CLICKABLE_LABEL), - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - AbstractViewer childViewer = parentMessageBox.getChildViewer (); - - if (childViewer != null) - { - - childViewer.setExtendedState (JFrame.NORMAL); - childViewer.toFront (); - - return; - - } - - // Load up the project with the specific text. - // See if we have a project viewer for the project. - ProjectInfo proj = null; - - try - { - - proj = Environment.getProjectById (message.getForProjectId (), - Project.NORMAL_PROJECT_TYPE); - - } catch (Exception e) { - - Environment.logError ("Unable to get project for: " + - message.getForProjectId (), - e); - - UIUtils.showErrorMessage (viewer, - getUIString (editors,projectsent,actions,openproject,actionerror)); - //"Unable to show the {project}, please contact Quoll Writer support for assistance."); - - return; - - } - - final ProjectInfo _proj = proj; - - ActionListener open = new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - String pwd = _proj.getFilePassword (); - -/* - ev.getActionCommand (); - - if (pwd.equals ("")) - { - - pwd = null; - - } -*/ - Set chaps = null; - - try - { - - chaps = Environment.getVersionedChapters (_proj, - message.getChapters (), - pwd); - - } catch (Exception e) { - - Environment.logError ("Unable to get versioned chapters for project: " + - _proj, - e); - - UIUtils.showErrorMessage (viewer, - getUIString (editors,projectsent,actions,openproject,actionerror)); - //"Unable to show {comments}, please contact Quoll Writer support for assistance."); - - return; - - } - - try - { - - // Need to "fill up" the project with the chapters and comments. - // Create a new project object just to be safe (in case the getProjectById call changes in the future). - Project np = new Project (); - np.setName (_proj.getName ()); - - np.setType (Project.EDITOR_PROJECT_TYPE); - np.setId (message.getForProjectId ()); - np.setName (message.getForProjectName ()); - - Book b = new Book (np, - np.getName ()); - - np.addBook (b); - - for (Chapter c : chaps) - { - - b.addChapter (c); - - } - - final int chapterCount = chaps.size (); - - ProjectSentReceivedViewer pcv = new ProjectSentReceivedViewer (np, - message) - { - - public ProjectSentReceivedSideBar getSideBar () - { - - return new ProjectSentReceivedSideBar (this, - this.message) - { - - @Override - public void onShow () - { - - } - - @Override - public void onHide () - { - - } - - @Override - public String getTitle () - { - - return getUIString (editors,projectsent,sidebar,title); - //"Sent to"; - - } - - @Override - public String getItemsIconType () - { - - return Chapter.OBJECT_TYPE; - - } - - @Override - public String getItemsTitle () - { - - return getUIString (editors,projectsent,sidebar,chapters,title); - //"{Chapters}"; - - } - - @Override - public int getItemCount () - { - - return chapterCount; - - } - - @Override - public JComponent getMessageDetails (AbstractProjectMessage message) - { - - java.util.List prefix = Arrays.asList (editors,projectsent,sidebar,labels); - - final ProjectSentReceivedSideBar _this = this; - - String rows = "p"; - - ProjectVersion projVer = message.getProjectVersion (); - - String verName = projVer.getName (); - - if (verName != null) - { - - rows += ", 6px, p"; - - } - - final String notes = (projVer.getDescription () != null ? projVer.getDescription ().getText () : null); - - if (notes != null) - { - - rows += ", 6px, top:p"; - - } - - FormLayout fl = new FormLayout ("right:p, 6px, fill:100px:grow", - rows); - - fl.setHonorsVisibility (true); - PanelBuilder builder = new PanelBuilder (fl); - - CellConstraints cc = new CellConstraints (); - - int row = 1; - - builder.addLabel (String.format ("%s", - getUIString (prefix,sent)), - //Environment.replaceObjectNames ("{Sent}"), - cc.xy (1, - row)); - - builder.addLabel ("" + Environment.formatDateTime (message.getWhen ()) + "", - cc.xy (3, - row)); - - row += 2; - - if (verName != null) - { - - builder.addLabel (String.format ("%s", - getUIString (prefix,version)), - //Environment.replaceObjectNames ("{Version}"), - cc.xy (1, - row)); - builder.addLabel (String.format ("%s", - verName), - cc.xy (3, - row)); - - row += 2; - - } - - if (notes != null) - { - - builder.addLabel (String.format ("%s", - getUIString (prefix,LanguageStrings.notes)), - //Environment.replaceObjectNames ("{Notes}"), - cc.xy (1, - row)); - - String commText = notes; - - TextIterator ti = new TextIterator (commText); - - if (ti.getSentenceCount () > 1) - { - - commText = ti.getFirstSentence ().getText (); - - commText += getUIString (prefix,more); - //"
    More, click to view all."; - - } - - JComponent mess = UIUtils.createHelpTextPane (commText, - this.viewer); - - mess.addMouseListener (new MouseEventHandler () - { - - @Override - public void handlePress (MouseEvent ev) - { - - UIUtils.showMessage ((PopupsSupported) _this.getViewer (), - getUIString (editors,projectsent,sidebar,notes,popup,title), - //"Notes", - notes); - - } - - }); - - mess.setBorder (null); - - builder.add (mess, - cc.xy (3, - row)); - - } - - JPanel bp = builder.getPanel (); - bp.setAlignmentX (Component.LEFT_ALIGNMENT); - bp.setOpaque (false); - - return bp; - - } - - }; - - } - - @Override - public void init () - throws Exception - { - - super.init (); - - this.viewObject (this.proj.getBook (0).getChapters ().get (0)); - - } - - @Override - public String getViewerIcon () - { - - return Constants.PROJECT_ICON_NAME; - - } - - @Override - public String getViewerTitle () - { - - return String.format (getUIString (editors,projectsent,viewertitle), - this.proj.getName ()); - //"{Project} sent: " + this.proj.getName (); - - } - - }; - - pcv.init (); - - parentMessageBox.setChildViewer (pcv); - - pcv.addWindowListener (new WindowAdapter () - { - - public void windowClosed (WindowEvent ev) - { - - parentMessageBox.setChildViewer (null); - - } - - }); - - pcv.showViewer (); - - } catch (Exception e) { - - Environment.logError ("Unable to view project: " + - _proj, - e); - - UIUtils.showErrorMessage (viewer, - getUIString (editors,projectsent,actions,openproject,actionerror)); - //"Unable to show {project}, please contact Quoll Writer support for assistance."); - - return; - - } - - } - - }; - - UIUtils.askForPasswordForProject (proj, - null, - open, - viewer); - - }}); - - } - - viewProj.setBorder (UIUtils.createPadding (0, 10, 0, 0)); - - builder.add (viewProj, - cc.xywh (1, - row, - 3, - 1)); - - } - - JPanel bp = builder.getPanel (); - bp.setOpaque (false); - bp.setAlignmentX (JComponent.LEFT_ALIGNMENT); - - return bp; - - } - - public static JComponent getNewProjectMessageDetails (final NewProjectMessage mess, - final AbstractProjectViewer viewer, - final MessageBox parentMessageBox) - { - - return EditorsUIUtils.getProjectMessageDetails (mess, - viewer, - parentMessageBox); - - } - -} diff --git a/src/com/quollwriter/editors/ui/InviteMessageBox.java b/src/com/quollwriter/editors/ui/InviteMessageBox.java deleted file mode 100644 index f8f79bd2..00000000 --- a/src/com/quollwriter/editors/ui/InviteMessageBox.java +++ /dev/null @@ -1,212 +0,0 @@ -package com.quollwriter.editors.ui; - -import java.util.Date; -import java.util.List; -import java.util.ArrayList; -import java.util.Map; -import java.util.LinkedHashMap; - -import java.awt.event.*; -import java.awt.Component; -import java.awt.Dimension; -import javax.swing.*; -import javax.swing.border.*; - -import com.jgoodies.forms.builder.*; -import com.jgoodies.forms.factories.*; -import com.jgoodies.forms.layout.*; - -import com.quollwriter.*; -import com.quollwriter.ui.*; -import com.quollwriter.data.*; -import com.quollwriter.data.editors.*; -import com.quollwriter.ui.components.ImagePanel; -import com.quollwriter.editors.messages.*; -import com.quollwriter.editors.*; - -import static com.quollwriter.LanguageStrings.*; -import static com.quollwriter.Environment.getUIString; - -public class InviteMessageBox extends MessageBox -{ - - private Box responseBox = null; - - public InviteMessageBox (InviteMessage mess, - AbstractViewer viewer) - { - - super (mess, - viewer); - - } - - @Override - public boolean isShowAttentionBorder () - { - - return false; - - } - - @Override - public boolean isAutoDealtWith () - { - - return false; - - } - - public void doUpdate () - { - - this.responseBox.setVisible (!this.message.isDealtWith ()); - - } - - public void doInit () - { - - final InviteMessageBox _this = this; - - String title = getUIString (editors,messages,invite,sent,LanguageStrings.title); - //"Sent invitation"; - - if (!this.message.isSentByMe ()) - { - - title = getUIString (editors,messages,invite,received,LanguageStrings.title); - //"Received an invitation to become {an editor}"; - - } - - JComponent h = UIUtils.createBoldSubHeader (title, - Constants.EDITORS_ICON_NAME); - - this.add (h); - - - if ((!this.message.isDealtWith ()) - && - (!this.message.isSentByMe ()) - ) - { - - this.responseBox = new Box (BoxLayout.Y_AXIS); - - this.responseBox.setBorder (UIUtils.createPadding (0, 5, 0, 5)); - - this.add (this.responseBox); - - JComponent l = UIUtils.createBoldSubHeader (getUIString (editors,messages,invite,received,response), - //"Select your response below", - null); - - this.responseBox.add (l); - - JButton accept = UIUtils.createButton (getUIString (editors,messages,invite,received,buttons,LanguageStrings.confirm,text), - //"Accept", - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - _this.handleResponse (true); - - } - - }); - - accept.setToolTipText (getUIString (editors,messages,invite,received,buttons,LanguageStrings.confirm,tooltip)); - //"Click to accept the invitation"); - - JButton reject = UIUtils.createButton (getUIString (editors,messages,invite,received,buttons,LanguageStrings.reject,text), - //"Reject", - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - _this.handleResponse (false); - - } - - }); - - reject.setToolTipText (getUIString (editors,messages,invite,received,buttons,LanguageStrings.reject,text)); - //"Click to reject the invitation"); - - JButton[] buts = new JButton[] { accept, reject }; - - JComponent bb = UIUtils.createButtonBar2 (buts, - Component.LEFT_ALIGNMENT); - - bb.setAlignmentX (Component.LEFT_ALIGNMENT); - - this.responseBox.add (bb); - - } - - } - - private void handleResponse (boolean accepted) - { - - final InviteMessageBox _this = this; - - EditorEditor ed = this.message.getEditor (); - - InviteResponseMessage rm = new InviteResponseMessage (accepted, - EditorsEnvironment.getUserAccount ()); - rm.setEditor (ed); - - ActionListener onComplete = new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.message.setDealtWith (true); - - try - { - - EditorsEnvironment.updateMessage (_this.message); - - } catch (Exception e) { - - Environment.logError ("Unable to update message: " + - _this.message, - e); - - UIUtils.showErrorMessage (_this.viewer, - getUIString (editors,messages,update,actionerror)); - //"Unable to update invite, please contact Quoll Writer support for assistance."); - - } - - } - - }; - - if (accepted) - { - - EditorsEnvironment.acceptInvite (ed, - rm, - onComplete); - - } else { - - EditorsEnvironment.rejectInvite (ed, - rm, - onComplete); - - } - - } -} diff --git a/src/com/quollwriter/editors/ui/InviteResponseMessageBox.java b/src/com/quollwriter/editors/ui/InviteResponseMessageBox.java deleted file mode 100644 index 81f6fc0a..00000000 --- a/src/com/quollwriter/editors/ui/InviteResponseMessageBox.java +++ /dev/null @@ -1,254 +0,0 @@ -package com.quollwriter.editors.ui; - -import java.util.List; -import java.util.ArrayList; - -import java.awt.event.*; -import java.awt.Component; -import java.awt.Dimension; -import javax.swing.*; -import javax.swing.border.*; - -import com.jgoodies.forms.builder.*; -import com.jgoodies.forms.factories.*; -import com.jgoodies.forms.layout.*; - -import com.quollwriter.*; -import com.quollwriter.ui.*; -import com.quollwriter.data.*; -import com.quollwriter.data.editors.*; -import com.quollwriter.ui.components.ImagePanel; -import com.quollwriter.ui.components.ActionAdapter; -import com.quollwriter.editors.messages.*; -import com.quollwriter.editors.*; - -import static com.quollwriter.LanguageStrings.*; -import static com.quollwriter.Environment.getUIString; - -// Use an annotation? -//@MessageBox(messageClass=InviteResponseMessage) -public class InviteResponseMessageBox extends MessageBox -{ - - private Box responseBox = null; - - public InviteResponseMessageBox (InviteResponseMessage mess, - AbstractViewer viewer) - { - - super (mess, - viewer); - - } - - public boolean isAutoDealtWith () - { - - return false; - - } - - public void doUpdate () - { - - } - - public void doInit () - { - - final InviteResponseMessageBox _this = this; - - if (!this.message.isDealtWith ()) - { - - // Show the response. - this.responseBox = new Box (BoxLayout.Y_AXIS); - - this.add (this.responseBox); - - JComponent l = UIUtils.createBoldSubHeader (getUIString (editors,messages,inviteresponse,undealtwith,(this.message.isAccepted () ? accepted : rejected),title), - //String.format ("%s the invitation", - // (this.message.isAccepted () ? "Accepted" : "Rejected")), - (this.message.isAccepted () ? Constants.ACCEPTED_ICON_NAME : Constants.REJECTED_ICON_NAME)); - - this.responseBox.add (l); - this.responseBox.setBorder (UIUtils.createPadding (5, 5, 0, 5)); - - if (this.message.isAccepted ()) - { - - if ((this.message.getEditorName () != null) - || - (this.message.getEditorAvatar () != null) - ) - { - - JTextPane desc = UIUtils.createHelpTextPane (getUIString (editors,messages,inviteresponse,undealtwith,accepted,text), - //"Additionally they provided the following name/avatar.", - this.viewer); - - this.responseBox.add (Box.createVerticalStrut (5)); - - this.responseBox.add (desc); - desc.setBorder (null); - desc.setSize (new Dimension (UIUtils.getPopupWidth () - 20, - desc.getPreferredSize ().height)); - - Box editorInfo = new Box (BoxLayout.X_AXIS); - editorInfo.setAlignmentX (Component.LEFT_ALIGNMENT); - editorInfo.setBorder (UIUtils.createPadding (5, 5, 5, 5)); - - this.responseBox.add (editorInfo); - - if (this.message.getEditorAvatar () != null) - { - - JLabel avatar = new JLabel (); - - avatar.setAlignmentY (Component.TOP_ALIGNMENT); - avatar.setVerticalAlignment (SwingConstants.TOP); - - editorInfo.add (avatar); - avatar.setOpaque (false); - - avatar.setIcon (new ImageIcon (UIUtils.getScaledImage (_this.message.getEditorAvatar (), - 50))); - - avatar.setBorder (new CompoundBorder (UIUtils.createPadding (0, 0, 0, 5), - UIUtils.createLineBorder ())); - - } - - if (this.message.getEditorName () != null) - { - - JLabel name = new JLabel (this.message.getEditorName ()); - editorInfo.add (name); - - name.setBorder (null); - name.setAlignmentY (Component.TOP_ALIGNMENT); - name.setVerticalAlignment (JLabel.TOP); - name.setAlignmentX (Component.LEFT_ALIGNMENT); - name.setFont (name.getFont ().deriveFont ((float) UIUtils.getScaledFontSize (14)).deriveFont (java.awt.Font.PLAIN)); - - } - - } - - } - - final EditorEditor ed = this.message.getEditor (); - - JButton ok = UIUtils.createButton (getUIString (editors,messages,inviteresponse,undealtwith,buttons,confirm)); - //"Ok, got it"); - - ok.addActionListener (new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - try - { - - if (_this.message.isAccepted ()) - { - - ed.setEditorStatus (EditorEditor.EditorStatus.current); - - if (_this.message.getEditorName () != null) - { - - ed.setName (_this.message.getEditorName ()); - - } - - if (_this.message.getEditorAvatar () != null) - { - - ed.setAvatar (_this.message.getEditorAvatar ()); - - } - - EditorsEnvironment.updateEditor (ed); - - // Is this response for an invite message or just out of the blue from a web service invite? - if (!EditorsEnvironment.hasSentMessageOfTypeToEditor (ed, - InviteMessage.MESSAGE_TYPE)) - { - - EditorsEnvironment.sendUserInformationToEditor (ed, - null, - null, - null); - - } - - } else { - - ed.setEditorStatus (EditorEditor.EditorStatus.rejected); - - EditorsEnvironment.updateEditor (ed); - - } - - _this.message.setDealtWith (true); - - EditorsEnvironment.updateMessage (_this.message); - - _this.responseBox.setVisible (false); - - } catch (Exception e) { - - Environment.logError ("Unable to update editor: " + - ed, - e); - - UIUtils.showErrorMessage (_this.viewer, - getUIString (editors,editor,edit,actionerror)); - //"Unable to update {editor}, please contact Quoll Writer support for assistance."); - - return; - - } - - } - - }); - - JButton[] buts = new JButton[] { ok }; - - JPanel bb = UIUtils.createButtonBar2 (buts, - Component.LEFT_ALIGNMENT); - bb.setOpaque (false); - bb.setAlignmentX (Component.LEFT_ALIGNMENT); - bb.setBorder (UIUtils.createPadding (5, 0, 0, 0)); - - this.responseBox.add (bb); - - return; - - } - - boolean accepted = this.message.isAccepted (); - String iconName = (accepted ? Constants.ACCEPTED_ICON_NAME : Constants.REJECTED_ICON_NAME); - - String message = getUIString (editors,messages,inviteresponse,dealtwith,LanguageStrings.accepted,title); - //"Accepted invitation to be {an editor}"; - - if (!accepted) - { - - message = getUIString (editors,messages,inviteresponse,dealtwith,rejected,title); - //"Rejected invitation to be {an editor}"; - - } - - JComponent h = UIUtils.createBoldSubHeader (message, - iconName); - - this.add (h); - - } - -} diff --git a/src/com/quollwriter/editors/ui/MessageAccordionItem.java b/src/com/quollwriter/editors/ui/MessageAccordionItem.java deleted file mode 100644 index 6b975b22..00000000 --- a/src/com/quollwriter/editors/ui/MessageAccordionItem.java +++ /dev/null @@ -1,297 +0,0 @@ -package com.quollwriter.editors.ui; - -import java.awt.Component; -import java.awt.Point; -import java.awt.Color; -import java.awt.Dimension; -import java.awt.event.*; -import java.awt.dnd.*; - -import java.util.Date; -import java.util.List; -import java.util.ArrayList; -import java.util.StringTokenizer; -import java.util.Set; -import java.util.LinkedHashSet; - -import javax.swing.*; -import javax.swing.border.*; -import javax.swing.tree.*; - -import com.jgoodies.forms.builder.*; -import com.jgoodies.forms.factories.*; -import com.jgoodies.forms.layout.*; - -import com.quollwriter.data.*; -import com.quollwriter.data.editors.*; -import com.quollwriter.*; -import com.quollwriter.events.*; -import com.quollwriter.editors.messages.*; -import com.quollwriter.ui.*; -import com.quollwriter.ui.actionHandlers.*; -import com.quollwriter.ui.components.ActionAdapter; -import com.quollwriter.ui.components.Header; -import com.quollwriter.ui.components.ImagePanel; -import com.quollwriter.ui.renderers.*; - -import static com.quollwriter.LanguageStrings.*; -import static com.quollwriter.Environment.getUIString; - -public class MessageAccordionItem extends AccordionItem -{ - - protected AbstractViewer viewer = null; - protected Box content = null; - protected Set messageBoxes = new LinkedHashSet (); - protected Date date = null; - - public MessageAccordionItem (AbstractViewer viewer, - Date d, - Set messages) - { - - super (""); - - this.date = d; - - if (messages == null) - { - - messages = new LinkedHashSet (); - - } - - int c = messages.size (); - /* - String dateName = null; - - if (Utils.isToday (d)) - { - - dateName = "Today"; - - } - - if (Utils.isYesterday (d)) - { - - dateName = "Yesterday"; - - } - - if (dateName == null) - { - - dateName = Environment.formatDate (d); - - } - - this.setTitle (String.format ("%s (%s)", - dateName, - c)); - */ - this.setIconType (null); - - this.viewer = viewer; - - final MessageAccordionItem _this = this; - - this.content = new Box (BoxLayout.Y_AXIS); - - Header h = this.getHeader (); - - // TODO: Make a configurable value. - h.setTitleColor (UIUtils.getColor ("#aaaaaa")); - h.setFontSize (14); - - // TODO: Tidy this up. - - h.setBorder (new CompoundBorder (new CompoundBorder (new MatteBorder (0, 0, 1, 0, UIUtils.getColor ("#dddddd")), - new EmptyBorder (0, 0, 3, 0)), - h.getBorder ())); - - this.content.setBorder (UIUtils.createPadding (5, 0, 10, 0)); - - for (E m : messages) - { - - this.addMessage (m); - - } - - this.content.add (Box.createVerticalGlue ()); - - this.updateHeaderTitle (); - - } - - public void updateHeaderTitle () - { - - String dateName = null; - - if (Utils.isToday (this.date)) - { - - dateName = getUIString (times,today); - //"Today"; - - } - - if (Utils.isYesterday (this.date)) - { - - dateName = getUIString (times,yesterday); - //"Yesterday"; - - } - - if (dateName == null) - { - - dateName = Environment.formatDate (this.date); - - } - - int c = this.getContent ().getComponentCount () - 1; - - this.setTitle (String.format (getUIString (editors,editor,view,chatmessages,title), - //"%s (%s)", - dateName, - c)); - - } - - private JLabel createLabel (String m) - { - - JLabel l = UIUtils.createInformationLabel (m); - - l.setForeground (UIUtils.getColor ("#aaaaaa")); - - return l; - - } - - public void addMessage (E m) - { - - JComponent mb = this.getMessageBox (m); - - if (mb == null) - { - - return; - - } - - this.content.add (mb); - - int c = this.messageBoxes.size (); - - this.updateHeaderTitle (); - - this.validate (); - this.repaint (); - - } - - public JComponent getMessageBox (E m) - { - - MessageBox mb = null; - - try - { - - mb = MessageBoxFactory.getMessageBoxInstance (m, - this.viewer); - - } catch (Exception e) { - - Environment.logError ("Unable to get message box for message: " + - m, - e); - - return null; - - } - - if (mb != null) - { - - try - { - - mb.init (); - - } catch (Exception e) { - - Environment.logError ("Unable to init message box for message: " + - m, - e); - - return null; - - } - - } else { - - return null; - - } - - this.messageBoxes.add (mb); - - Box b = new Box (BoxLayout.Y_AXIS); - b.setAlignmentX (Component.LEFT_ALIGNMENT); - - Box details = new Box (BoxLayout.X_AXIS); - details.setAlignmentX (Component.LEFT_ALIGNMENT); - - String name = m.getEditor ().getMainName (); - - if (m.isSentByMe ()) - { - - name = "Me"; - - } - - details.add (this.createLabel (name)); - details.add (Box.createHorizontalGlue ()); - details.add (this.createLabel (Environment.formatTime (m.getWhen ()))); - - b.add (details); - - b.add (Box.createVerticalStrut (5)); - - mb.setAlignmentX (Component.LEFT_ALIGNMENT); - - b.add (mb); - - b.setBorder (new EmptyBorder (0, 0, 3, 0)); - - details.setBorder (new CompoundBorder (new MatteBorder (0, 0, 1, 0, UIUtils.getColor ("#dddddd")), - new EmptyBorder (5, 0, 5, 0))); - - - return b; - - } - - public JComponent getContent () - { - - return this.content; - - } - - public void init () - { - - super.init (); - - } - -} diff --git a/src/com/quollwriter/editors/ui/MessageBox.java b/src/com/quollwriter/editors/ui/MessageBox.java deleted file mode 100644 index 6bdea5cb..00000000 --- a/src/com/quollwriter/editors/ui/MessageBox.java +++ /dev/null @@ -1,383 +0,0 @@ -package com.quollwriter.editors.ui; - -import java.awt.Component; -import java.awt.Dimension; -import java.awt.Point; -import java.awt.Container; -import java.awt.AWTEvent; -import javax.swing.plaf.LayerUI; -import java.awt.event.*; -import javax.swing.*; -import javax.swing.border.*; - -import com.quollwriter.*; -import com.quollwriter.ui.*; -import com.quollwriter.events.*; -import com.quollwriter.ui.components.ImagePanel; -import com.quollwriter.editors.messages.*; -import com.quollwriter.editors.*; - -import static com.quollwriter.LanguageStrings.*; -import static com.quollwriter.Environment.getUIString; - -public abstract class MessageBox extends Box implements EditorMessageListener -{ - - protected AbstractViewer viewer = null; - protected E message = null; - protected boolean showAttentionBorder = true; - private Box content = null; - private PropertyChangedListener updateListener = null; - private AbstractViewer childViewer = null; - - public MessageBox (E mess, - AbstractViewer viewer) - { - - super (BoxLayout.Y_AXIS); - - this.content = new Box (BoxLayout.Y_AXIS); - - final MessageBox _this = this; - - final Timer update = new Timer (750, - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.message.setDealtWith (true); - - try - { - - EditorsEnvironment.updateMessage (_this.message); - - } catch (Exception e) { - - Environment.logError ("Unable to update message: " + - _this.message, - e); - - } - - } - - }); - - update.setRepeats (false); - - this.add (new JLayer (this.content, new LayerUI () - { - - @Override - public void installUI(JComponent c) { - super.installUI(c); - // enable mouse motion events for the layer's subcomponents - ((JLayer) c).setLayerEventMask(AWTEvent.MOUSE_EVENT_MASK); - } - - @Override - public void uninstallUI(JComponent c) { - super.uninstallUI(c); - // reset the layer event mask - ((JLayer) c).setLayerEventMask(0); - } - - @Override - public void processMouseEvent (MouseEvent ev, - JLayer l) - { - - if ((ev.isPopupTrigger ()) - && - (!_this.message.isSentByMe ()) - ) - { - - ev.consume (); - - JPopupMenu popup = new JPopupMenu (); - - popup.add (UIUtils.createMenuItem (getUIString (editors,messages,report,popupmenu,items,report), - //"Report this message", - Constants.ERROR_ICON_NAME, - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - EditorsUIUtils.showReportMessage (_this, - _this.viewer); - - } - - })); - - popup.show (_this, - ev.getX (), - ev.getY ()); - - return; - - } - - if ((!_this.message.isDealtWith ()) - && - (_this.isAutoDealtWith ()) - ) - { - - if (ev.getID () == MouseEvent.MOUSE_EXITED) - { - - Point p = SwingUtilities.convertPoint ((Component) ev.getSource (), - ev.getPoint (), - _this); - - if (!SwingUtilities.getLocalBounds (_this).contains (p)) - { - - update.stop (); - - } - - return; - - } - - if (ev.getID () == MouseEvent.MOUSE_ENTERED) - { - - update.start (); - - return; - - } - - } - - } - - })); - - this.setOpaque (false); - this.setBackground (null); - - this.content.setBackground (UIUtils.getComponentColor ()); - - this.message = mess; - this.viewer = viewer; - this.setAlignmentX (Component.LEFT_ALIGNMENT); - - this.content.setToolTipText (String.format (getUIString (editors,messages,view,tooltip,(this.message.isSentByMe () ? sent : received)), - //"%s %s", - //this.message.isSentByMe () ? "Sent" : "Received", - Environment.formatDateTime (this.message.getWhen ()))); - - } - - public abstract boolean isAutoDealtWith (); - - public AbstractViewer getChildViewer () - { - - return this.childViewer; - - } - - public void setChildViewer (AbstractViewer v) - { - - this.childViewer = v; - - } - - @Override - public Component add (Component c) - { - - if (c instanceof JLayer) - { - - return super.add (c); - - } - - return this.content.add (c); - - } - - public void setShowAttentionBorder (boolean v) - { - - this.showAttentionBorder = v; - - } - - public boolean isShowAttentionBorder () - { - - return this.showAttentionBorder; - - } - - public EditorMessage getMessage () - { - - return this.message; - - } - - public boolean isDealtWith () - { - - return this.message.isDealtWith (); - - } - - public abstract void doUpdate (); - - public abstract void doInit () - throws GeneralException; - - public String getOpenMessageLink (EditorMessage m, - String link) - { - - return String.format ("%s", - Constants.OPENEDITORMESSAGE_PROTOCOL, - m.getKey (), - link); - - } - - public void update () - { - - this.doUpdate (); - - if (this.message.isDealtWith ()) - { - - this.setToolTipText (null); - this.setBorder (null); - - } - - } - - public void init () - throws GeneralException - { - - this.doInit (); - - if ((!this.message.isDealtWith ()) - && - (this.isShowAttentionBorder ()) - ) - { - - this.setToolTipText (getUIString (editors,messages,view,attention,tooltip));//"This message needs your attention!"); - - this.setBorder (new CompoundBorder (new MatteBorder (0, 2, 0, 0, UIUtils.getColor ("#ff0000")), - UIUtils.createPadding (0, 5, 0, 0))); - - } - - // Add ourselves as a message listener in case our message gets updated in a different context. - EditorsEnvironment.addEditorMessageListener (this); - - } - - @Override - /** - * Listens for message events relating to the underlying message this box is displaying. - * If the event is for our message and the message has been changed then {@link #update()} is called. - * - * @param ev The event. - */ - public void handleMessage (EditorMessageEvent ev) - { - - // Is this message for us? - if ((ev.getMessage ().equals (this.message)) - && - (ev.getType () == EditorMessageEvent.MESSAGE_CHANGED) - ) - { - - this.update (); - - } - - } - - protected JComponent getMessageQuoteComponent (String message) - { - - Box b = new Box (BoxLayout.X_AXIS); - - ImagePanel ip = new ImagePanel (Environment.getIcon (Constants.MESSAGE_ICON_NAME, - Constants.ICON_POPUP), - null); - - ip.setAlignmentY (Component.TOP_ALIGNMENT); - - //b.add (ip); - //b.add (Box.createHorizontalStrut (5)); - - JComponent t = UIUtils.createHelpTextPane (message, - this.viewer); - t.setAlignmentY (Component.TOP_ALIGNMENT); - - t.setBorder (null); - t.setOpaque (false); - - b.add (t); - - b.setAlignmentX (Component.LEFT_ALIGNMENT); - - return b; - - } - - protected JComponent getMessageComponent (String message, - String iconName) - { - - Box b = new Box (BoxLayout.X_AXIS); - - if (iconName != null) - { - - ImagePanel ip = new ImagePanel (Environment.getIcon (iconName, - Constants.ICON_EDITOR_MESSAGE), - null); - - ip.setAlignmentY (Component.TOP_ALIGNMENT); - - b.add (ip); - b.add (Box.createHorizontalStrut (5)); - - } - - JComponent t = UIUtils.createHelpTextPane (message, - this.viewer); - t.setAlignmentY (Component.TOP_ALIGNMENT); - - t.setBorder (null); - t.setOpaque (false); - - b.add (t); - - b.setAlignmentX (Component.LEFT_ALIGNMENT); - - return b; - - } - -} diff --git a/src/com/quollwriter/editors/ui/NewProjectMessageBox.java b/src/com/quollwriter/editors/ui/NewProjectMessageBox.java deleted file mode 100644 index cc831740..00000000 --- a/src/com/quollwriter/editors/ui/NewProjectMessageBox.java +++ /dev/null @@ -1,766 +0,0 @@ -package com.quollwriter.editors.ui; - -import java.util.Date; -import java.util.List; -import java.util.ArrayList; -import java.util.Map; -import java.util.LinkedHashMap; -import java.util.Set; -import java.util.LinkedHashSet; -import java.util.Arrays; - -import java.io.*; - -import java.awt.Point; -import java.awt.event.*; -import java.awt.Component; -import java.awt.Dimension; -import javax.swing.*; -import javax.swing.border.*; - -import com.jgoodies.forms.builder.*; -import com.jgoodies.forms.factories.*; -import com.jgoodies.forms.layout.*; - -import com.quollwriter.*; -import com.quollwriter.ui.forms.*; -import com.quollwriter.ui.*; -import com.quollwriter.editors.ui.sidebars.*; -import com.quollwriter.data.*; -import com.quollwriter.ui.components.ImagePanel; -import com.quollwriter.ui.components.QPopup; -import com.quollwriter.editors.messages.*; -import com.quollwriter.editors.*; -import com.quollwriter.text.*; -import com.quollwriter.events.*; - -import static com.quollwriter.LanguageStrings.*; -import static com.quollwriter.Environment.getUIString; - -public class NewProjectMessageBox extends MessageBox implements EditorChangedListener -{ - - private Box responseBox = null; - private ProjectSentReceivedViewer sentViewer = null; - private JLabel previousLabel = null; - - public NewProjectMessageBox (NewProjectMessage mess, - AbstractViewer viewer) - { - - super (mess, - viewer); - - } - - @Override - public void editorChanged (EditorChangedEvent ev) - { - - if (ev.getEditor () == this.message.getEditor ()) - { - - this.updateForEditor (); - - } - - } - - @Override - public boolean isAutoDealtWith () - { - - return false; - - } - - @Override - public boolean isShowAttentionBorder () - { - - if (this.message.getEditor ().isPrevious ()) - { - - return false; - - } - - return super.isShowAttentionBorder (); - - } - - private void updateForEditor () - { - - this.previousLabel.setVisible (false); - - if ((!this.message.isDealtWith ()) - && - (this.message.getEditor ().isPrevious ()) - ) - { - - this.previousLabel.setText (String.format (getUIString (editors,messages,newproject,received,undealtwith,previouseditor), - //"%s is a previous {contact}. This message can no longer be acted upon.", - this.message.getEditor ().getShortName ())); - - this.previousLabel.setVisible (true); - - this.responseBox.setVisible (false); - - } - - } - - public void doUpdate () - { - - this.responseBox.setVisible (!this.message.isDealtWith ()); - - } - - public void doInit () - { - - EditorsEnvironment.addEditorChangedListener (this); - - final NewProjectMessageBox _this = this; - - String t = null; - //"Sent {project}"; - - if (!this.message.isSentByMe ()) - { - - t = getUIString (editors,messages,newproject,received,title); - //"Received an invitation to edit a {project}"; - - } else { - - t = getUIString (editors,messages,newproject,sent,title); - - } - - JComponent h = UIUtils.createBoldSubHeader (t, - Constants.PROJECT_ICON_NAME); - - this.add (h); - - JComponent bp = EditorsUIUtils.getProjectMessageDetails (this.message, - this.viewer, - this); - - bp.setBorder (UIUtils.createPadding (0, 5, 0, 5)); - - this.add (bp); - - this.responseBox = new Box (BoxLayout.Y_AXIS); - - this.responseBox.setVisible (false); - - this.add (this.responseBox); - - this.previousLabel = UIUtils.createInformationLabel (""); - - this.add (this.previousLabel); - - this.updateForEditor (); - - if ((!this.message.isDealtWith ()) - && - (!this.message.isSentByMe ()) - && - (!this.message.getEditor ().isPrevious ()) - ) - { - - this.responseBox.setVisible (true); - - JComponent l = UIUtils.createBoldSubHeader (getUIString (editors,messages,newproject,received,undealtwith,text), - //"Select your response below", - null); - - this.responseBox.add (l); - - JButton accept = UIUtils.createButton (getUIString (editors,messages,newproject,received,undealtwith,buttons,LanguageStrings.accept,text), - //"Accept", - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - // Show a message box. - _this.showResponseMessagePopup (true); - - } - - }); - - accept.setToolTipText (getUIString (editors,messages,newproject,received,undealtwith,buttons,LanguageStrings.accept,title)); - //"Click to accept the invitation"); - - JButton reject = UIUtils.createButton (getUIString (editors,messages,newproject,received,undealtwith,buttons,LanguageStrings.reject,text), - //"Reject", - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - _this.showResponseMessagePopup (false); - - } - - }); - - reject.setToolTipText (getUIString (editors,messages,newproject,received,undealtwith,buttons,LanguageStrings.reject,title)); - //"Click to reject the invitation"); - - JButton[] buts = new JButton[] { accept, reject }; - - JComponent bb = UIUtils.createButtonBar2 (buts, - Component.LEFT_ALIGNMENT); - - bb.setAlignmentX (Component.LEFT_ALIGNMENT); - - this.responseBox.add (bb); - - } - - } - - private void showResponseMessagePopup (final boolean accepted) - { - - this.handleNewProjectResponse (this.viewer, - this.message, - accepted); - - } - - public void handleNewProjectResponse ( AbstractViewer viewer, - final NewProjectMessage mess, - final boolean accepted) - { - - if (viewer == null) - { - - viewer = Environment.getFocusedViewer (); - - } - - if (accepted) - { - - java.util.List prefix = Arrays.asList (editors,messages,newproject,received,undealtwith,LanguageStrings.accepted,popup); - - final QPopup qp = UIUtils.createClosablePopup (getUIString (prefix,title), - //"Accept the invitation", - Environment.getIcon (Constants.PROJECT_ICON_NAME, - Constants.ICON_POPUP), - null); - - String rows = "p, 6px, p, 6px, p, 6px, p"; - - int row = 1; - - Box content = new Box (BoxLayout.Y_AXIS); - - content.add (UIUtils.createBoldSubHeader (getUIString (prefix,labels,where), - //"Where should the {project} be saved?", - null)); - - content.add (Box.createVerticalStrut (5)); - - File defDir = Environment.getDefaultSaveProjectDir (); - - defDir.mkdirs (); - - File nf = new File (defDir, "editor-projects/" + mess.getEditor ().getEmail ()); - - final FileFinder saveField = new FileFinder (); - - saveField.setFile (nf); - - saveField.setApproveButtonText (getUIString (prefix,finder,button)); - //"Select"); - saveField.setFinderSelectionMode (JFileChooser.DIRECTORIES_ONLY); - saveField.setFinderTitle (getUIString (prefix,finder,title)); - //"Select a directory to save to"); - - saveField.setFindButtonToolTip (getUIString (prefix,finder,tooltip)); - //"Click to find a directory"); - saveField.setClearOnCancel (true); - saveField.init (); - - final String projName = mess.getForProjectName (); - - final JCheckBox encryptField = UIUtils.createCheckBox (getUIString (prefix,labels,encrypt)); - //"Encrypt this {project}? You will be prompted for a password."); - - Set items = new LinkedHashSet<> (); - - items.add (new AnyFormItem (getUIString (prefix,labels,project), - //"{Project}", - UIUtils.createLabel (projName))); - - items.add (new AnyFormItem (getUIString (prefix,labels,save), - //"Save In", - saveField)); - - items.add (new AnyFormItem (null, - encryptField)); - - FormLayout pfl = new FormLayout ("right:p, 6px, 100px, 20px, p, 6px, fill:100px", - "p, 6px"); - pfl.setHonorsVisibility (true); - PanelBuilder pbuilder = new PanelBuilder (pfl); - - CellConstraints cc = new CellConstraints (); - - final JPasswordField passwordField = new JPasswordField (); - - pbuilder.addLabel (getUIString (prefix,labels,password), - //"Password", - cc.xy (1, - 1)); - - pbuilder.add (passwordField, - cc.xy (3, - 1)); - - final JPasswordField passwordField2 = new JPasswordField (); - - pbuilder.addLabel (getUIString (prefix,labels,confirmpassword), - //"Confirm", - cc.xy (5, - 1)); - - pbuilder.add (passwordField2, - cc.xy (7, - 1)); - - final JPanel ppanel = pbuilder.getPanel (); - ppanel.setVisible (false); - ppanel.setOpaque (false); - - items.add (new AnyFormItem (null, - ppanel)); - - encryptField.addActionListener (new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - ppanel.setVisible (encryptField.isSelected ()); - - qp.resize (); - - } - - }); - - final JLabel error = UIUtils.createErrorLabel (""); - error.setVisible (false); - error.setBorder (UIUtils.createPadding (0, 0, 5, 0)); - - Form f = UIUtils.createForm (items); - - content.add (error); - content.add (f); - - content.add (Box.createVerticalStrut (10)); - content.add (UIUtils.createBoldSubHeader (getUIString (prefix,labels,sendmessage,text), - //"Send a message back", - null)); - - final TextArea res = new TextArea (String.format (getUIString (prefix,labels,sendmessage,tooltip), - //"You can optionally return a message to %s using this box.", - mess.getEditor ().getMainName ()), - 5, - 5000); - - content.setBorder (UIUtils.createPadding (5, 0, 0, 0)); - content.add (res); - - ActionListener doSave = new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - error.setVisible (false); - - java.util.List prefix = Arrays.asList (editors,messages,newproject,received,undealtwith,LanguageStrings.accepted,popup); - - // See if the project already exists. - File pf = new File (saveField.getSelectedFile (), Utils.sanitizeForFilename (projName)); - - if (pf.exists ()) - { - - error.setText (String.format (getUIString (prefix,errors,valueexists), - //"A {project} called: %s already exists.", - projName, - pf.getPath ())); - - error.setVisible (true); - - qp.resize (); - - return; - - } - - String pwd = null; - - if (encryptField.isSelected ()) - { - - // Make sure a password has been provided. - pwd = new String (passwordField.getPassword ()).trim (); - - String pwd2 = new String (passwordField2.getPassword ()).trim (); - - if (pwd.equals ("")) - { - - error.setText (getUIString (prefix,errors,nopassword)); - //"Please provide a password for securing the {project}.")); - - error.setVisible (true); - - qp.resize (); - - return; - - } - - if (pwd2.equals ("")) - { - - error.setText (getUIString (prefix,errors,confirmpassword)); - //"Please confirm your password."); - - error.setVisible (true); - - qp.resize (); - - return; - - } - - if (!pwd.equals (pwd2)) - { - - error.setText (getUIString (prefix,errors,nomatch)); - //"The passwords do not match."); - - error.setVisible (true); - - qp.resize (); - - return; - - } - - } - - final String responseMessage = (res.getText ().trim ().length () == 0 ? null : res.getText ().trim ()); - - mess.setResponseMessage (responseMessage); - - // Create the project. - Project p = null; - - try - { - - p = mess.createProject (); - - } catch (Exception e) { - - Environment.logError ("Unable to create project from message: " + - mess, - e); - - UIUtils.showErrorMessage (Environment.getFocusedViewer (), - getUIString (editors,messages,newproject,received,undealtwith,LanguageStrings.accepted,actionerror)); - //"Unable to save {project}, please contact Quoll Writer support for assistance."); - - return; - - } - - final Project fproj = p; - - // Put it in the user's directory. - try - { - - // We create the project but then close the connection pool since the user - // may not want to open the project yet. - Environment.createProject (saveField.getSelectedFile (), - p, - pwd).closeConnectionPool (); - - } catch (Exception e) { - - Environment.logError ("Unable to save editor project to: " + - saveField.getSelectedFile () + - ", message: " + - mess, - e); - - UIUtils.showErrorMessage (Environment.getFocusedViewer (), - getUIString (editors,messages,newproject,received,undealtwith,LanguageStrings.accepted,actionerror)); - //"Unable to save {project}, please contact Quoll Writer support for assistance."); - - return; - - } - - mess.setDealtWith (true); - - ActionListener onComplete = new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - qp.removeFromParent (); - - mess.setAccepted (accepted); - mess.setDealtWith (true); - mess.setResponseMessage (responseMessage); - - try - { - - // Update the original message. - EditorsEnvironment.updateMessage (mess); - - } catch (Exception e) { - - Environment.logError ("Unable to update message: " + - mess, - e); - - UIUtils.showErrorMessage (Environment.getFocusedViewer (), - getUIString (editors,messages,newproject,received,undealtwith,LanguageStrings.accepted,actionerror)); - //"Unable to update message, please contact Quoll Writer support for assistance."); - - // Should really carry on... maybe... - - } - - // Ask if they want to open the project now. - UIUtils.createQuestionPopup (Environment.getFocusedViewer (), - getUIString (editors,messages,newproject,received,undealtwith,LanguageStrings.accepted,openproject,popup,title), - //"Open the {project}?", - Constants.OPEN_PROJECT_ICON_NAME, - getUIString (editors,messages,newproject,received,undealtwith,LanguageStrings.accepted,openproject,popup,text), - //"Open the {project} now?", - getUIString (editors,messages,newproject,received,undealtwith,LanguageStrings.accepted,openproject,popup,buttons,confirm), - //"Yes, open it", - getUIString (editors,messages,newproject,received,undealtwith,LanguageStrings.accepted,openproject,popup,buttons,cancel), - //"Not now", - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - try - { - - Environment.openProject (fproj, - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - // Show the first chapter. - AbstractProjectViewer pv = Environment.getProjectViewer (fproj); - - if (pv != null) - { - - pv.viewObject (pv.getProject ().getBook (0).getChapters ().get (0)); - - } - - } - - }); - - } catch (Exception e) { - - Environment.logError ("Unable to open project: " + - fproj, - e); - - UIUtils.showErrorMessage (Environment.getFocusedViewer (), - getUIString (editors,messages,newproject,received,undealtwith,LanguageStrings.accepted,openproject,actionerror)); - //"Unable to open {project}: " + fproj.getName () + " please contact Quoll Support for assistance."); - - } - - } - - }, - null, - null, - null); - - } - - }; - - NewProjectResponseMessage res = new NewProjectResponseMessage (mess.getForProjectId (), - true, - responseMessage, - mess.getEditor (), - EditorsEnvironment.getUserAccount ()); - - if (mess.getEditor ().isPending ()) - { - - EditorsEnvironment.acceptInvite (mess.getEditor (), - res, - onComplete); - - } else { - - EditorsEnvironment.sendMessageToEditor (res, - onComplete, - null, - null); - - } - - } - - }; - - JButton save = UIUtils.createButton (getUIString (prefix,buttons,LanguageStrings.save), - //"Save {project}", - doSave); - - UIUtils.addDoActionOnReturnPressed (res, - doSave); - - JButton cancel = UIUtils.createButton (getUIString (prefix,buttons,LanguageStrings.cancel), - //Environment.getButtonLabel (Constants.CANCEL_BUTTON_LABEL_ID), - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - qp.removeFromParent (); - - } - - }); - - JButton[] buts = new JButton[] { save, cancel }; - - JComponent bs = UIUtils.createButtonBar2 (buts, - Component.LEFT_ALIGNMENT); - bs.setAlignmentX (Component.LEFT_ALIGNMENT); - - content.add (Box.createVerticalStrut (10)); - content.add (bs); - content.setBorder (new EmptyBorder (10, 10, 10, 10)); - - qp.setContent (content); - - content.setPreferredSize (new Dimension (UIUtils.getPopupWidth (), - content.getPreferredSize ().height)); - - Point showAt = UIUtils.getCenterShowPosition (viewer, - qp); - - viewer.showPopupAt (qp, - showAt, - false); - - qp.setDraggable (viewer); - - } else { - - // Ask for a response? - final String responseMessage = null; - - mess.setDealtWith (true); - - ActionListener onComplete = new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - mess.setAccepted (accepted); - mess.setDealtWith (true); - mess.setResponseMessage (responseMessage); - - try - { - - // Update the original message. - EditorsEnvironment.updateMessage (mess); - - } catch (Exception e) { - - Environment.logError ("Unable to update message: " + - mess, - e); - - UIUtils.showErrorMessage (Environment.getFocusedViewer (), - getUIString (editors,messages,update,actionerror)); - //"Unable to update message, please contact Quoll Writer support for assistance."); - - // Should really carry on... maybe... - - } - - } - - }; - - NewProjectResponseMessage res = new NewProjectResponseMessage (mess.getForProjectId (), - false, - responseMessage, - mess.getEditor (), - EditorsEnvironment.getUserAccount ()); - - if (mess.getEditor ().isPending ()) - { - - EditorsEnvironment.rejectInvite (mess.getEditor (), - res, - onComplete); - - } else { - - EditorsEnvironment.sendMessageToEditor (res, - onComplete, - null, - null); - - } - - } - - } - -} diff --git a/src/com/quollwriter/editors/ui/NewProjectResponseMessageBox.java b/src/com/quollwriter/editors/ui/NewProjectResponseMessageBox.java deleted file mode 100644 index 9bcb0df0..00000000 --- a/src/com/quollwriter/editors/ui/NewProjectResponseMessageBox.java +++ /dev/null @@ -1,669 +0,0 @@ -package com.quollwriter.editors.ui; - -import java.util.List; -import java.util.ArrayList; - -import java.awt.event.*; -import java.awt.Component; -import java.awt.Dimension; -import javax.swing.*; -import javax.swing.border.*; - -import com.jgoodies.forms.builder.*; -import com.jgoodies.forms.factories.*; -import com.jgoodies.forms.layout.*; - -import com.quollwriter.*; -import com.quollwriter.ui.*; -import com.quollwriter.data.*; -import com.quollwriter.data.editors.*; -import com.quollwriter.ui.components.ImagePanel; -import com.quollwriter.ui.components.ActionAdapter; -import com.quollwriter.editors.messages.*; -import com.quollwriter.editors.*; - -import static com.quollwriter.LanguageStrings.*; -import static com.quollwriter.Environment.getUIString; - -// Use an annotation? -//@MessageBox(class=NewProjectResponseMessage) -public class NewProjectResponseMessageBox extends MessageBox -{ - - private Box responseBox = null; - - public NewProjectResponseMessageBox (NewProjectResponseMessage mess, - AbstractViewer viewer) - { - - super (mess, - viewer); - - } - - public boolean isAutoDealtWith () - { - - return false; - - } - - public void doUpdate () - { - - if (this.message.isDealtWith ()) - { - - if (this.responseBox != null) - { - - this.responseBox.setVisible (false); - - } - - } - - } - - public void doInit () - { - - final NewProjectResponseMessageBox _this = this; - - ProjectInfo proj = null; - - try - { - - proj = Environment.getProjectById (this.message.getForProjectId (), - (this.message.isSentByMe () ? Project.EDITOR_PROJECT_TYPE : Project.NORMAL_PROJECT_TYPE)); - - } catch (Exception e) { - - Environment.logError ("Unable to get project: " + - this.message.getForProjectId (), - e); - - } - - final EditorEditor ed = this.message.getEditor (); - - ProjectEditor pe = null; - - if (proj != null) - { - - try - { - - pe = EditorsEnvironment.getProjectEditor (proj, - ed); - - } catch (Exception e) { - - Environment.logError ("Unable to get project editor for project: " + - proj + - ", editor: " + - ed, - e); - - } - - } - - final ProjectEditor fpe = pe; - - // Only do this if the editor is still pending. - if ((!this.message.isDealtWith ()) - && - (this.message.getEditor ().isPending ()) - ) - { - - // Show the response. - this.responseBox = new Box (BoxLayout.Y_AXIS); - - this.add (this.responseBox); - - JComponent l = UIUtils.createBoldSubHeader (getUIString (editors,messages,newprojectresponse,received,(this.message.isAccepted () ? accepted : rejected),title), - //String.format ("%s the {project}", - // (this.message.isAccepted () ? "Accepted" : "Rejected")), - (this.message.isAccepted () ? Constants.ACCEPTED_ICON_NAME : Constants.REJECTED_ICON_NAME)); - - this.responseBox.add (l); - this.responseBox.setBorder (UIUtils.createPadding (5, 5, 0, 5)); - - this.responseBox.add (this.getResponseDetails ()); - - if (this.message.isAccepted ()) - { - - if ((this.message.getEditorName () != null) - || - (this.message.getEditorAvatar () != null) - ) - { - - JTextPane desc = UIUtils.createHelpTextPane (getUIString (editors,messages,newprojectresponse,labels,extra), - //"Additionally they provided the following name/avatar.", - this.viewer); - - this.responseBox.add (Box.createVerticalStrut (5)); - - this.responseBox.add (desc); - desc.setBorder (null); - desc.setSize (new Dimension (UIUtils.getPopupWidth () - 20, - desc.getPreferredSize ().height)); - - Box editorInfo = new Box (BoxLayout.X_AXIS); - editorInfo.setAlignmentX (Component.LEFT_ALIGNMENT); - editorInfo.setBorder (UIUtils.createPadding (5, 5, 5, 5)); - - this.responseBox.add (editorInfo); - - if (this.message.getEditorAvatar () != null) - { - - JLabel avatar = new JLabel (); - - avatar.setAlignmentY (Component.TOP_ALIGNMENT); - avatar.setVerticalAlignment (SwingConstants.TOP); - - editorInfo.add (avatar); - avatar.setOpaque (false); - - avatar.setIcon (new ImageIcon (UIUtils.getScaledImage (_this.message.getEditorAvatar (), - 50))); - - avatar.setBorder (new CompoundBorder (UIUtils.createPadding (0, 0, 0, 5), - UIUtils.createLineBorder ())); - - } - - if (this.message.getEditorName () != null) - { - - JLabel name = new JLabel (this.message.getEditorName ()); - editorInfo.add (name); - - name.setBorder (null); - name.setAlignmentY (Component.TOP_ALIGNMENT); - name.setVerticalAlignment (JLabel.TOP); - name.setAlignmentX (Component.LEFT_ALIGNMENT); - name.setFont (name.getFont ().deriveFont ((float) UIUtils.getScaledFontSize (14)).deriveFont (java.awt.Font.PLAIN)); - - } - - } - - } - - JButton ok = UIUtils.createButton (getUIString (editors,messages,newprojectresponse,received,undealtwith,buttons,confirm)); - //"Ok, got it"); - - ok.addActionListener (new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - try - { - - if (_this.message.isAccepted ()) - { - - ed.setEditorStatus (EditorEditor.EditorStatus.current); - - if (_this.message.getEditorName () != null) - { - - ed.setName (_this.message.getEditorName ()); - - } - - if (_this.message.getEditorAvatar () != null) - { - - ed.setAvatar (_this.message.getEditorAvatar ()); - - } - - EditorsEnvironment.updateEditor (ed); - - fpe.setStatusMessage (String.format (getUIString (editors,messages,newprojectresponse,received,editorstatus,accepted), - //"Accepted {project}: %s", - Environment.formatDate (_this.message.getWhen ()))); - fpe.setEditorFrom (_this.message.getWhen ()); - fpe.setCurrent (true); - fpe.setStatus (ProjectEditor.Status.accepted); - - EditorsEnvironment.updateProjectEditor (fpe); - - } else { - - ed.setEditorStatus (EditorEditor.EditorStatus.rejected); - - EditorsEnvironment.updateEditor (ed); - - if (fpe != null) - { - - try - { - - EditorsEnvironment.removeProjectEditor (fpe); - - } catch (Exception e) { - - Environment.logError ("Unable to remove project editor: " + - fpe, - e); - - } - - } - - } - - _this.message.setDealtWith (true); - - EditorsEnvironment.updateMessage (_this.message); - - _this.responseBox.setVisible (false); - - } catch (Exception e) { - - Environment.logError ("Unable to update editor: " + - ed, - e); - - UIUtils.showErrorMessage (_this.viewer, - getUIString (editors,editor,edit,actionerror)); - //"Unable to update {editor}, please contact Quoll Writer support for assistance."); - - return; - - } - - } - - }); - - JButton[] buts = new JButton[] { ok }; - - JPanel bb = UIUtils.createButtonBar2 (buts, - Component.LEFT_ALIGNMENT); - bb.setOpaque (false); - bb.setAlignmentX (Component.LEFT_ALIGNMENT); - bb.setBorder (UIUtils.createPadding (5, 0, 0, 0)); - - this.responseBox.add (bb); - - return; - - } - - boolean accepted = this.message.isAccepted (); - //String resMessage = this.message.getResponseMessage (); - - String iconName = (accepted ? Constants.ACCEPTED_ICON_NAME : Constants.REJECTED_ICON_NAME); - - String t = ""; - - if (this.message.isSentByMe ()) - { - - //String text = "Accepted"; - - if (!accepted) - { - - t = getUIString (editors,messages,newprojectresponse,sent,rejected,title); - - //text = "Rejected"; - - } else { - - t = getUIString (editors,messages,newprojectresponse,sent,LanguageStrings.accepted,title); - - } - - //message = text + " {project}"; - - } else { - - //message = "{Project} accepted"; - - if (!accepted) - { - - t = getUIString (editors,messages,newprojectresponse,received,rejected,title); - - //message = "{Project} rejected"; - - } else { - - t = getUIString (editors,messages,newprojectresponse,received,LanguageStrings.accepted,title); - - } - - } - - JComponent h = UIUtils.createBoldSubHeader (t, - iconName); - - this.add (h); - - this.add (this.getResponseDetails ()); - - if ((this.message.isSentByMe ()) - && - (proj != null) - ) - { - - JLabel viewProj = UIUtils.createClickableLabel (getUIString (editors,messages,newprojectresponse,sent,labels,clicktoview), - //"Click to view the {project}", - Environment.getIcon (Constants.VIEW_ICON_NAME, - Constants.ICON_CLICKABLE_LABEL), - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - ProjectInfo proj = null; - - try - { - - proj = Environment.getProjectById (_this.message.getForProjectId (), - Project.EDITOR_PROJECT_TYPE); - - } catch (Exception e) { - - Environment.logError ("Unable to get project: " + - _this.message.getForProjectId (), - e); - - UIUtils.showErrorMessage (Environment.getFocusedViewer (), - String.format (getUIString (project,actions,openproject,openerrors,general), - _this.message.getForProjectId (), - getUIString (project,actions,openproject,openerrors,unspecified))); - //"Unable to open {project}, please contact Quoll Writer support for assistance."); - - return; - - } - - try - { - - Environment.openProject (proj); - - } catch (Exception e) { - - Environment.logError ("Unable to get project: " + - _this.message.getForProjectId (), - e); - - UIUtils.showErrorMessage (Environment.getFocusedViewer (), - String.format (getUIString (project,actions,openproject,openerrors,general), - _this.message.getForProjectId (), - getUIString (project,actions,openproject,openerrors,unspecified))); - //"Unable to open {project}, please contact Quoll Writer support for assistance."); - - return; - - } - - } - - }); - - viewProj.setBorder (UIUtils.createPadding (5, 10, 5, 5)); - - this.add (viewProj); - - } - - if ((!this.message.isSentByMe ()) - && - (!this.message.isDealtWith ()) - ) - { - - final Box b = new Box (BoxLayout.Y_AXIS); - b.setAlignmentX (Component.LEFT_ALIGNMENT); - - JButton ok = UIUtils.createButton (getUIString (editors,messages,newprojectresponse,received,undealtwith,buttons,confirm)); - //"Ok, got it"); - - ok.addActionListener (new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - try - { - - if (_this.message.isAccepted ()) - { - - fpe.setStatus (ProjectEditor.Status.accepted); - - fpe.setEditorFrom (_this.message.getWhen ()); - fpe.setCurrent (true); - fpe.setStatusMessage (String.format (getUIString (editors,messages,newprojectresponse,received,editorstatus,LanguageStrings.accepted), - //"Accepted {project}: %s", - Environment.formatDate (_this.message.getWhen ()))); - - EditorsEnvironment.updateProjectEditor (fpe); - - } else { - - fpe.setCurrent (false); - fpe.setStatusMessage (String.format (getUIString (editors,messages,newprojectresponse,received,editorstatus,rejected), - //"Rejected {project}: %s", - Environment.formatDate (_this.message.getWhen ()))); - - EditorsEnvironment.removeProjectEditor (fpe); - - } - - _this.message.setDealtWith (true); - - EditorsEnvironment.updateMessage (_this.message); - - b.setVisible (false); - - UIUtils.resizeParent (b); - - b.getParent ().remove (b); - - } catch (Exception e) { - - Environment.logError ("Unable to update message: " + - _this.message, - e); - - UIUtils.showErrorMessage (_this.viewer, - getUIString (editors,messages,update,actionerror)); - //"Unable to update message, please contact Quoll Writer support for assistance."); - - return; - - } - - } - - }); - - JButton[] buts = new JButton[] { ok }; - - JPanel bb = UIUtils.createButtonBar2 (buts, - Component.LEFT_ALIGNMENT); - bb.setOpaque (false); - bb.setAlignmentX (Component.LEFT_ALIGNMENT); - bb.setBorder (UIUtils.createPadding (5, 10, 0, 0)); - - b.add (bb); - - this.add (b); - - } - - } - - private JComponent getResponseDetails () - { - - final NewProjectResponseMessageBox _this = this; - - String rows = "top:p"; - - String resMessage = this.message.getResponseMessage (); - - if (resMessage != null) - { - - rows += ", 6px, top:p"; - - } - - FormLayout fl = new FormLayout ("right:p, 6px, fill:100px:grow", - rows); - - fl.setHonorsVisibility (true); - PanelBuilder builder = new PanelBuilder (fl); - - CellConstraints cc = new CellConstraints (); - - int row = 1; - - builder.addLabel ("" + getUIString (editors,messages,newprojectresponse,labels,project) + "", - //Environment.replaceObjectNames ("{Project}"), - cc.xy (1, - row)); - - ProjectInfo proj = null; - - try - { - - proj = Environment.getProjectById (this.message.getForProjectId (), - (this.message.isSentByMe () ? Project.EDITOR_PROJECT_TYPE : Project.NORMAL_PROJECT_TYPE)); - - } catch (Exception e) { - - Environment.logError ("Unable to get project: " + - this.message.getForProjectId (), - e); - - } - - if (proj != null) - { - - JLabel openProj = UIUtils.createClickableLabel (proj.getName (), - null, - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - ProjectInfo proj = null; - - try - { - - proj = Environment.getProjectById (_this.message.getForProjectId (), - (_this.message.isSentByMe () ? Project.EDITOR_PROJECT_TYPE : Project.NORMAL_PROJECT_TYPE)); - - } catch (Exception e) { - - Environment.logError ("Unable to get project: " + - _this.message.getForProjectId (), - e); - - } - - if (proj != null) - { - - try - { - - Environment.openProject (proj); - - } catch (Exception e) { - - Environment.logError ("Unable to open project: " + - proj, - e); - - } - - } - - } - - }); - - openProj.setToolTipText (getUIString (project,actions,openproject,tooltips,general)); - //Environment.replaceObjectNames ("Click to open the {project}")); - - builder.add (openProj, - cc.xy (3, - row)); - - } else { - - NewProjectMessage m = (NewProjectMessage) this.message.getEditor ().getMessage (NewProjectMessage.MESSAGE_TYPE, - this.message.getForProjectId ()); - - if (m != null) - { - - builder.addLabel (m.getForProjectName (), - cc.xy (3, - row)); - - } - - } - - row += 2; - - if (resMessage != null) - { - - builder.addLabel ("" + getUIString (editors,messages,newprojectresponse,labels,LanguageStrings.message) + "", - //Environment.replaceObjectNames ("{Message}"), - cc.xy (1, - row)); - - JComponent nc = UIUtils.createHelpTextPane (resMessage, - this.viewer); - nc.setBorder (null); - - builder.add (nc, - cc.xy (3, - row)); - - } - - JPanel bp = builder.getPanel (); - bp.setOpaque (false); - bp.setAlignmentX (JComponent.LEFT_ALIGNMENT); - bp.setAlignmentY (JComponent.TOP_ALIGNMENT); - bp.setBorder (UIUtils.createPadding (0, 5, 0, 5)); - - return bp; - - } - -} diff --git a/src/com/quollwriter/editors/ui/ProjectCommentsChaptersAccordionItem.java b/src/com/quollwriter/editors/ui/ProjectCommentsChaptersAccordionItem.java deleted file mode 100644 index c1e8298e..00000000 --- a/src/com/quollwriter/editors/ui/ProjectCommentsChaptersAccordionItem.java +++ /dev/null @@ -1,353 +0,0 @@ -package com.quollwriter.editors.ui; - -import java.awt.Component; -import java.awt.Point; -import java.awt.event.*; -import java.awt.dnd.*; - -import java.util.Date; -import java.util.Set; -import java.util.List; -import java.util.ArrayList; -import java.util.Enumeration; -import java.util.Arrays; - -import javax.swing.*; -import javax.swing.tree.*; - -import com.quollwriter.data.*; -import com.quollwriter.*; -import com.quollwriter.ui.*; -import com.quollwriter.ui.sidebars.*; -import com.quollwriter.ui.actionHandlers.*; -import com.quollwriter.ui.components.ActionAdapter; -import com.quollwriter.ui.renderers.*; -import com.quollwriter.editors.ui.panels.*; - -import static com.quollwriter.LanguageStrings.*; -import static com.quollwriter.Environment.getUIString; - -// TODO: Make abstract ProjectSentReceivedChaptersAccordionItem, maybe move into ProjectSentReceivedSideBar. -public class ProjectCommentsChaptersAccordionItem extends ProjectObjectsAccordionItem -{ - - public ProjectCommentsChaptersAccordionItem (ProjectSentReceivedViewer pv) - { - - super ("", - Constants.COMMENT_ICON_NAME, - pv); - - } - - @Override - public String getId () - { - - return null; - - } - - @Override - public DragActionHandler getTreeDragActionHandler (ProjectSentReceivedViewer pv) - { - - return null; - - } - - protected void handleViewObject (TreePath tp, - Object obj) - { - - if (obj instanceof Chapter) - { - - Chapter c = (Chapter) obj; - - if (c.getNotes ().size () > 0) - { - - Note n = c.getNotes ().iterator ().next (); - - this.viewer.viewObject (n); - - this.tree.expandPath (UIUtils.getTreePathForUserObject ((DefaultMutableTreeNode) this.tree.getModel ().getRoot (), - c)); - - return; - - } - - } - - this.viewer.viewObject ((DataObject) obj); - - } - - @Override - public void reloadTree () - { - - ((DefaultTreeModel) tree.getModel ()).setRoot (EditorsUIUtils.createTree (this.viewer.getProject (), - null, - null, - false)); - - } - - @Override - public void initTree () - { - - DefaultMutableTreeNode root = (DefaultMutableTreeNode) EditorsUIUtils.createTree (this.viewer.getProject (), - null, - null, - false); - - ((DefaultTreeModel) this.tree.getModel ()).setRoot (root); - - this.tree.expandPath (UIUtils.getTreePathForUserObject (root, - this.viewer.getProject ().getBook (0).getChapters ().get (0))); - - } - - public boolean showItemCountOnHeader () - { - - return true; - - } - - @Override - public void fillTreePopupMenu (JPopupMenu m, - MouseEvent ev) - { - - java.util.List prefix = Arrays.asList (editors,projectcomments,sidebar,comments,treepopupmenu); - - final TreePath tp = this.tree.getPathForLocation (ev.getX (), - ev.getY ()); - - final ProjectCommentsChaptersAccordionItem _this = this; - - final AbstractProjectViewer pv = this.viewer; - - final DefaultMutableTreeNode node = (DefaultMutableTreeNode) tp.getLastPathComponent (); - - JMenuItem mi = null; - - if (tp != null) - { - - final DataObject d = (DataObject) node.getUserObject (); - - if (d instanceof Note) - { - - final Note n = (Note) d; - - // Is this a project we have sent? - if (!this.viewer.getMessage ().isSentByMe ()) - { - - m.add (UIUtils.createMenuItem (getUIString (prefix,comment,items,(n.isDealtWith () ? undealtwith : dealtwith)), - //String.format ("Set %s with", - // (n.isDealtWith () ? "undealt" : "dealt")), - Constants.VIEW_ICON_NAME, - new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - n.setDealtWith (n.isDealtWith () ? null : new Date ()); - - _this.update (); - - } - - })); - - } - - m.add (UIUtils.createMenuItem (getUIString (prefix,comment,items,view), - //"View", - Constants.VIEW_ICON_NAME, - new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - pv.viewObject (n); - - } - - })); - - } - - if (d instanceof Chapter) - { - - final Chapter c = (Chapter) d; - - final String chapterObjTypeName = Environment.getObjectTypeName (c); - - // Is this a project we have sent? - if (!this.viewer.getMessage ().isSentByMe ()) - { - - int nc = 0; - - final Set notes = c.getNotes (); - - for (Note n : notes) - { - - if (n.isDealtWith ()) - { - - nc++; - - } - - } - - if (nc > 0) - { - - m.add (UIUtils.createMenuItem (getUIString (prefix,Chapter.OBJECT_TYPE,items,undealtwith), - //"Set all undealt with", - Constants.SET_UNDEALT_WITH_ICON_NAME, - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - for (Note n : notes) - { - - n.setDealtWith (null); - - } - - _this.update (); - - } - - })); - - } - - if (nc != notes.size ()) - { - - m.add (UIUtils.createMenuItem (getUIString (prefix,Chapter.OBJECT_TYPE,items,dealtwith), - //"Set all dealt with", - Constants.SET_DEALT_WITH_ICON_NAME, - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - Date d = new Date (); - - for (Note n : notes) - { - - n.setDealtWith (d); - - } - - _this.update (); - - } - - })); - - } - - } - - m.add (UIUtils.createMenuItem (getUIString (prefix,Chapter.OBJECT_TYPE,items,view), - //"View {Chapter}", - Constants.EDIT_ICON_NAME, - pv.getAction (ProjectViewer.EDIT_CHAPTER_ACTION, - c))); - - m.add (UIUtils.createMenuItem (getUIString (prefix,Chapter.OBJECT_TYPE,items,close), - //"Close {Chapter}", - Constants.CLOSE_ICON_NAME, - new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - pv.closePanel (c); - - } - - })); - - } - - } - - } - - @Override - public TreeCellEditor getTreeCellEditor (ProjectSentReceivedViewer pv) - { - - return null; - - } - - @Override - public int getItemCount () - { - - return 0; - - } - - @Override - public int getViewObjectClickCount (Object d) - { - - return 1; - - } - - @Override - public boolean isAllowObjectPreview () - { - - return true; - - } - - @Override - public boolean isTreeEditable () - { - - return false; - - } - - @Override - public boolean isDragEnabled () - { - - return false; - - } - -} diff --git a/src/com/quollwriter/editors/ui/ProjectCommentsMessageBox.java b/src/com/quollwriter/editors/ui/ProjectCommentsMessageBox.java deleted file mode 100644 index a015f0b8..00000000 --- a/src/com/quollwriter/editors/ui/ProjectCommentsMessageBox.java +++ /dev/null @@ -1,450 +0,0 @@ -package com.quollwriter.editors.ui; - -import java.util.List; -import java.util.ArrayList; -import java.util.Set; -import java.util.Map; -import java.util.HashMap; - -import java.awt.event.*; -import java.awt.Component; -import java.awt.Dimension; -import java.awt.Point; -import javax.swing.*; -import javax.swing.border.*; -import javax.swing.tree.*; - -import com.jgoodies.forms.builder.*; -import com.jgoodies.forms.factories.*; -import com.jgoodies.forms.layout.*; - -import com.quollwriter.*; -import com.quollwriter.ui.*; -import com.quollwriter.text.*; -import com.quollwriter.data.*; -import com.quollwriter.ui.components.ImagePanel; -import com.quollwriter.editors.messages.*; -import com.quollwriter.editors.*; -import com.quollwriter.data.editors.*; - -import static com.quollwriter.LanguageStrings.*; -import static com.quollwriter.Environment.getUIString; - -//@MessageBoxFor(Message=ProjectCommentsMessage.class) -public class ProjectCommentsMessageBox extends MessageBox -{ - - private JComponent commentsTree = null; - private AbstractProjectViewer commentsViewer = null; - - public ProjectCommentsMessageBox (ProjectCommentsMessage mess, - AbstractViewer viewer) - { - - super (mess, - viewer); - - } - - public boolean isAutoDealtWith () - { - - return false; - - } - - public void doUpdate () - { - - } - - public void doInit () - throws GeneralException - { - - final ProjectCommentsMessageBox _this = this; - - ProjectInfo proj = null; - - try - { - - proj = Environment.getProjectById (this.message.getForProjectId (), - (this.message.isSentByMe () ? Project.EDITOR_PROJECT_TYPE : Project.NORMAL_PROJECT_TYPE)); - - } catch (Exception e) { - - Environment.logError ("Unable to get project info for project with id: " + - this.message.getForProjectId (), - e); - - } - - final String text = String.format (getUIString (editors,messages,projectcomments,(this.message.isSentByMe () ? sent : received),title), - //"%s {Comment%s} %s", // %s - this.message.getComments ().size ()); - //(this.message.getComments ().size () > 1 ? "s" : ""), - //(this.message.isSentByMe () ? "sent" : "received")); - - JComponent h = UIUtils.createBoldSubHeader (text, - Constants.COMMENT_ICON_NAME); - - this.add (h); - - // Show - // * Sent/Received - // * Version (optional) - // * Notes (optional) - // * View comments - - ProjectVersion pv = this.message.getProjectVersion (); - String genComm = this.message.getGeneralComment (); - - String verName = pv.getName (); - - String rows = "p, 6px, p"; - - if (verName != null) - { - - rows += ", 6px, p"; - - } - - if (genComm != null) - { - - rows += ", 6px, top:p"; - - } - - rows += ", 6px, p"; - - EditorEditor ed = this.message.getEditor (); - - // We are wimping out here - String projVerName = this.message.getProjectVersion ().getName (); - - String projVerId = this.message.getProjectVersion ().getId (); - - FormLayout fl = new FormLayout ("right:p, 6px, fill:100px:grow", - rows); - - fl.setHonorsVisibility (true); - PanelBuilder builder = new PanelBuilder (fl); - - CellConstraints cc = new CellConstraints (); - - int row = 1; - - builder.addLabel ("" + getUIString (editors,messages,projectcomments,labels,project) + "", - cc.xy (1, - row)); - - if (proj != null) - { - - JLabel openProj = UIUtils.createClickableLabel (message.getForProjectName (), - null, - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - ProjectInfo proj = null; - - try - { - - proj = Environment.getProjectById (_this.message.getForProjectId (), - (_this.message.isSentByMe () ? Project.EDITOR_PROJECT_TYPE : Project.NORMAL_PROJECT_TYPE)); - - } catch (Exception e) { - - Environment.logError ("Unable to get project info for project with id: " + - _this.message.getForProjectId (), - e); - - } - - if (proj != null) - { - - try - { - - Environment.openProject (proj); - - } catch (Exception e) { - - Environment.logError ("Unable to open project: " + - proj, - e); - - } - - } - - } - - }); - - openProj.setToolTipText (getUIString (editors,messages,projectcomments,labels,clicktoviewproject)); - //Environment.replaceObjectNames ("Click to open the {project}")); - - builder.add (openProj, - cc.xy (3, - row)); - - } else { - - builder.addLabel (String.format ("%s", - message.getForProjectName ()), - cc.xy (3, - row)); - - } - - row += 2; - - builder.addLabel ("" + getUIString (editors,messages,projectcomments,labels,(this.message.isSentByMe () ? sent : received)) + "", - //(this.message.isSentByMe () ? "Sent" : "Received")), - cc.xy (1, - row)); - - builder.addLabel (Environment.formatDateTime (this.message.getWhen ()), - cc.xy (3, - row)); - - row += 2; - - if (verName != null) - { - - builder.addLabel ("" + getUIString (editors,messages,projectcomments,labels,version) + "", - cc.xy (1, - row)); - - builder.addLabel (projVerName, - cc.xy (3, - row)); - - row += 2; - - } - - if (genComm != null) - { - - TextIterator ti = new TextIterator (genComm); - - if (ti.getSentenceCount () > 1) - { - - genComm = ti.getFirstSentence ().getText (); - - } - - JComponent mess = UIUtils.createHelpTextPane (genComm, - _this.viewer); - - mess.setBorder (null); - - builder.addLabel ("" + getUIString (editors,messages,projectcomments,labels,notes) + "", - cc.xy (1, - row)); - - builder.add (mess, - cc.xy (3, - row)); - - row += 2; - - } - - if (proj != null) - { - - JLabel viewComments = UIUtils.createClickableLabel (getUIString (editors,messages,projectcomments,labels,clicktoviewcomments), - //"Click to view the {comments}", - Environment.getIcon (Constants.VIEW_ICON_NAME, - Constants.ICON_CLICKABLE_LABEL), - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.message.setDealtWith (true); - - try - { - - EditorsEnvironment.updateMessage (_this.message); - - } catch (Exception e) { - - Environment.logError ("Unable to update message: " + - _this.message, - e); - - } - - if (_this.commentsViewer != null) - { - - _this.commentsViewer.setExtendedState (JFrame.NORMAL); - _this.commentsViewer.toFront (); - - return; - - } - - EditorsUIUtils.showProjectComments (_this.message, - _this.viewer, - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.commentsViewer = (AbstractProjectViewer) ev.getSource (); - - _this.commentsViewer.addWindowListener (new WindowAdapter () - { - - public void windowClosed (WindowEvent ev) - { - - _this.commentsViewer = null; - - } - - }); - - } - - }); - -/* - if (_this.message.isSentByMe ()) - { - - // Show a popup with the comments in it. - - Project p = _this.projectViewer.getProject (); - - // Need to now "fill out" the chapters and notes to have the correct values. - // We use the ids to get the keys. - for (Chapter c : _this.message.getChapters ()) - { - - NamedObject ch = (NamedObject) p.getObjectById (Chapter.class, - c.getId ()); - - if (ch != null) - { - - c.setName (ch.getName ()); - - } - - } - - JTree tree = EditorsUIUtils.createViewTree (_this.message.getChapters (), - _this.projectViewer); - - UIUtils.expandAllNodesWithChildren (tree); - - Dimension pref = tree.getPreferredSize (); - - if (pref.height > 300) - { - - pref.height = 300; - - } else { - - pref.height += 5; - - } - - final JScrollPane sp = UIUtils.createScrollPane (tree); - - sp.setPreferredSize (pref); - sp.setBorder (UIUtils.createPadding (5, 0, 0, 0)); - - UIUtils.createClosablePopup (text, - Environment.getIcon (Constants.COMMENT_ICON_NAME, - Constants.ICON_POPUP), - null, - sp, - _this.viewer, - null); - - } else { - - if (_this.commentsViewer != null) - { - - _this.commentsViewer.setExtendedState (JFrame.NORMAL); - _this.commentsViewer.toFront (); - - return; - - } - - EditorsUIUtils.showProjectComments (_this.message, - _this.viewer, - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.commentsViewer = (AbstractProjectViewer) ev.getSource (); - - _this.commentsViewer.addWindowListener (new WindowAdapter () - { - - public void windowClosed (WindowEvent ev) - { - - _this.commentsViewer = null; - - } - - }); - - } - - }); - - } - */ - } - - }); - - viewComments.setBorder (UIUtils.createPadding (0, 10, 0, 0)); - - builder.add (viewComments, - cc.xywh (1, - row, - 3, - 1)); - - } - - JPanel bp = builder.getPanel (); - bp.setOpaque (false); - bp.setAlignmentX (JComponent.LEFT_ALIGNMENT); - - bp.setBorder (UIUtils.createPadding (0, 5, 0, 5)); - - this.add (bp); - - } - -} diff --git a/src/com/quollwriter/editors/ui/ProjectCommentsViewer.java b/src/com/quollwriter/editors/ui/ProjectCommentsViewer.java deleted file mode 100644 index 6ed08f20..00000000 --- a/src/com/quollwriter/editors/ui/ProjectCommentsViewer.java +++ /dev/null @@ -1,278 +0,0 @@ -package com.quollwriter.editors.ui; - -import java.awt.*; -import java.awt.dnd.*; -import java.awt.event.*; - -import java.net.*; - -import java.security.*; - -import java.text.*; - -import java.util.ArrayList; -import java.util.Date; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedHashSet; -import java.util.TreeSet; -import java.util.Map; -import java.util.Set; -import java.util.StringTokenizer; -import java.util.Iterator; -import java.util.Vector; -import java.util.Arrays; - -import javax.swing.*; -import javax.swing.border.*; -import javax.swing.event.*; -import javax.swing.text.*; -import javax.swing.tree.*; - -import com.gentlyweb.properties.*; - -import com.gentlyweb.utils.*; - -import com.jgoodies.forms.builder.*; -import com.jgoodies.forms.factories.*; -import com.jgoodies.forms.layout.*; - -import com.quollwriter.*; - -import com.quollwriter.data.*; -import com.quollwriter.data.editors.*; - -import com.quollwriter.db.*; - -import com.quollwriter.events.*; -import com.quollwriter.data.comparators.*; -import com.quollwriter.text.*; -import com.quollwriter.editors.ui.sidebars.*; -import com.quollwriter.editors.ui.panels.*; -import com.quollwriter.ui.panels.*; -import com.quollwriter.ui.sidebars.*; -import com.quollwriter.ui.actionHandlers.*; -import com.quollwriter.ui.*; -import com.quollwriter.ui.components.QPopup; -import com.quollwriter.ui.components.Header; -import com.quollwriter.ui.components.ActionAdapter; -import com.quollwriter.ui.events.*; -import com.quollwriter.ui.renderers.*; -import com.quollwriter.editors.*; -import com.quollwriter.editors.messages.*; -import com.quollwriter.editors.ui.*; - -import static com.quollwriter.LanguageStrings.*; -import static com.quollwriter.Environment.getUIString; - -public class ProjectCommentsViewer extends ProjectSentReceivedViewer -{ - - public static final String OPEN_PROJECT_HEADER_CONTROL_ID = "openProject"; - - public ProjectCommentsViewer (Project proj, - ProjectCommentsMessage message) - { - - super (proj, - message); - - } - - /* - public void switchToProjectComments (ProjectCommentsMessage pcm) - { - - if (pcm == null) - { - - throw new IllegalArgumentException ("Expected a project comments message"); - - } - - this.message = pcm; - - this.initTitle (); - - ProjectSentReceivedSideBar sb = null; - - try - { - - sb = this.getSideBar (); - - sb.init (); - - } catch (Exception e) { - - Environment.logError ("Unable to init new editor project comments side bar", - e); - - UIUtils.showErrorMessage (this, - "Unable to show comments, please contact Quoll Writer support for assistance."); - - // Need to close and reopen the project? - - return; - - } - - this.sideBar = sb; - - this.setMainSideBar (this.sideBar); - - } - */ - - @Override - public Set getTitleHeaderControlIds () - { - - Set ids = new LinkedHashSet<> (); - - ids.add (OPEN_PROJECT_HEADER_CONTROL_ID); - - ids.addAll (super.getTitleHeaderControlIds ()); - - return ids; - - } - - @Override - public JComponent getTitleHeaderControl (String id) - { - - if (id == null) - { - - return null; - - } - - java.util.List prefix = Arrays.asList (editors,projectcomments,title,toolbar,buttons); - - final ProjectCommentsViewer _this = this; - - JComponent c = null; - - if (id.equals (OPEN_PROJECT_HEADER_CONTROL_ID)) - { - - return UIUtils.createButton (Constants.OPEN_PROJECT_ICON_NAME, - Constants.ICON_TITLE_ACTION, - getUIString (prefix,openproject,tooltip), - //"Click to open the find", - new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - ProjectInfo proj = null; - - try - { - - proj = Environment.getProjectById (_this.message.getForProjectId (), - _this.message.isSentByMe () ? Project.EDITOR_PROJECT_TYPE : Project.NORMAL_PROJECT_TYPE); - - } catch (Exception e) { - - Environment.logError ("Unable to get project for: " + - _this.message.getForProjectId (), - e); - - UIUtils.showErrorMessage (_this, - getUIString (editors,project,actions,openproject,openerrors,general)); - //"Unable to show {comments}, please contact Quoll Writer support for assistance."); - - return; - - } - - try - { - - Environment.openProject (proj); - - } catch (Exception e) { - - Environment.logError ("Unable to get project for: " + - _this.message.getForProjectId (), - e); - - UIUtils.showErrorMessage (_this, - getUIString (editors,project,actions,openproject,openerrors,general)); - //"Unable to show {comments}, please contact Quoll Writer support for assistance."); - - return; - - } - - } - - }); - - } - - return super.getTitleHeaderControl (id); - - } - - @Override - public ProjectSentReceivedSideBar getSideBar () - { - - return new ProjectCommentsSideBar (this, - this.message); - - } - - @Override - public void init () - throws Exception - { - - super.init (); - - // Show the first comment in the first chapter. - this.viewObject (this.proj.getBook (0).getChapters ().get (0).getNotes ().iterator ().next ()); - - } - - @Override - public String getViewerIcon () - { - - return Constants.COMMENT_ICON_NAME; - - } - - @Override - public String getViewerTitle () - { - - String verName = this.getProject ().getProjectVersion ().getName (); - - if (verName != null) - { - - verName = String.format (getUIString (editors,projectcomments,(this.message.isSentByMe () ? sent : received),viewertitleversionwrapper), - //" (%s)", - verName); - - } else { - - verName = ""; - - } - - return String.format (getUIString (editors,projectcomments,(this.message.isSentByMe () ? sent : received),viewertitle), - //"{Comments} on%s: %s", - verName, - this.proj.getName ()); - - } - -} diff --git a/src/com/quollwriter/editors/ui/ProjectEditStopMessageBox.java b/src/com/quollwriter/editors/ui/ProjectEditStopMessageBox.java deleted file mode 100644 index dae30217..00000000 --- a/src/com/quollwriter/editors/ui/ProjectEditStopMessageBox.java +++ /dev/null @@ -1,321 +0,0 @@ -package com.quollwriter.editors.ui; - -import java.util.List; -import java.util.ArrayList; -import java.util.Set; -import java.util.Map; -import java.util.HashMap; -import java.util.Date; - -import java.awt.event.*; -import java.awt.Component; -import java.awt.Dimension; -import java.awt.Point; -import javax.swing.*; -import javax.swing.border.*; -import javax.swing.tree.*; - -import com.jgoodies.forms.builder.*; -import com.jgoodies.forms.factories.*; -import com.jgoodies.forms.layout.*; - -import com.quollwriter.*; -import com.quollwriter.ui.*; -import com.quollwriter.data.*; -import com.quollwriter.data.editors.*; -import com.quollwriter.ui.components.ImagePanel; -import com.quollwriter.editors.messages.*; -import com.quollwriter.editors.*; - -import static com.quollwriter.LanguageStrings.*; -import static com.quollwriter.Environment.getUIString; - -//@MessageBoxFor(Message=ProjectEditStopMessage.class) -public class ProjectEditStopMessageBox extends MessageBox -{ - - private AbstractProjectViewer commentsViewer = null; - private Box responseBox = null; - - public ProjectEditStopMessageBox (ProjectEditStopMessage mess, - AbstractViewer viewer) - { - - super (mess, - viewer); - - } - - public boolean isAutoDealtWith () - { - - return false; - - } - - public void doUpdate () - { - - if (this.message.isDealtWith ()) - { - - if (this.responseBox != null) - { - - this.responseBox.setVisible (false); - - } - - } - - } - - public void doInit () - { - - final ProjectEditStopMessageBox _this = this; - - String title = null; - //"Stopped editing {project}"; - - if (this.message.isSentByMe ()) - { - - title = getUIString (editors,messages,projecteditstop,sent,LanguageStrings.title); - - } else { - - title = getUIString (editors,messages,projecteditstop,received,LanguageStrings.title); - - } - - JComponent h = UIUtils.createBoldSubHeader (title, - Constants.CANCEL_ICON_NAME); - - this.add (h); - - String reason = this.message.getReason (); - - String rows = "top:p"; - - if (reason != null) - { - - rows += ", 6px, top:p"; - - } - - FormLayout fl = new FormLayout ("right:p, 6px, fill:100px:grow", - rows); - - fl.setHonorsVisibility (true); - PanelBuilder builder = new PanelBuilder (fl); - - CellConstraints cc = new CellConstraints (); - - int row = 1; - - builder.addLabel ("" + getUIString (editors,messages,projecteditstop,labels,project) + "", - //Environment.replaceObjectNames ("{Project}"), - cc.xy (1, - row)); - - ProjectInfo proj = null; - - try - { - - proj = Environment.getProjectById (_this.message.getForProjectId (), - null); - - } catch (Exception e) { - - Environment.logError ("Unable to get project info for project with id: " + - _this.message.getForProjectId (), - e); - - } - - if (proj != null) - { - - JLabel openProj = UIUtils.createClickableLabel (this.message.getForProjectName (), - null, - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - ProjectInfo proj = null; - - try - { - - proj = Environment.getProjectById (_this.message.getForProjectId (), - null); - - } catch (Exception e) { - - Environment.logError ("Unable to get project info for project with id: " + - _this.message.getForProjectId (), - e); - - } - - if (proj != null) - { - - try - { - - Environment.openProject (proj); - - } catch (Exception e) { - - Environment.logError ("Unable to open project: " + - proj, - e); - - } - - } - - } - - }); - - openProj.setToolTipText (getUIString (project,actions,openproject,tooltips,general)); - //Environment.replaceObjectNames ("Click to open the {project}")); - - builder.add (openProj, - cc.xy (3, - row)); - - } else { - - builder.addLabel (this.message.getForProjectName (), - cc.xy (3, - row)); - - } - - row += 2; - - if (reason != null) - { - - builder.addLabel (getUIString (editors,messages,projecteditstop,labels,project), - //Environment.replaceObjectNames ("Message"), - cc.xy (1, - row)); - - builder.addLabel (String.format ("%s", - reason), - cc.xy (3, - row)); - - row += 2; - - } - - JPanel bp = builder.getPanel (); - bp.setOpaque (false); - bp.setAlignmentX (JComponent.LEFT_ALIGNMENT); - bp.setBorder (UIUtils.createPadding (0, 5, 0, 5)); - - this.add (bp); - - if (!this.message.isDealtWith ()) - { - - // Show the response. - this.responseBox = new Box (BoxLayout.Y_AXIS); - - this.add (this.responseBox); - - JTextPane rdesc = UIUtils.createHelpTextPane (String.format (getUIString (editors,messages,projecteditstop,received,undealtwith,text), - //"%s has stopped editing {project} %s.", - this.message.getEditor ().getShortName (), - this.message.getForProjectName ()), - this.viewer); - - this.responseBox.add (Box.createVerticalStrut (5)); - - Box rdescb = new Box (BoxLayout.Y_AXIS); - rdescb.setBorder (UIUtils.createPadding (0, 5, 0, 0)); - rdescb.add (rdesc); - rdescb.setAlignmentX (Component.LEFT_ALIGNMENT); - this.responseBox.add (rdescb); - - rdesc.setBorder (null); - rdesc.setSize (new Dimension (UIUtils.getPopupWidth () - 20, - rdesc.getPreferredSize ().height)); - - final EditorEditor ed = this.message.getEditor (); - - this.responseBox.setBorder (UIUtils.createPadding (5, 0, 0, 0)); - - JButton ok = new JButton (getUIString (editors,messages,projecteditstop,received,undealtwith,buttons,confirm)); - //"Ok, got it"); - - ok.addActionListener (new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - try - { - - ProjectInfo p = Environment.getProjectById (_this.message.getForProjectId (), - Project.NORMAL_PROJECT_TYPE); - - ProjectEditor pe = EditorsEnvironment.getProjectEditor (p, - ed); - - pe.setCurrent (false); - pe.setEditorTo (new Date ()); - pe.setStatusMessage (String.format (getUIString (editors,messages,projecteditstop,editorstatus), - //"Stopped editing: %s", - Environment.formatDate (pe.getEditorTo ()))); - - EditorsEnvironment.updateProjectEditor (pe); - - _this.message.setDealtWith (true); - - EditorsEnvironment.updateMessage (_this.message); - - } catch (Exception e) { - - Environment.logError ("Unable to update editor: " + - ed, - e); - - UIUtils.showErrorMessage (_this.viewer, - getUIString (editors,editor,edit,actionerror)); - //"Unable to update {contact}, please contact Quoll Writer support for assistance."); - - return; - - } - - } - - }); - - JButton[] buts = new JButton[] { ok }; - - JPanel bb = UIUtils.createButtonBar2 (buts, - Component.LEFT_ALIGNMENT); - bb.setOpaque (false); - bb.setAlignmentX (Component.LEFT_ALIGNMENT); - bb.setBorder (UIUtils.createPadding (5, 0, 0, 0)); - - this.responseBox.add (bb); - - } - - } - -} diff --git a/src/com/quollwriter/editors/ui/ProjectEditorsAccordionItem.java b/src/com/quollwriter/editors/ui/ProjectEditorsAccordionItem.java deleted file mode 100644 index ff12fbe0..00000000 --- a/src/com/quollwriter/editors/ui/ProjectEditorsAccordionItem.java +++ /dev/null @@ -1,823 +0,0 @@ -package com.quollwriter.editors.ui; - -import java.awt.Component; -import java.awt.Insets; -import java.awt.event.*; -import java.util.Set; -import java.util.LinkedHashSet; -import java.util.Arrays; -import java.util.ArrayList; -import javax.swing.*; -import javax.swing.border.*; - -import com.quollwriter.data.editors.*; -import com.quollwriter.*; -import com.quollwriter.events.*; -import com.quollwriter.ui.*; -import com.quollwriter.editors.*; -import com.quollwriter.ui.components.ScrollableBox; - -import static com.quollwriter.LanguageStrings.*; -import static com.quollwriter.Environment.getUIString; - -public class ProjectEditorsAccordionItem extends AccordionItem implements ProjectEditorChangedListener, EditorMessageListener -{ - - private Box wrapper = null; - private ProjectViewer viewer = null; - private ComponentListener listener = null; - private Box currentEditors = null; - private Box previousEditors = null; - private boolean showPreviousEditors = false; - private boolean inited = false; - - public ProjectEditorsAccordionItem (ProjectViewer pv) - { - - super ("", - //"{Editors}", - Constants.EDIT_ICON_NAME); - //Constants.EDITORS_ICON_NAME); - - this.viewer = pv; - - final ProjectEditorsAccordionItem _this = this; - - this.wrapper = new ScrollableBox (BoxLayout.Y_AXIS); - this.wrapper.setBorder (UIUtils.createPadding (0, 10, 0, 0)); - - this.currentEditors = new Box (BoxLayout.Y_AXIS); - this.currentEditors.setAlignmentX (Component.LEFT_ALIGNMENT); - - this.wrapper.add (this.currentEditors); - - this.previousEditors = new Box (BoxLayout.Y_AXIS); - this.previousEditors.setAlignmentX (Component.LEFT_ALIGNMENT); - - this.wrapper.add (this.previousEditors); - - JLabel help = UIUtils.createInformationLabel (getUIString (project,sidebar,editors,text)); - //"People who are editing this {project} for you."); - help.setBorder (UIUtils.createPadding (0, 0, 5, 0)); - - this.currentEditors.add (help); - - this.previousEditors.add (UIUtils.createBoldSubHeader (getUIString (project,sidebar,editors,previouseditors,title), - //"Previous {Editors}", - null)); - - this.previousEditors.setVisible (false); - - this.listener = new ComponentAdapter () - { - - @Override - public void componentResized (ComponentEvent ev) - { - - _this.updateBorders (); - - } - - }; - - EditorsEnvironment.addProjectEditorChangedListener (this); - EditorsEnvironment.addEditorMessageListener (this); - - //this.getHeader ().setPadding (new Insets (0, 0, 2, 0)); - //this.getHeader ().getLabel ().setBorder (UIUtils.createPadding (0, 5, 0, 0)); - - } - - @Override - public String getTitle () - { - - return getUIString (project,sidebar,editors,title); - - } - - @Override - public void handleMessage (EditorMessageEvent ev) - { - - if (this.viewer.getProject () == null) - { - - // The viewer is no longer valid. - return; - - } - - // See if the editor is a project editor. - ProjectEditor pe = this.viewer.getProject ().getProjectEditor (ev.getMessage ().getEditor ()); - - if (pe == null) - { - - return; - - } - - this.setContentVisible (true); - - } - - @Override - public String getId () - { - - return ProjectEditor.OBJECT_TYPE; - - } - - @Override - public void projectEditorChanged (ProjectEditorChangedEvent ev) - { - - if (this.viewer.getProject () == null) - { - - return; - - } - - ProjectEditor pe = ev.getProjectEditor (); - - if (ev.getType () == ProjectEditorChangedEvent.PROJECT_EDITOR_ADDED) - { - - // Editor is new. - EditorInfoBox infBox = null; - - try - { - - infBox = this.getEditorBox (pe); - - } catch (Exception e) { - - Environment.logError ("Unable to get editor info box for project editor: " + - pe, - e); - - return; - - } - - infBox.init (); - - this.currentEditors.add (infBox, - 1); - - } else { - - for (int i = 0; i < this.currentEditors.getComponentCount (); i++) - { - - Component c = this.currentEditors.getComponent (i); - - if (c instanceof EditorInfoBox) - { - - EditorInfoBox b = (EditorInfoBox) c; - - if (b.getProjectEditor () == pe) - { - - if (ev.getType () == EditorChangedEvent.EDITOR_DELETED) - { - - this.currentEditors.remove (b); - - break; - - } - - if (ev.getType () == EditorChangedEvent.EDITOR_CHANGED) - { - - // See if there is a project editor and if they are now previous, if so remove them. - if (!pe.isCurrent ()) - { - - this.previousEditors.add (b); - - break; - - } - - } - - } - - } - - } - - for (int i = 0; i < this.previousEditors.getComponentCount (); i++) - { - - Component c = this.previousEditors.getComponent (i); - - if (c instanceof EditorInfoBox) - { - - EditorInfoBox b = (EditorInfoBox) c; - - if (b.getProjectEditor () == pe) - { - - if (ev.getType () == EditorChangedEvent.EDITOR_DELETED) - { - - this.previousEditors.remove (b); - - break; - - } - - if (ev.getType () == EditorChangedEvent.EDITOR_CHANGED) - { - - if (pe.isCurrent ()) - { - - this.currentEditors.add (b); - - break; - - } - - } - - } - - } - - } - - } - - this.setContentVisible (true); - - } - - private EditorInfoBox getEditorBox (ProjectEditor pe) - throws GeneralException - { - - return this.getEditorBox (pe.getEditor ()); - - } - - private EditorInfoBox getEditorBox (EditorEditor ed) - throws GeneralException - { - - EditorInfoBox b = new EditorInfoBox (ed, - this.viewer, - true); - - b.setAlignmentX (Component.LEFT_ALIGNMENT); - - b.addFullPopupListener (); - - b.init (); - - b.addComponentListener (this.listener); - - return b; - - } - - @Override - public JComponent getContent () - { - - return this.wrapper; - - } - - private Set getCurrentEditors () - { - - Set pes = this.viewer.getProject ().getProjectEditors (); - - Set ret = new LinkedHashSet (); - - if (pes != null) - { - - for (ProjectEditor pe : pes) - { - - if (pe.isPrevious ()) - { - - continue; - - } - - ret.add (pe); - - } - - } - - return ret; - - } - - private Set getPreviousEditors () - { - - Set pes = this.viewer.getProject ().getProjectEditors (); - - Set ret = new LinkedHashSet (); - - if (pes != null) - { - - for (ProjectEditor pe : pes) - { - - if (pe.isCurrent ()) - { - - continue; - - } - - ret.add (pe); - - } - - } - - return ret; - - } - - public void updateItemCount () - { - - Set pes = this.getCurrentEditors (); - - String title = String.format ("%s (%s)", - this.getTitle (), - Environment.formatNumber (pes.size ())); - - // Set the title on the header directly. - this.header.setTitle (title); - - } - - @Override - public void setContentVisible (boolean v) - { - - Set cpes = this.getCurrentEditors (); - - Set ppes = this.getPreviousEditors (); - - this.currentEditors.setVisible (cpes.size () > 0); - this.previousEditors.setVisible ((this.showPreviousEditors && ppes.size () > 0)); - - super.setContentVisible (this.currentEditors.isVisible () || this.previousEditors.isVisible ()); - - this.updateBorders (); - - this.updateItemCount (); - - } - - private void updateBorders () - { - - EditorInfoBox last = null; - - for (int i = 0; i < this.currentEditors.getComponentCount (); i++) - { - - Component c = this.currentEditors.getComponent (i); - - if (c instanceof EditorInfoBox) - { - - EditorInfoBox b = (EditorInfoBox) c; - - this.setBorder (b, - false); - - last = b; - - } - - } - - if (last != null) - { - - this.setBorder (last, - true); - - } - - last = null; - - for (int i = 0; i < this.previousEditors.getComponentCount (); i++) - { - - Component c = this.previousEditors.getComponent (i); - - if (c instanceof EditorInfoBox) - { - - EditorInfoBox b = (EditorInfoBox) c; - - this.setBorder (b, - false); - - last = b; - - } - - } - - if (last != null) - { - - this.setBorder (last, - true); - - } - - } - - private void showPreviousEditors () - { - - this.previousEditors.setVisible (this.showPreviousEditors); - - this.setContentVisible (true); - - } - - @Override - public void init () - { - - if (this.inited) - { - - return; - - } - - this.inited = true; - - super.init (); - - final ProjectEditorsAccordionItem _this = this; - - this.getHeader ().addMouseListener (new MouseEventHandler () - { - - @Override - public void handlePress (MouseEvent ev) - { - - // TODO: Make this nicer - if (!EditorsEnvironment.hasRegistered ()) - { - - if (EditorsEnvironment.isEditorsServiceAvailable ()) - { - - try - { - - EditorsUIUtils.showRegister (_this.viewer); - - } catch (Exception e) { - - Environment.logError ("Unable to show editors service register", - e); - - } - - } - - } - - } - - }); - - Set pes = this.viewer.getProject ().getProjectEditors (); - - if (pes != null) - { - - for (ProjectEditor pe : pes) - { - - EditorInfoBox infBox = null; - - try - { - - infBox = this.getEditorBox (pe.getEditor ()); - - } catch (Exception e) { - - Environment.logError ("Unable to get editor info box for editor: " + - pe.getEditor (), - e); - - continue; - - } - - infBox.init (); - - if (!pe.isPrevious ()) - { - - this.currentEditors.add (infBox); - - } else { - - this.previousEditors.add (infBox); - - } - - } - - } - - this.setContentVisible (true); - - } - - @Override - public void fillHeaderPopupMenu (JPopupMenu m, - MouseEvent ev) - { - - java.util.List prefix = Arrays.asList (project,sidebar,editors,headerpopupmenu,items); - - final ProjectEditorsAccordionItem _this = this; - - if (EditorsEnvironment.getUserAccount () != null) - { - - m.add (UIUtils.createMenuItem (getUIString (prefix,invite), - //"Invite someone to edit this {project}", - Constants.ADD_ICON_NAME, - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - Set eds = new LinkedHashSet<> (EditorsEnvironment.getEditors ()); - - java.util.List projEds = null; - - try - { - - projEds = EditorsEnvironment.getProjectEditors (_this.viewer.getProject ().getId ()); - - } catch (Exception e) { - - Environment.logError ("Unable to get project editors for project: " + - _this.viewer.getProject ().getId (), - e); - - UIUtils.showErrorMessage (_this.viewer, - getUIString (project,sidebar,editors,sendinvite,actionerror)); - //"Unable to show contacts."); - - return; - - } - - for (ProjectEditor pe : projEds) - { - - eds.remove (pe.getEditor ()); - - } - - java.util.Iterator iter = eds.iterator (); - - while (iter.hasNext ()) - { - - EditorEditor ed = iter.next (); - - if (ed.isPending ()) - { - - iter.remove (); - - } - - } - - final JLabel l = UIUtils.createClickableLabel (getUIString (project,sidebar,editors,sendinvite,popup,labels,notinlist), - //"Not in the list? Click here to invite someone using their email address.", - Environment.getIcon (Constants.EMAIL_ICON_NAME, - Constants.ICON_MENU)); - - UIUtils.makeClickable (l, - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - EditorsUIUtils.showInviteEditor (_this.viewer); - - UIUtils.closePopupParent (l); - - } - - }); - - EditorsUIUtils.showContacts (eds, - getUIString (project,sidebar,editors,sendinvite,popup,title), - _this.viewer, - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - EditorsUIUtils.showSendProject (_this.viewer, - (EditorEditor) ev.getSource (), - null); - - } - - }, - l); - - } - - })); - - m.add (UIUtils.createMenuItem (getUIString (prefix,vieweditors), - //"Show all {contacts}", - Constants.EDITORS_ICON_NAME, - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - try - { - - _this.viewer.viewEditors (); - - } catch (Exception e) { - - Environment.logError ("Unable to view all editors", - e); - - UIUtils.showErrorMessage (_this.viewer, - getUIString (editors,vieweditorserror)); - //"Unable to view all {contacts}"); - - } - - } - - })); - - } - - // Get all previous editors. - if (!this.showPreviousEditors) - { - - int prevCount = 0; - - Set pes = this.viewer.getProject ().getProjectEditors (); - - if (pes != null) - { - - for (ProjectEditor pe : pes) - { - - if (pe.isPrevious ()) - { - - prevCount++; - - } - - } - - if (prevCount > 0) - { - - m.add (UIUtils.createMenuItem (String.format (getUIString (prefix,previouseditors), - //"View the previous {editors} (%s)", - Environment.formatNumber (prevCount)), - Constants.STOP_ICON_NAME, - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.showPreviousEditors = true; - _this.showPreviousEditors (); - - } - - })); - - } - - } - - } else { - - int prevCount = 0; - - Set pes = this.viewer.getProject ().getProjectEditors (); - - if (pes != null) - { - - for (ProjectEditor pe : pes) - { - - if (pe.isPrevious ()) - { - - prevCount++; - - } - - } - - if (prevCount > 0) - { - - m.add (UIUtils.createMenuItem (getUIString (prefix,hidepreviouseditors), - //"Hide the previous {editors}", - Constants.CANCEL_ICON_NAME, - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.showPreviousEditors = false; - _this.showPreviousEditors (); - - } - - })); - - } - - } - - } - - } - - private void setBorder (EditorInfoBox b, - boolean isLast) - { - - b.setBorder (isLast ? UIUtils.createPadding (5, 0, 5, 0) : UIUtils.createBottomLineWithPadding (5, 0, 5, 0)); - - /* - if (b.isShowAttentionBorder ()) - { - - b.setBorder (new CompoundBorder (new MatteBorder (0, 2, 0, 0, UIUtils.getColor ("#ff0000")), - new CompoundBorder (new EmptyBorder (0, 5, 0, 0), - (isLast ? UIUtils.createPadding (5, 0, 5, 0) : UIUtils.createBottomLineWithPadding (5, 0, 5, 0))))); - - } else { - - b.setBorder (isLast ? UIUtils.createPadding (5, 0, 5, 0) : UIUtils.createBottomLineWithPadding (5, 0, 5, 0)); - - } - */ - } - -} diff --git a/src/com/quollwriter/editors/ui/ProjectSentReceivedViewer.java b/src/com/quollwriter/editors/ui/ProjectSentReceivedViewer.java deleted file mode 100644 index b9514312..00000000 --- a/src/com/quollwriter/editors/ui/ProjectSentReceivedViewer.java +++ /dev/null @@ -1,887 +0,0 @@ -package com.quollwriter.editors.ui; - -import java.awt.*; -import java.awt.dnd.*; -import java.awt.event.*; - -import java.net.*; - -import java.security.*; - -import java.text.*; - -import java.util.ArrayList; -import java.util.Date; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedHashSet; -import java.util.TreeSet; -import java.util.Map; -import java.util.Set; -import java.util.StringTokenizer; -import java.util.Iterator; - -import javax.swing.*; -import javax.swing.border.*; -import javax.swing.event.*; -import javax.swing.text.*; -import javax.swing.tree.*; - -import com.gentlyweb.properties.*; - -import com.gentlyweb.utils.*; - -import com.jgoodies.forms.builder.*; -import com.jgoodies.forms.factories.*; -import com.jgoodies.forms.layout.*; - -import com.quollwriter.*; - -import com.quollwriter.data.*; -import com.quollwriter.data.editors.*; - -import com.quollwriter.db.*; - -import com.quollwriter.events.*; -import com.quollwriter.data.comparators.*; -import com.quollwriter.text.*; -import com.quollwriter.editors.ui.sidebars.*; -import com.quollwriter.editors.ui.panels.*; -import com.quollwriter.ui.panels.*; -import com.quollwriter.ui.sidebars.*; -import com.quollwriter.ui.actionHandlers.*; -import com.quollwriter.ui.*; - -import com.quollwriter.ui.components.TabHeader; -import com.quollwriter.ui.components.ActionAdapter; -import com.quollwriter.ui.components.IconProvider; -import com.quollwriter.ui.events.*; -import com.quollwriter.ui.renderers.*; -import com.quollwriter.editors.*; -import com.quollwriter.editors.messages.*; -import com.quollwriter.editors.ui.*; - -import static com.quollwriter.LanguageStrings.*; -import static com.quollwriter.Environment.getUIString; - -public abstract class ProjectSentReceivedViewer extends AbstractProjectViewer -{ - - protected ProjectSentReceivedSideBar sideBar = null; - private DefaultChapterItemViewPopupProvider chapterItemViewPopupProvider = null; - private IconProvider iconProvider = null; - private EditorEditor editor = null; - protected E message = null; - - public ProjectSentReceivedViewer (Project proj, - E message) - { - - final ProjectSentReceivedViewer _this = this; - - this.proj = proj; - this.message = message; - - this.chapterItemViewPopupProvider = new DefaultChapterItemViewPopupProvider () - { - - @Override - public boolean canEdit (ChapterItem it) - { - - return false; - - } - - @Override - public boolean canDelete (ChapterItem it) - { - - return false; - - } - - }; - - this.chapterItemViewPopupProvider.setShowLinks (false); - this.chapterItemViewPopupProvider.setFormatDetails (Note.OBJECT_TYPE, - new NoteFormatDetails () - { - - @Override - public String getTitle (Note item) - { - - return getUIString (editors,projectcomments,(_this.message.isSentByMe () ? sent : received),comment,view,title); - //)"{Comment}"; - - } - - @Override - public String getIcon (Note item) - { - - return Constants.COMMENT_ICON_NAME; - - } - - @Override - public String getItemDescription (Note item) - { - - return item.getDescription ().getMarkedUpText (); - - } - - @Override - public ActionListener getEditItemActionHandler (Note item, - ChapterItemViewer ep) - { - - throw new UnsupportedOperationException ("Not supported for project comments."); - - } - - @Override - public ActionListener getDeleteItemActionHandler (Note item, - ChapterItemViewer ep, - boolean showAtItem) - { - - throw new UnsupportedOperationException ("Not supported for project comments."); - - } - - @Override - public Set getTools (Note item, - ChapterItemViewer ep) - { - - if (_this.message.isSentByMe ()) - { - - return null; - - } - - Set buts = new LinkedHashSet (); - - final JButton but = UIUtils.createButton ((item.isDealtWith () ? Constants.SET_UNDEALT_WITH_ICON_NAME : Constants.SET_DEALT_WITH_ICON_NAME), - Constants.ICON_MENU, - getUIString (editors,projectcomments,received,comment,tools, (item.isDealtWith () ? undealtwith : dealtwith),tooltip), - //"Click to mark the {comment} as %s with", - //"undealt" : "dealt")), - null); - - ActionListener aa = new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - Date d = null; - - if (!item.isDealtWith ()) - { - - d = new Date (); - - } - - item.setDealtWith (d); - - but.setToolTipText (getUIString (editors,projectcomments,received,comment,tools, (item.isDealtWith () ? undealtwith : dealtwith),tooltip)); - //String.format ("Click to mark the {comment} as %s with", - // (item.isDealtWith () ? "undealt" : "dealt"))); - but.setIcon (Environment.getIcon ((item.isDealtWith () ? Constants.SET_UNDEALT_WITH_ICON_NAME : Constants.SET_DEALT_WITH_ICON_NAME), - Constants.ICON_MENU)); - - // Inform the sidebar of the change. - _this.sideBar.reloadTreeForObjectType (Chapter.OBJECT_TYPE); - - } - - }; - - but.addActionListener (aa); - - buts.add (but); - - return buts; - - } - - }); - - this.iconProvider = new DefaultIconProvider () - { - - @Override - public ImageIcon getIcon (String name, - int type) - { - - if (name.equals (Note.OBJECT_TYPE)) - { - - name = Constants.COMMENT_ICON_NAME; - - } - - return super.getIcon (name, - type); - - } - - }; - - this.sideBar = this.getSideBar (); - - } - - public E getMessage () - { - - return this.message; - - } - - public abstract ProjectSentReceivedSideBar getSideBar (); - - public void close () - { - - this.close (true, - null); - - } - - @Override - public boolean close (boolean noConfirm, - final ActionListener afterClose) - { - - this.dispose (); - - if (afterClose != null) - { - - afterClose.actionPerformed (new ActionEvent (this, - 0, - "closed")); - - } - - return true; - - } - - @Override - public Set getTitleHeaderControlIds () - { - - Set ids = new LinkedHashSet (); - - ids.add (FIND_HEADER_CONTROL_ID); - ids.add (CLOSE_HEADER_CONTROL_ID); - - return ids; - - } - - @Override - public void init () - throws Exception - { - - super.init (); - /* - final ProjectSentReceivedViewer _this = this; - - JToolBar titleC = UIUtils.createButtonBar (new ArrayList ()); - - titleC.add (UIUtils.createButton (Constants.FIND_ICON_NAME, - Constants.ICON_TITLE_ACTION, - "Click to open the find", - new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.showFind (null); - - } - - })); - - titleC.add (UIUtils.createButton (Constants.CLOSE_ICON_NAME, - Constants.ICON_TITLE_ACTION, - "Click to close", - new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.close (); - - } - - })); - - this.setViewerControls (titleC); - */ - this.initSideBars (); - - this.initWindow (); - - } - - public IconProvider getIconProvider () - { - - return this.iconProvider; - - } - - public ChapterItemViewPopupProvider getChapterItemViewPopupProvider () - { - - return this.chapterItemViewPopupProvider; - - } - - public void initActionMappings (ActionMap am) - { - - super.initActionMappings (am); - - } - - public void initKeyMappings (InputMap im) - { - - super.initKeyMappings (im); - - } - - public void showObjectInTree (String treeObjType, - NamedObject obj) - { - - this.sideBar.showObjectInTree (treeObjType, - obj); - - } - - public void reloadTreeForObjectType (String objType) - { - - this.sideBar.reloadTreeForObjectType (objType); - - } - - public void reloadTreeForObjectType (NamedObject obj) - { - - this.sideBar.reloadTreeForObjectType (obj.getObjectType ()); - - } - - public AbstractSideBar getMainSideBar () - { - - return this.sideBar; - - } - - public void fillFullScreenTitleToolbar (JToolBar toolbar) - { - - this.fillTitleToolbar (toolbar); - - } - - public void fillTitleToolbar (JToolBar toolbar) - { - - } - - public void fillSettingsPopup (JPopupMenu titlePopup) - { - - } - - public Action getAction (int name, - final NamedObject other) - { - - Action a = super.getAction (name, - other); - - if (a != null) - { - - return a; - - } - - throw new IllegalArgumentException ("Action: " + - name + - " not known."); - - } - - public void handleNewProject () - { - - throw new UnsupportedOperationException ("Not supported for viewing project comments."); - - } - - public String getViewerIcon () - { - - return Constants.COMMENT_ICON_NAME; - - } - - @Override - public abstract String getViewerTitle (); - - public void handleHTMLPanelAction (String v) - { - - StringTokenizer t = new StringTokenizer (v, - ",;"); - - if (t.countTokens () > 1) - { - - while (t.hasMoreTokens ()) - { - - String tok = t.nextToken ().trim (); - - this.handleHTMLPanelAction (tok); - - } - - return; - - } - - if (v.equals ("find")) - { - - this.showFind (null); - - return; - - } - - super.handleHTMLPanelAction (v); - - } - - public void handleOpenProject () - { - - throw new UnsupportedOperationException ("Not supported for viewing project comments."); - - } - - public void handleItemChangedEvent (ItemChangedEvent ev) - { - - if (ev.getChangedObject () instanceof Chapter) - { - - this.sideBar.reloadTreeForObjectType (Chapter.OBJECT_TYPE); - - } - - if (ev.getChangedObject () instanceof Note) - { - - this.sideBar.reloadTreeForObjectType (Note.OBJECT_TYPE); - - } - - } - - @Override - public void saveProject () - { - - - - } - - @Override - public void doSaveState () - { - - } - - public ChapterCommentsPanel getEditorForChapter (Chapter c) - { - - for (QuollPanel qp : this.getAllQuollPanelsForObject (c)) - { - - if (qp instanceof FullScreenQuollPanel) - { - - qp = ((FullScreenQuollPanel) qp).getChild (); - - } - - if (qp instanceof ChapterCommentsPanel) - { - - return (ChapterCommentsPanel) qp; - - } - - } - - return null; - - } - - /** - * This is a top-level action so it can handle showing the user a message, it returns a boolean to indicate - * whether the chapter has been opened for editing. - */ - public boolean editChapter (Chapter c, - ActionListener doAfterOpen) - { - - // Check our tabs to see if we are already editing this chapter, if so then just switch to it instead. - ChapterCommentsPanel qep = (ChapterCommentsPanel) this.getQuollPanelForObject (c); - - if (qep != null) - { - - this.setPanelVisible (qep); - - qep.getEditor ().grabFocus (); - - if (doAfterOpen != null) - { - - UIUtils.doActionWhenPanelIsReady (qep, - doAfterOpen, - c, - "afterview"); - - } - - return true; - - } - - final ProjectSentReceivedViewer _this = this; - - try - { - - qep = new ChapterCommentsPanel (this, - c); - - qep.init (); - - } catch (Exception e) - { - - Environment.logError ("Unable to edit chapter: " + - c, - e); - - UIUtils.showErrorMessage (_this, - getUIString (editors,projectsent,actions,viewchapter,actionerror)); - //"Unable to edit {chapter}: " + - //c.getName ()); - - return false; - - } - - final TabHeader th = this.addPanel (qep); - - qep.addActionListener (new ActionAdapter () - { - - - public void actionPerformed (ActionEvent ev) - { - - if (ev.getID () == QuollPanel.UNSAVED_CHANGES_ACTION_EVENT) - { - - th.setComponentChanged (true); - - } - - } - - }); - - /* - *TODO: Change name if "parent" chapter changes name? - this.addNameChangeListener (c, - qep); -*/ - // Open the tab :) - return this.editChapter (c, - doAfterOpen); - - } - - public boolean viewObject (DataObject d) - { - - return this.viewObject (d, - null); - - } - - public boolean viewObject (final DataObject d, - final ActionListener doAfterView) - { - - if (d instanceof Note) - { - - final Note n = (Note) d; - - if (n.getObject () != null) - { - - final Chapter c = (Chapter) n.getObject (); - - final ProjectSentReceivedViewer _this = this; - - ActionListener onOpen = new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - try - { - - _this.getEditorForChapter (c).showNote (n); - - } catch (Exception e) { - - Environment.logError ("Unable to scroll to note: " + - n, - e); - - UIUtils.showErrorMessage (_this, - getUIString (editors,projectsent,actions,viewcomment,actionerror)); - //"Unable to display {comment}."); - - } - - if (doAfterView != null) - { - - doAfterView.actionPerformed (ev); - - } - - } - - }; - - return this.editChapter (c, - onOpen); - - } - - } - - if (d instanceof Chapter) - { - - Chapter c = (Chapter) d; - - return this.editChapter (c, - doAfterView); - - } - - // Record the error, then ignore. - Environment.logError ("Unable to open object: " + d); - - return false; - - } - - public boolean openPanel (String id) - { - - return false; - - } - - public JTree getTreeForObjectType (String objType) - { - - return this.sideBar.getTreeForObjectType (objType); - - } - - public JTree getChapterTree () - { - - return this.getTreeForObjectType (Chapter.OBJECT_TYPE); - - } - - public void chapterTreeChanged (DataObject d) - { - - DefaultTreeModel model = (DefaultTreeModel) this.getChapterTree ().getModel (); - - DefaultMutableTreeNode node = (DefaultMutableTreeNode) UIUtils.getTreePathForUserObject ((DefaultMutableTreeNode) model.getRoot (), - d).getLastPathComponent (); - - model.nodeStructureChanged (node); - - } - - public void scrollTo (final Chapter c, - final int pos) - { - - final ProjectSentReceivedViewer _this = this; - - this.editChapter (c, - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - try - { - - _this.getEditorForChapter (c).scrollToPosition (pos); - - } catch (Exception e) - { - - Environment.logError ("Unable to show snippet at position: " + - pos, - e); -/* - UIUtils.showErrorMessage (_this, - "Unable to scroll to position."); -*/ - } - - } - - }); - - } - - public void updateChapterIndexes (Book b) - throws GeneralException - { - - throw new UnsupportedOperationException ("Not supported for project comments."); - - } - - public void deleteChapter (Chapter c) - { - - throw new UnsupportedOperationException ("Not supported for project comments."); - - } - - public void deleteObject (NamedObject o) - throws GeneralException - { - - throw new UnsupportedOperationException ("Not supported for project comments."); - - } - - public void deleteObject (NamedObject o, - boolean deleteChildObjects) - throws GeneralException - { - - throw new UnsupportedOperationException ("Not supported for project comments."); - - } - - public String getChapterObjectName () - { - - return Environment.getObjectTypeName (Chapter.OBJECT_TYPE); - - } - - public TypesHandler getObjectTypesHandler (String objType) - { - - return null; - - } - - @Override - public void setLinks (NamedObject o) - { - - // No links for viewing comments. - - } - - public Set findText (String t) - { - - Set res = new LinkedHashSet (); - - // Get the snippets. - Map> snippets = this.getTextSnippets (t); - - if (snippets.size () > 0) - { - - res.add (new ChapterFindResultsBox (Environment.getObjectTypeNamePlural (Chapter.OBJECT_TYPE), - Chapter.OBJECT_TYPE, - Chapter.OBJECT_TYPE, - this, - snippets)); - - } - - Set notes = this.proj.getNotesContaining (t); - - if (notes.size () > 0) - { - - res.add (new NamedObjectFindResultsBox (Environment.getObjectTypeNamePlural (comment), - //"{Comments}", - Constants.COMMENT_ICON_NAME, - Note.OBJECT_TYPE, - this, - notes)); - - } - - return res; - - } - -} diff --git a/src/com/quollwriter/editors/ui/SendProjectWizard.java b/src/com/quollwriter/editors/ui/SendProjectWizard.java deleted file mode 100644 index 3b8b7fdd..00000000 --- a/src/com/quollwriter/editors/ui/SendProjectWizard.java +++ /dev/null @@ -1,1246 +0,0 @@ -package com.quollwriter.editors.ui; - -import java.awt.Component; -import java.awt.Dimension; - -import java.awt.event.*; - -import java.util.List; -import java.util.Set; -import java.util.LinkedHashSet; -import java.util.Date; -import java.util.Calendar; -import java.util.GregorianCalendar; - -import javax.swing.*; -import javax.swing.tree.*; - -import com.toedter.calendar.*; - -import com.jgoodies.forms.builder.*; -import com.jgoodies.forms.factories.*; -import com.jgoodies.forms.layout.*; - -import com.quollwriter.*; -import com.quollwriter.data.editors.*; -import com.quollwriter.data.*; -import com.quollwriter.ui.*; -import com.quollwriter.ui.panels.*; -import com.quollwriter.editors.*; -import com.quollwriter.editors.messages.*; - -public class SendProjectWizard extends Wizard -{ - - private EditorEditor editor = null; - private ActionListener onSend = null; - private ProjectVersion projectVersion = null; - - private TextArea notes = null; - private JDateChooser date = null; - private JLabel error = null; - private JTree chapterTree = null; - private Box sendBox = null; - private boolean firstSend = false; - private JTextField newVerName = null; - private JLabel newVerNameError = null; - private JRadioButton createVersion = null; - private JRadioButton selectDetails = null; - - public SendProjectWizard (AbstractProjectViewer viewer, - EditorEditor ed, - ActionListener onSend) - throws Exception - { - - super (viewer); - this.editor = ed; - this.onSend = onSend; - - final SendProjectWizard _this = this; - - this.firstSend = !EditorsEnvironment.hasUserSentAProjectBefore (); - this.firstSend = true; - - this.newVerNameError = UIUtils.createErrorLabel ("Please enter a name for the version."); - - this.newVerName = new JTextField (); - - this.newVerName.addKeyListener (new KeyAdapter () - { - - public void keyPressed (KeyEvent ev) - { - - _this.enableButton ("next", - false); - - if (_this.newVerName.getText ().trim ().length () > 0) - { - - _this.enableButton ("next", - true); - - } - - } - - }); - } - - public String getFirstHelpText () - { - - return String.format ("Send your {project} to %s.", - this.editor.getShortName ()); - - } - - public int getContentPreferredHeight () - { - - return 350; - - } - - public boolean handleFinish () - { - - Set chapters = new LinkedHashSet (); - - DefaultMutableTreeNode root = (DefaultMutableTreeNode) this.chapterTree.getModel ().getRoot (); - - UIUtils.getSelectedObjects (root, - chapters); - - String err = null; - - if (chapters.size () == 0) - { - - // Show the error. - err = "Please select at least 1 {chapter}."; - - } - - for (Chapter c : chapters) - { - - AbstractEditorPanel qp = this.viewer.getEditorForChapter (c); - - if (qp != null) - { - - if (qp.hasUnsavedChanges ()) - { - - err = "One of the selected {chapters} has unsaved changes, please save your work before sending the {project}."; - - break; - - } - - } - - } - - if (this.notes.getText ().trim ().length () > 5000) - { - - err = "Notes can be a maximum of 5000 characters."; - - } - - if (err != null) - { - - this.error.setText (err); - this.error.setVisible (true); - - UIUtils.resizeParent (this); - - return false; - - } - - this.error.setVisible (false); - - // Show the sending. - this.sendBox.setVisible (true); - - UIUtils.resizeParent (this); - - String n = this.notes.getText ().trim (); - - ProjectVersion pv = new ProjectVersion (); - pv.setName (this.newVerName.getText ().trim ()); - pv.setDueDate (this.date.getDate ()); - pv.setDescription (new StringWithMarkup (n)); - - // Need to snapshot the chapters. - Set nchapters = null; - - try - { - - nchapters = this.viewer.snapshotChapters (chapters, - pv); - - } catch (Exception e) { - - Environment.logError ("Unable to snapshot chapters: " + - chapters, - e); - - UIUtils.showErrorMessage (this.viewer, - "Unable to send new project to {editor}, please contact Quoll Writer support for assistance."); - - return false; - - } - - NewProjectMessage mess = new NewProjectMessage (this.viewer.getProject (), - nchapters, - pv, - this.editor, - this.editor.getEditorStatus () == EditorEditor.EditorStatus.pending ? EditorsEnvironment.getUserAccount () : null); - - // Since we are sending the message we have dealt with it. - mess.setDealtWith (true); - - final SendProjectWizard _this = this; - - EditorsEnvironment.sendMessageToEditor (mess, - // On send. - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - ProjectEditor pe = new ProjectEditor (_this.viewer.getProject (), - _this.editor); - - pe.setStatus (ProjectEditor.Status.invited); - pe.setStatusMessage ("{Project} sent: " + Environment.formatDate (new Date ())); - - // Add the editor to the list of editors - // for the project. A little dangerous to do it here - // since it's not in the same transaction as the message. - // TODO: Maybe have the message have a "side-effect" or "after save" - // TODO: that will add the editor to the project in the same transaction. - try - { - - EditorsEnvironment.addProjectEditor (pe); - - _this.viewer.getProject ().addProjectEditor (pe); - - } catch (Exception e) { - - // Goddamn it! - // Nothing worse than having to show an error and success at the same time. - Environment.logError ("Unable to add editor: " + - _this.editor + - " to project: " + - _this.viewer.getProject (), - e); - - UIUtils.showErrorMessage (_this.viewer, - "Unable to add {editor} " + _this.editor.getMainName () + " to the {project}. Please contact Quoll Writer support for assistance."); - - } - - UIUtils.showMessage ((PopupsSupported) _this.viewer, - "Your {project} has been sent", - String.format ("Your {project} %s has been sent to %s", - _this.viewer.getProject ().getName (), - _this.editor.getMainName ())); - - UIUtils.closePopupParent (_this); - - } - - }, - // On cancel of login. - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - UIUtils.closePopupParent (_this); - - } - - }, - null); - - return false; - - } - - public void handleCancel () - { - - final SendProjectWizard _this = this; - - // Check to see if we are sending to a pending editor. - if (this.editor.isPending ()) - { - - InviteMessage invite = new InviteMessage (EditorsEnvironment.getUserAccount ()); - - invite.setEditor (this.editor); - - // Send an invite. - EditorsEnvironment.sendMessageToEditor (invite, - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - AbstractViewer viewer = Environment.getFocusedViewer (); - - UIUtils.showMessage ((PopupsSupported) viewer, - "Invite sent", - String.format ("An invite has been sent to: %s.", - _this.editor.getEmail ()), - "Ok, got it", - null); - - } - - }, - null, - null); - - } - - } - - @Override - public String getNextButtonLabel (String currStage) - { - - if (currStage.equals ("details")) - { - - return "Send"; - - } - - return super.getNextButtonLabel (currStage); - - } - - public String getNextStage (String currStage) - { - - if (currStage == null) - { - - return "choose"; - - } - - if (currStage.equals ("newversionname")) - { - - if (this.firstSend) - { - - return "first.selectchapters"; - - } - - return "details"; - - } - - if (currStage.equals ("first")) - { - - if (this.createVersion.isSelected ()) - { - - return "newversionname"; - - } - - return "details"; - - } - - if (currStage.equals ("first.selectchapters")) - { - - return "first.notes"; - - } - - if (currStage.equals ("first.notes")) - { - - return "first.create"; - - } - - if (currStage.equals ("first.create")) - { - - return "details"; - - } - - if (currStage.equals ("choose")) - { - - return "details"; - - } - - return null; - - } - - public String getPreviousStage (String currStage) - { - - if (currStage == null) - { - - return null; - - } - - if (currStage.equals ("details")) - { - - if (this.selectDetails.isSelected ()) - { - - if (this.firstSend) - { - - return "first"; - - } - - return "choose"; - - } - - if (this.createVersion.isSelected ()) - { - - return "newversionname"; - - } - - return "choose"; - - } - - if (currStage.equals ("first.selectchapters")) - { - - return "newversionname"; - - } - - if (currStage.equals ("first.notes")) - { - - return "first.selectchapters"; - - } - - if (currStage.equals ("newversionname")) - { - - if (this.firstSend) - { - - return "first"; - - } - - return "choose"; - - } - - if (currStage.equals ("details")) - { - - return "choose"; - - } - - return null; - - } - - public boolean handleStageChange (String oldStage, - String newStage) - { - - if (newStage.equals ("first")) - { - - this.enableButton ("next", - false); - - } - - if (newStage.equals ("newversionname")) - { - - this.newVerName.grabFocus (); - - this.enableButton ("next", - false); - - } - - if (newStage.equals ("first")) - { - - return true; - - } - - if (newStage.equals ("choose")) - { - - return true; - - } - - if (oldStage != null) - { - - if (oldStage.equals ("newversionname")) - { - - this.newVerNameError.setVisible (false); - - if (this.newVerName.getText ().length () == 0) - { - - this.newVerNameError.setText ("Please enter a name for the version."); - - this.newVerNameError.setVisible (true); - - return false; - - } else { - - try - { - - if (this.viewer.getProjectVersion (this.newVerName.getText ().trim ()) != null) - { - - this.newVerNameError.setText ("Already have a version with that name."); - - this.newVerNameError.setVisible (true); - - return false; - - } - - } catch (Exception e) { - - Environment.logError ("Unable to get project version with name: " + - this.newVerName.getText (), - e); - - UIUtils.showErrorMessage (this.viewer, - "Unable to check the version name."); - - return false; - - } - - } - - } - - } - - return true; - - } - - public String getStartStage () - { - - if (this.firstSend) - { - - return "first"; - - } - - //return "choose"; - - return "first"; - - } - - public WizardStep getStage (String stage) - { - - final SendProjectWizard _this = this; - - WizardStep ws = new WizardStep (); - - if (stage.equals ("first.notes")) - { - - ws.title = "Finally, add some notes"; - - FormLayout fl = new FormLayout ("5px, fill:410px:grow, 10px", - "p, 10px, p"); - - PanelBuilder builder = new PanelBuilder (fl); - - CellConstraints cc = new CellConstraints (); - - JTextPane desc = UIUtils.createHelpTextPane ("The final step in creating a version is adding some notes about what you would like the {editor} to do. It's a description of what you would like them to focus on while editing and areas they should pay attention to (or not).

    Leave this bit blank if you want to give individual instructions for each {editor}.", - this.viewer); - desc.setBorder (null); - - int row = 1; - - builder.add (desc, - cc.xy (2, - row)); - - row += 2; - - this.notes = new TextArea (null, - 4, - 5000); - - builder.add (notes, - cc.xy (2, - row)); - - JPanel p = builder.getPanel (); - p.setOpaque (false); - p.setAlignmentX (JComponent.LEFT_ALIGNMENT); - p.setAlignmentY (JComponent.TOP_ALIGNMENT); - - ws.panel = p; - - } - - if (stage.equals ("first.selectchapters")) - { - - ws.title = "Select the {chapters}"; - - FormLayout fl = new FormLayout ("5px, fill:410px:grow, 10px", - "p, 10px, p"); - - PanelBuilder builder = new PanelBuilder (fl); - - CellConstraints cc = new CellConstraints (); - - JTextPane desc = UIUtils.createHelpTextPane ("Select the {chapters} that you would like to be part of the version. But don't worry, the version only acts as a template for what you send. You can always change what you actually send to {an editor} when you send it.", - this.viewer); - desc.setBorder (null); - - int row = 1; - - builder.add (desc, - cc.xy (2, - row)); - - row += 2; - - this.chapterTree = UIUtils.createSelectableTree (); - - Project proj = this.viewer.getProject (); - - final DefaultMutableTreeNode root = UIUtils.createTreeNode (proj, - null, - null, - true); - - if (proj.getBooks ().size () == 1) - { - - Book b = (Book) proj.getBooks ().get (0); - - DefaultMutableTreeNode broot = UIUtils.createTreeNode (b, - null, - null, - true); - - //root.add (broot); - - // Get the chapters. - List chaps = b.getChapters (); - - for (Chapter c : chaps) - { - - DefaultMutableTreeNode node = UIUtils.createTreeNode (c, - null, - null, - true); - - SelectableDataObject s = (SelectableDataObject) node.getUserObject (); - - s.selected = true; - - if (node == null) - { - - continue; - - } - - root.add (node); - - } - - } else - { - - List books = proj.getBooks (); - - for (int i = 0; i < books.size (); i++) - { - - Book b = books.get (i); - - DefaultMutableTreeNode node = UIUtils.createTree (b, - null, - null, - true); - - if (node == null) - { - - continue; - - } - - root.add (node); - - } - - } - - this.chapterTree.setModel (new DefaultTreeModel (root)); - - UIUtils.expandAllNodesWithChildren (this.chapterTree); - - JComponent t = this.chapterTree; - - if (this.chapterTree.getPreferredSize ().height > 300) - { - - JScrollPane sp = UIUtils.createScrollPane (this.chapterTree); - sp.setOpaque (false); - //sp.setBorder (null); - - sp.setPreferredSize (new Dimension (200, - 300)); - - t = sp; - - } - - builder.add (t, - cc.xy (2, - row)); - - JPanel p = builder.getPanel (); - p.setOpaque (false); - p.setAlignmentX (JComponent.LEFT_ALIGNMENT); - p.setAlignmentY (JComponent.TOP_ALIGNMENT); - - ws.panel = p; - - } - - if (stage.equals ("newversionname")) - { - - ws.title = "Select a name for the version"; - - int row = 1; - - FormLayout fl = new FormLayout ("5px, fill:410px:grow, 10px", - "p, 10px, p, p"); - - PanelBuilder builder = new PanelBuilder (fl); - - CellConstraints cc = new CellConstraints (); - - JTextPane desc = UIUtils.createHelpTextPane ("Version names should be meanginful to you, for example 1st Draft, 2nd Draft. You can also create special versions just for your {editor}, for example Jason first edit. The only restriction is that the name must be unique across all versions you create for this {project}.

    Enter the name of the version in the box below.", - this.viewer); - desc.setBorder (null); - - builder.add (desc, - cc.xy (2, - row)); - - row += 2; - - this.newVerNameError.setVisible (false); - this.newVerNameError.setBorder (UIUtils.createPadding (0, 0, 5, 5)); - - UIUtils.addDoActionOnReturnPressed (this.newVerName, - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - if (_this.firstSend) - { - - _this.showStage ("first.selectchapters"); - - return; - - } - - _this.showStage ("details"); - - } - - }); - - this.newVerName.addKeyListener (new KeyAdapter () - { - - public void keyPressed (KeyEvent ev) - { - - _this.newVerNameError.setVisible (false); - - _this.enableButton ("next", - true); - - } - - }); - - builder.add (this.newVerNameError, - cc.xy (2, - row)); - - row++; - - builder.add (this.newVerName, - cc.xy (2, - row)); - - JPanel p = builder.getPanel (); - p.setOpaque (false); - p.setAlignmentX (JComponent.LEFT_ALIGNMENT); - p.setAlignmentY (JComponent.TOP_ALIGNMENT); - - ws.panel = p; - - this.enableButton ("next", - false); - - } - - if (stage.equals ("first")) - { - - ws.title = "Sending your first project"; - - int row = 1; - - FormLayout fl = new FormLayout ("5px, fill:410px:grow, 10px", - "p, 10px, p, 6px, p"); - - PanelBuilder builder = new PanelBuilder (fl); - - CellConstraints cc = new CellConstraints (); - - JTextPane desc = UIUtils.createHelpTextPane ("It is recommended that you send a version of your {project}. A version is just a snapshot of your {chapters} with a name you provide. It acts as a template or shortcut for what you send to {editors}.

    For example you might have a 1st Draft version or a Ready for edit version and so on. The name is a label that helps you remember what you sent and makes any comments you receive from {editors} more meaningful.

    A version helps ensure you send the same thing to your {editors} (although you can tweak what you send).

    So, pick an option below to continue.", - this.viewer); - desc.setBorder (null); - - builder.add (desc, - cc.xy (2, - row)); - - row += 2; - - this.createVersion = new JRadioButton ("Create a version"); - - this.createVersion.addActionListener (new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.showStage ("newversionname"); - - UIUtils.doLater (new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.newVerName.grabFocus (); - - } - - }); - - } - - }); - - this.createVersion.setOpaque (false); - - this.selectDetails = new JRadioButton (Environment.replaceObjectNames ("I'll select the {chapters} to send")); - - this.selectDetails.addActionListener (new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.showStage ("details"); - - } - - }); - - this.selectDetails.setOpaque (false); - - ButtonGroup bg = new ButtonGroup (); - - bg.add (this.createVersion); - bg.add (this.selectDetails); - - builder.add (this.createVersion, - cc.xy (2, - row)); - - row += 2; - - builder.add (this.selectDetails, - cc.xy (2, - row)); - - JPanel p = builder.getPanel (); - p.setOpaque (false); - p.setAlignmentX (JComponent.LEFT_ALIGNMENT); - p.setAlignmentY (JComponent.TOP_ALIGNMENT); - - ws.panel = p; - - this.enableButton ("next", - false); - - } - - if (stage.equals ("choose")) - { - - ws.title = "Select what you would like to do"; - - FormLayout fl = new FormLayout ("10px, p, 10px", - "p, 6px, p, 6px, p"); - - PanelBuilder builder = new PanelBuilder (fl); - - CellConstraints cc = new CellConstraints (); - - this.createVersion = new JRadioButton ("Create a new version"); - - this.createVersion.setOpaque (false); - - JRadioButton b2 = new JRadioButton (Environment.replaceObjectNames ("Select the {chapters} to send")); - - b2.setOpaque (false); - - ButtonGroup bg = new ButtonGroup (); - - bg.add (this.createVersion); - bg.add (b2); - - int row = 1; - - builder.add (this.createVersion, - cc.xy (2, - row)); - - row += 2; - - builder.add (b2, - cc.xy (2, - row)); - - JPanel p = builder.getPanel (); - p.setOpaque (false); - p.setAlignmentX (JComponent.LEFT_ALIGNMENT); - - ws.panel = p; - - } - - if (stage.equals ("details")) - { - - Box content = new Box (BoxLayout.Y_AXIS); - - ws.title = "Select what you would like to send"; - ws.alwaysRefreshPanel = true; - - JTextPane desc = UIUtils.createHelpTextPane ("You can select a date indicating when you would like the editing to be completed, but be reasonable, {editors} have lives too!", - this.viewer); - desc.setBorder (null); - - desc.setBorder (UIUtils.createPadding (0, 5, 0, 0)); - content.add (desc); - - this.error = UIUtils.createErrorLabel (""); - this.error.setBorder (UIUtils.createPadding (10, 10, 0, 10)); - this.error.setVisible (false); - - content.add (this.error); - - - - String verName = (this.projectVersion != null ? this.projectVersion.getName () : this.newVerName.getText ().trim ()); - - boolean hasVersion = verName.length () > 0; - - String verRow = ""; - - if (this.createVersion.isSelected ()) - { - - verRow = "p, 6px,"; - - } - - FormLayout fl = new FormLayout ("6px, right:p, 6px, fill:200px:grow", - "10px, " + verRow + " top:p, 6px, p, 6px, top:min(150px;p), 0px"); - - fl.setHonorsVisibility (true); - PanelBuilder builder = new PanelBuilder (fl); - - CellConstraints cc = new CellConstraints (); - - int row = 2; - - if (hasVersion) - { - - builder.addLabel (Environment.replaceObjectNames ("Version"), - cc.xy (2, - row)); - - builder.addLabel (verName, - cc.xy (4, - row)); - - row += 2; - - } - - builder.addLabel (Environment.replaceObjectNames ("Notes"), - cc.xy (2, - row)); - - this.notes = new TextArea (Environment.replaceObjectNames ("Tell your {editor} about your {project}/book/story here. Also add instructions/hints on what you are wanting them to do, what to look at specifically and so on."), - 4, - 5000); - - builder.add (notes, - cc.xy (4, - row)); - - row += 2; - - builder.addLabel (Environment.replaceObjectNames ("Due by"), - cc.xy (2, - row)); - - Calendar cal = new GregorianCalendar (); - cal.add (Calendar.DATE, - 7); - - this.date = new JDateChooser (cal.getTime ()); - - this.date.setMinSelectableDate (new Date ()); - this.date.getCalendarButton ().setMargin (new java.awt.Insets (3, 3, 3, 3)); - this.date.setIcon (Environment.getIcon ("date", - 16)); - - Box calBox = new Box (BoxLayout.X_AXIS); - calBox.add (this.date); - this.date.setMaximumSize (this.date.getPreferredSize ()); - builder.add (calBox, - cc.xy (4, - row)); - - row += 2; - - builder.addLabel (Environment.replaceObjectNames ("{Chapters}"), - cc.xy (2, - row)); - - this.chapterTree = UIUtils.createSelectableTree (); - - Project p = this.viewer.getProject (); - - final DefaultMutableTreeNode root = UIUtils.createTreeNode (p, - null, - null, - true); - - if (p.getBooks ().size () == 1) - { - - Book b = (Book) p.getBooks ().get (0); - - DefaultMutableTreeNode broot = UIUtils.createTreeNode (b, - null, - null, - true); - - //root.add (broot); - - // Get the chapters. - List chaps = b.getChapters (); - - for (Chapter c : chaps) - { - - DefaultMutableTreeNode node = UIUtils.createTreeNode (c, - null, - null, - true); - - SelectableDataObject s = (SelectableDataObject) node.getUserObject (); - - s.selected = true; - - if (node == null) - { - - continue; - - } - - root.add (node); - - } - - } else - { - - List books = p.getBooks (); - - for (int i = 0; i < books.size (); i++) - { - - Book b = books.get (i); - - DefaultMutableTreeNode node = UIUtils.createTree (b, - null, - null, - true); - - if (node == null) - { - - continue; - - } - - root.add (node); - - } - - } - - this.chapterTree.setModel (new DefaultTreeModel (root)); - - UIUtils.expandAllNodesWithChildren (this.chapterTree); - - JComponent t = this.chapterTree; - - if (this.chapterTree.getPreferredSize ().height > 200) - { - - JScrollPane sp = UIUtils.createScrollPane (this.chapterTree); - sp.setOpaque (false); - //sp.setBorder (null); - - sp.setPreferredSize (new Dimension (200, - 170)); - - t = sp; - - } - - builder.add (t, - cc.xy (4, - row)); - - row++; - - JLabel sending = UIUtils.createLoadingLabel ("Sending {project}"); - sending.setText (Environment.replaceObjectNames ("Sending {project}...")); - sending.setVisible (true); - - this.sendBox = new Box (BoxLayout.X_AXIS); - this.sendBox.setBorder (UIUtils.createPadding (10, 0, 0, 0)); - this.sendBox.add (sending); - this.sendBox.setVisible (false); - - builder.add (this.sendBox, - cc.xy (4, - row)); - - JPanel panel = builder.getPanel (); - panel.setOpaque (false); - panel.setAlignmentX (JComponent.LEFT_ALIGNMENT); - - content.add (panel); - - ws.panel = content; - - UIUtils.doLater (new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - //_this.notes.getTextArea ().getCaret ().setDot (0); - //_this.notes.grabFocus (); - - UIUtils.resizeParent (_this); - - } - - }); - - } - - return ws; - - } - -} \ No newline at end of file diff --git a/src/com/quollwriter/editors/ui/UpdateProjectMessageBox.java b/src/com/quollwriter/editors/ui/UpdateProjectMessageBox.java deleted file mode 100644 index f48a43b1..00000000 --- a/src/com/quollwriter/editors/ui/UpdateProjectMessageBox.java +++ /dev/null @@ -1,204 +0,0 @@ -package com.quollwriter.editors.ui; - -import java.util.Date; -import java.util.List; -import java.util.ArrayList; -import java.util.Map; -import java.util.LinkedHashMap; -import java.util.Set; - -import java.awt.event.*; -import java.awt.Component; -import java.awt.Dimension; -import javax.swing.*; -import javax.swing.border.*; - -import com.jgoodies.forms.builder.*; -import com.jgoodies.forms.factories.*; -import com.jgoodies.forms.layout.*; - -import com.quollwriter.*; -import com.quollwriter.ui.*; -import com.quollwriter.editors.ui.sidebars.*; -import com.quollwriter.data.*; -import com.quollwriter.ui.components.ImagePanel; -import com.quollwriter.editors.messages.*; -import com.quollwriter.editors.*; -import com.quollwriter.text.*; -import com.quollwriter.events.*; - -import static com.quollwriter.LanguageStrings.*; -import static com.quollwriter.Environment.getUIString; - -public class UpdateProjectMessageBox extends MessageBox implements EditorChangedListener -{ - - private Box responseBox = null; - private ProjectSentReceivedViewer sentViewer = null; - private JLabel previousLabel = null; - - public UpdateProjectMessageBox (UpdateProjectMessage mess, - AbstractViewer viewer) - { - - super (mess, - viewer); - - } - - @Override - public void editorChanged (EditorChangedEvent ev) - { - - if (ev.getEditor () == this.message.getEditor ()) - { - - this.updateForEditor (); - - } - - } - - private void updateForEditor () - { - - this.previousLabel.setVisible (false); - - if ((!this.message.isDealtWith ()) - && - (this.message.getEditor ().isPrevious ()) - ) - { - - this.previousLabel.setText (String.format (getUIString (editors,messages,updateproject,received,undealtwith,previouseditor), - //"%s is a previous {contact}. This message can no longer be acted upon.", - this.message.getEditor ().getShortName ())); - - this.previousLabel.setVisible (true); - - this.responseBox.setVisible (false); - - } - - } - - @Override - public boolean isShowAttentionBorder () - { - - if (this.message.getEditor ().isPrevious ()) - { - - return false; - - } - - return super.isShowAttentionBorder (); - - } - - @Override - public boolean isAutoDealtWith () - { - - return false; - - } - - public void doUpdate () - { - - this.responseBox.setVisible (!this.message.isDealtWith ()); - - } - - public void doInit () - { - - EditorsEnvironment.addEditorChangedListener (this); - - final UpdateProjectMessageBox _this = this; - - String text = getUIString (editors,messages,updateproject,sent,title); - //"{Project} update sent";//Sent {project} update"; - - if (!this.message.isSentByMe ()) - { - - text = getUIString (editors,messages,updateproject,received,title); - //"{Project} update received"; //Received {project} update"; - - } - - JComponent h = UIUtils.createBoldSubHeader (text, - Constants.EDIT_ICON_NAME); - - this.add (h); - - JComponent bp = EditorsUIUtils.getProjectMessageDetails (this.message, - this.viewer, - this); - bp.setBorder (UIUtils.createPadding (0, 5, 0, 5)); - - this.add (bp); - - this.responseBox = new Box (BoxLayout.Y_AXIS); - - this.responseBox.setVisible (false); - - this.add (this.responseBox); - - this.previousLabel = UIUtils.createInformationLabel (""); - - this.add (this.previousLabel); - - this.updateForEditor (); - - if (!this.message.isSentByMe ()) - { - - ActionListener updateOrView = new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - EditorsUIUtils.showProjectUpdate (_this.message, - _this.viewer, - null); - - } - - }; - - // Not sent by me. - if ((!this.message.isDealtWith ()) - && - (!this.message.getEditor ().isPrevious ()) - ) - { - - JButton update = UIUtils.createButton (getUIString (editors,messages,updateproject,received,undealtwith,buttons,LanguageStrings.update), - //"Update the {project}", - updateOrView); - - //update.setToolTipText ("Click to update the {project}"); - - JButton[] buts = new JButton[] { update }; - - JComponent bb = UIUtils.createButtonBar2 (buts, - Component.LEFT_ALIGNMENT); - - bb.setAlignmentX (Component.LEFT_ALIGNMENT); - - this.responseBox.add (bb); - this.responseBox.setVisible (true); - - } - - } - - } - -} diff --git a/src/com/quollwriter/editors/ui/panels/ChapterCommentsPanel.java b/src/com/quollwriter/editors/ui/panels/ChapterCommentsPanel.java deleted file mode 100644 index 71d0ed1d..00000000 --- a/src/com/quollwriter/editors/ui/panels/ChapterCommentsPanel.java +++ /dev/null @@ -1,604 +0,0 @@ -package com.quollwriter.editors.ui.panels; - -import java.awt.*; -import java.awt.im.*; -import java.awt.event.*; - -import java.io.*; - -import java.text.*; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -import javax.swing.*; -import javax.swing.border.*; -import javax.swing.event.*; -import javax.swing.text.*; -import javax.swing.undo.*; -import java.awt.datatransfer.*; - -//import org.incava.util.diff.*; - -import com.gentlyweb.properties.*; - -import com.jgoodies.forms.builder.*; -import com.jgoodies.forms.factories.*; -import com.jgoodies.forms.layout.*; - -import com.quollwriter.*; -import com.quollwriter.ui.*; -import com.quollwriter.editors.ui.*; -import com.quollwriter.ui.panels.*; -import com.quollwriter.data.*; - -import com.quollwriter.text.*; -import com.quollwriter.text.rules.*; - -import com.quollwriter.ui.actionHandlers.*; -import com.quollwriter.ui.components.ActionAdapter; -import com.quollwriter.ui.components.Header; -import com.quollwriter.ui.components.ImagePanel; -import com.quollwriter.ui.components.QTextEditor; -import com.quollwriter.ui.components.ScrollablePanel; -import com.quollwriter.ui.components.BlockPainter; -import com.quollwriter.ui.renderers.*; - -import static com.quollwriter.LanguageStrings.*; -import static com.quollwriter.Environment.getUIString; - -public class ChapterCommentsPanel extends AbstractViewOnlyEditorPanel implements ChapterItemViewer -{ - - private IconColumn iconColumn = null; - protected ProjectSentReceivedViewer projectViewer = null; - private int lastCaret = -1; - private ChapterItemTransferHandler chItemTransferHandler = null; - private BlockPainter highlight = null; - private boolean chapterItemEditVisible = false; - - public ChapterCommentsPanel (ProjectSentReceivedViewer pv, - Chapter c) - throws GeneralException - { - - super (pv, - c); - - this.projectViewer = pv; - - final ChapterCommentsPanel _this = this; - - this.editor.setEditable (false); - this.editor.setCanCopy (false); - - this.iconColumn = new IconColumn (this, - c, - this.projectViewer.getIconProvider (), - this.projectViewer.getChapterItemViewPopupProvider ()); - - this.iconColumn.setItemMoveAllowed (false); - this.iconColumn.setSinglePopupOnly (true); - - this.chItemTransferHandler = new ChapterItemTransferHandler (this.getIconColumn ()); - - //this.setTransferHandler (this.chItemTransferHandler); - - InputMap im = this.editor.getInputMap (JComponent.WHEN_IN_FOCUSED_WINDOW); - - // Remove ctrl+shift+O from the when_focused set since it conflicts. - this.editor.getInputMap (JComponent.WHEN_FOCUSED).put (KeyStroke.getKeyStroke ("ctrl shift O"), - "none"); - - this.highlight = new BlockPainter (Environment.getHighlightColor ()); - - } - - @Override - public void scrollCaretIntoView () - { - - // Do nothing. - - } - - /* - public void showDifferences (Chapter c) - { - - BlockPainter newp = new BlockPainter (Color.GREEN); - BlockPainter modp = new BlockPainter (Color.YELLOW); - BlockPainter oldp = new BlockPainter (Color.RED); - - String ot = TextUtilities.stripNonValidXMLCharacters (this.editor.getTextWithMarkup ().getText ()); - - String nt = TextUtilities.stripNonValidXMLCharacters (c.getText ().getText ()); - - this.editor.setTextWithMarkup (c.getText ()); - - String[] oldText = ot.split ("\\n"); - String[] newText = nt.split ("\\n"); -System.out.println ("OT: " + ot); -System.out.println ("NT: " + nt); -//LinkedList -diff_match_patch dmp = new diff_match_patch (); - System.out.println ("DIFF2: " + dmp.patch_make(ot, nt)); - - List diffs = new Diff (oldText, - newText).diff (); -System.out.println ("DIFF: " + diffs); - for (int i = 0; i < diffs.size (); i++) - { - - Difference d = (Difference) diffs.get (i); - - if (d.getDeletedEnd () == Difference.NONE) - { - - // This is an addition. - for (int k = d.getAddedStart (); k < (d.getAddedEnd () + 1); k++) - { - - this.editor.addHighlight (d.getAddedStart (), - d.getAddedEnd (), - newp, - false); - - } - - continue; - - } - - if (d.getAddedEnd () == Difference.NONE) - { - - // This is a deletion. - for (int k = d.getDeletedStart (); k < (d.getDeletedEnd () + 1); k++) - { - - this.editor.addHighlight (d.getDeletedStart (), - d.getDeletedEnd (), - oldp, - false); - - } - - continue; - - } - - // This is a modification. - for (int k = d.getAddedStart (); k < (d.getAddedEnd () + 1); k++) - { - - this.editor.addHighlight (d.getAddedStart (), - d.getAddedEnd (), - modp, - false); - - } - - } - - } - */ - @Override - public void setState (final Map s, - boolean hasFocus) - { - - if (hasFocus) - { - - this.editor.grabFocus (); - - } - - } - - public void setChapterItemEditVisible (boolean v) - { - - this.chapterItemEditVisible = v; - - } - - public boolean isChapterItemEditVisible () - { - - return this.chapterItemEditVisible; - - } - - public int getTextPositionForMousePosition (Point p) - { - - Point pp = p; - - if (this.iconColumn.getMousePosition () != null) - { - - pp = new Point (0, - p.y); - - } - - return this.editor.viewToModel (pp); - - } - - public ActionListener getActionListenerForTextPosition (final String actionName, - final Point p) - { - - final ChapterCommentsPanel _this = this; - - final int pos = this.getTextPositionForMousePosition (p); - - return new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.performAction (ev, - actionName, - pos); - - } - - }; - - } - - public ChapterItemTransferHandler getChapterItemTransferHandler () - { - - return this.chItemTransferHandler; - - } - - public int getIconColumnXOffset (ChapterItem i) - { - - int xOffset = 22; - - if (i instanceof OutlineItem) - { - - xOffset = 22; - - } - - return xOffset; - - } - - public JComponent getEditorWrapper (QTextEditor q) - { - - Box b = new Box /*com.quollwriter.ui.components.ScrollableBox*/ (BoxLayout.X_AXIS); - b.add (this.iconColumn); - b.add (q); - q.setMaximumSize (new Dimension (Integer.MAX_VALUE, Integer.MAX_VALUE)); - - q.setMinimumSize (new Dimension (200, 200)); - q.setAlignmentY (Component.TOP_ALIGNMENT); - q.setAlignmentX (Component.LEFT_ALIGNMENT); - - this.iconColumn.setAlignmentY (Component.TOP_ALIGNMENT); - this.iconColumn.setAlignmentX (Component.LEFT_ALIGNMENT); - this.iconColumn.setMinimumSize (new Dimension (32, 200)); - this.iconColumn.setPreferredSize (new Dimension (32, 200)); - this.iconColumn.setMaximumSize (new Dimension (32, Integer.MAX_VALUE)); - - JPanel p = new ScrollablePanel (new BorderLayout ()); - p.add (b); - - return p; - - } - - @Override - public void doFillToolsPopupMenu (ActionEvent ev, - JPopupMenu p) - { - - } - - @Override - public void fillToolBar (JToolBar acts, - final boolean fullScreen) - { - - final AbstractEditorPanel _this = this; - - this.doFillToolBar (acts); - - acts.add (this.createToolbarButton (Constants.EDIT_PROPERTIES_ICON_NAME, - getUIString (editors,projectsent,commentspanel,toolbar,textproperties,tooltip), - //"Click to edit the text properties", - EDIT_TEXT_PROPERTIES_ACTION_NAME)); - - } - - public void doFillToolBar (JToolBar acts) - { - - final ChapterCommentsPanel _this = this; - - ActionAdapter aa = new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.performAction (ev); - - } - - }; - - } - - private void performAction (ActionEvent ev, - String c, - int pos) - { - - if (c == null) - { - - return; - - } - - } - - private void performAction (ActionEvent ev, - int pos) - { - - String c = ev.getActionCommand (); - - this.performAction (ev, - c, - pos); - - } - - public void fillPopupMenu (final MouseEvent ev, - final JPopupMenu popup) - { - - boolean compress = UserProperties.getAsBoolean (Constants.COMPRESS_CHAPTER_CONTEXT_MENU_PROPERTY_NAME); - - this.doFillPopupMenu (ev, - popup, - compress); - - } - - public void doFillPopupMenu (final MouseEvent ev, - final JPopupMenu popup, - boolean compress) - { - - final ChapterCommentsPanel _this = this; - - final QTextEditor editor = this.editor; - - JMenuItem mi = null; - - // Get the mouse position, don't get it later since the mouse could have moved. - Point mP = this.editor.getMousePosition (); - - if (mP == null) - { - - mP = this.iconColumn.getMousePosition (); - - } - - final Point mouseP = mP; - - int pos = this.getTextPositionForMousePosition (ev.getPoint ()); - - // This is needed to move to the correct character, the call above seems to get the character - // before what was clicked on. - // pos++; - - if (compress) - { - - List buts = new ArrayList (); - - buts.add (this.createButton (Constants.FIND_ICON_NAME, - Constants.ICON_MENU, - getUIString (editors,projectsent,commentspanel,popupmenu,Chapter.OBJECT_TYPE,items,find,tooltip), - //"Find", - Constants.SHOW_FIND_ACTION)); - - popup.add (UIUtils.createPopupMenuButtonBar (getUIString (editors,projectsent,commentspanel,popupmenu,Chapter.OBJECT_TYPE,compresstext), - //Environment.replaceObjectNames ("{Chapter}"), - popup, - buts)); - - } else { - - mi = this.createMenuItem (getUIString (editors,projectsent,commentspanel,popupmenu,Chapter.OBJECT_TYPE,items,find,text), - //"Find", - Constants.FIND_ICON_NAME, - Constants.SHOW_FIND_ACTION, - KeyStroke.getKeyStroke (KeyEvent.VK_F, - ActionEvent.CTRL_MASK)); - mi.setMnemonic (KeyEvent.VK_F); - popup.add (mi); - - } - - } - - public IconColumn getIconColumn () - { - - return this.iconColumn; - - } - - public QTextEditor getEditor () - { - - return this.editor; - - } - - public void scrollToItem (ChapterItem i) - throws GeneralException - { - - this.scrollToPosition (i.getPosition ()); - - } - - public void showNote (Note n) - throws GeneralException - { - - this.scrollToNote (n); - - this.iconColumn.showItem (n); - - } - - public void removeItemHighlightTextFromEditor (ChapterItem it) - { - - this.editor.removeAllHighlights (this.highlight); - - } - - public void highlightItemTextInEditor (ChapterItem it) - { - - this.editor.removeAllHighlights (this.highlight); - this.editor.addHighlight (it.getStartPosition (), - it.getEndPosition (), - this.highlight, - false); - - } - - public void scrollToNote (Note n) - throws GeneralException - { - - this.scrollToPosition (n.getPosition ()); - - } - - public List getTopLevelComponents () - { - - List l = new ArrayList (); - l.add (this.iconColumn); - l.add (this.editor); - - return l; - - } - - public void refresh (NamedObject n) - { - - // No need to do anything. - - } - - public void reinitIconColumn () - throws GeneralException - { - - try - { - - this.iconColumn.init (); - - } catch (Exception e) { - - throw new GeneralException ("Unable to init icon column", - e); - - } - - } - - @Override - public void init () - throws GeneralException - { - - super.init (); - - final ChapterCommentsPanel _this = this; - - this.reinitIconColumn (); - - this.setReadyForUse (true); - - } - - @Override - public void close () - { - - super.close (); - - } - - public void restoreBackgroundColor () - { - - super.restoreBackgroundColor (); - - //this.iconColumn.setBackground (IconColumn.defaultBGColor); - - } - - public void setBackgroundColor (Color c) - { - - super.setBackgroundColor (c); -/* - if (c.equals (Color.white)) - { - - this.iconColumn.setBackground (IconColumn.defaultBGColor); - - } else - { - - this.iconColumn.setBackground (c); - - } -*/ - } - - public void removeItem (ChapterItem c) - { - - throw new UnsupportedOperationException ("Not supported for project comments viewing."); - - } - - public void addItem (ChapterItem c) - throws GeneralException - { - - throw new UnsupportedOperationException ("Not supported for project comments viewing."); - - } - -} diff --git a/src/com/quollwriter/editors/ui/panels/EditorChapterPanel.java b/src/com/quollwriter/editors/ui/panels/EditorChapterPanel.java deleted file mode 100644 index 6d7e0519..00000000 --- a/src/com/quollwriter/editors/ui/panels/EditorChapterPanel.java +++ /dev/null @@ -1,1045 +0,0 @@ -package com.quollwriter.editors.ui.panels; - -import java.awt.*; -import java.awt.im.*; -import java.awt.event.*; - -import java.io.*; - -import java.text.*; - -import java.util.ArrayList; -import java.util.List; -import java.util.Arrays; - -import javax.swing.*; -import javax.swing.border.*; -import javax.swing.event.*; -import javax.swing.text.*; -import javax.swing.undo.*; -import java.awt.datatransfer.*; - -import com.gentlyweb.properties.*; - -import com.jgoodies.forms.builder.*; -import com.jgoodies.forms.factories.*; -import com.jgoodies.forms.layout.*; - -import com.quollwriter.*; -import com.quollwriter.ui.*; -import com.quollwriter.editors.ui.*; -import com.quollwriter.ui.panels.*; -import com.quollwriter.data.*; -import com.quollwriter.events.*; - -import com.quollwriter.text.*; -import com.quollwriter.text.rules.*; - -import com.quollwriter.ui.actionHandlers.*; -import com.quollwriter.ui.components.ActionAdapter; -import com.quollwriter.ui.components.Header; -import com.quollwriter.ui.components.ImagePanel; -import com.quollwriter.ui.components.QTextEditor; -import com.quollwriter.ui.components.ScrollablePanel; -import com.quollwriter.ui.components.BlockPainter; -import com.quollwriter.ui.renderers.*; - -import com.swabunga.spell.engine.*; -import com.swabunga.spell.event.*; - -import static com.quollwriter.LanguageStrings.*; -import static com.quollwriter.Environment.getUIString; - -public class EditorChapterPanel extends AbstractViewOnlyEditorPanel implements ChapterItemViewer -{ - - public static final String CHAPTER_INFO_ACTION_NAME = "chapter-info"; - public static final String SET_EDIT_COMPLETE_ACTION_NAME = "set-edit-complete"; - public static final String REMOVE_EDIT_POINT_ACTION_NAME = "remove-edit-point"; - - public static final String NEW_COMMENT_ACTION_NAME = "newcomment"; - - private IconColumn iconColumn = null; - protected EditorProjectViewer projectViewer = null; - private int lastCaret = -1; - private ChapterItemTransferHandler chItemTransferHandler = null; - private BlockPainter highlight = null; - private boolean chapterItemEditVisible = false; - - public EditorChapterPanel (EditorProjectViewer pv, - Chapter c) - throws GeneralException - { - - super (pv, - c); - - this.projectViewer = pv; - - final EditorChapterPanel _this = this; - - this.editor.setEditable (false); - this.editor.setCanCopy (false); - - this.iconColumn = new IconColumn (this, - c, - this.projectViewer.getIconProvider (), - this.projectViewer.getChapterItemViewPopupProvider ()); - - this.iconColumn.addMouseListener (new MouseEventHandler () - { - - public void handleDoublePress (MouseEvent ev) - { - - _this.getActionListenerForTextPosition (NEW_COMMENT_ACTION_NAME, - ev.getPoint ()).actionPerformed (new ActionEvent (_this, 1, "show")); - - } - - }); - - this.editor.addCaretListener (new CaretListener () - { - - public void caretUpdate (CaretEvent ev) - { - - if ((_this.editor.getSelectionEnd () > _this.editor.getSelectionStart ()) - && - (!_this.isChapterItemEditVisible ()) - && - (_this.isReadyForUse ()) - ) - { - - _this.performAction (new ActionEvent (_this, 1, "show"), - NEW_COMMENT_ACTION_NAME, - _this.editor.getSelectionStart ()); - - } - - } - - }); - - this.chItemTransferHandler = new ChapterItemTransferHandler (this.getIconColumn ()); - - this.setTransferHandler (this.chItemTransferHandler); - - this.actions.put (REMOVE_EDIT_POINT_ACTION_NAME, - new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.removeEditPosition (); - - } - - }); - - this.actions.put (SET_EDIT_COMPLETE_ACTION_NAME, - new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.setEditComplete (true); - - } - - }); - - this.actions.put (NEW_COMMENT_ACTION_NAME, - new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.performAction (ev, - NEW_COMMENT_ACTION_NAME, - -1); - - } - - }); - - this.actions.put (CHAPTER_INFO_ACTION_NAME, - new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - try - { - - _this.projectViewer.viewEditorChapterInformation (_this.obj); - - } catch (Exception e) - { - - Environment.logError ("Unable to show chapter information for: " + - _this.obj, - e); - - UIUtils.showErrorMessage (_this, - getUIString (editors,project,LanguageStrings.actions,showchapterinfo,actionerror)); - //Environment.replaceObjectNames ("Unable to show {chapter}.")); - - } - - } - - }); - - InputMap im = this.editor.getInputMap (JComponent.WHEN_IN_FOCUSED_WINDOW); - - // Remove ctrl+shift+O from the when_focused set since it conflicts. - this.editor.getInputMap (JComponent.WHEN_FOCUSED).put (KeyStroke.getKeyStroke ("ctrl shift O"), - "none"); - - im.put (KeyStroke.getKeyStroke ("ctrl shift C"), - NEW_COMMENT_ACTION_NAME); - - this.highlight = new BlockPainter (Environment.getHighlightColor ()); - - } - - public void setChapterItemEditVisible (boolean v) - { - - this.chapterItemEditVisible = v; - - } - - public boolean isChapterItemEditVisible () - { - - return this.chapterItemEditVisible; - - } - - public int getTextPositionForMousePosition (Point p) - { - - Point pp = p; - - if (this.iconColumn.getMousePosition () != null) - { - - pp = new Point (0, - p.y); - - } - - return this.editor.viewToModel (pp); - - } - - public ActionListener getActionListenerForTextPosition (final String actionName, - final Point p) - { - - final EditorChapterPanel _this = this; - - final int pos = this.getTextPositionForMousePosition (p); - - return new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.performAction (ev, - actionName, - pos); - - } - - }; - - } - - public ChapterItemTransferHandler getChapterItemTransferHandler () - { - - return this.chItemTransferHandler; - - } - - public int getIconColumnXOffset (ChapterItem i) - { - - int xOffset = 22; - - if (i instanceof OutlineItem) - { - - xOffset = 22; - - } - - return xOffset; - - } - - public JComponent getEditorWrapper (QTextEditor q) - { - - Box b = new Box /*com.quollwriter.ui.components.ScrollableBox*/ (BoxLayout.X_AXIS); - b.add (this.iconColumn); - b.add (q); - q.setMaximumSize (new Dimension (Integer.MAX_VALUE, Integer.MAX_VALUE)); - - q.setMinimumSize (new Dimension (200, 200)); - q.setAlignmentY (Component.TOP_ALIGNMENT); - q.setAlignmentX (Component.LEFT_ALIGNMENT); - - this.iconColumn.setAlignmentY (Component.TOP_ALIGNMENT); - this.iconColumn.setAlignmentX (Component.LEFT_ALIGNMENT); - this.iconColumn.setMinimumSize (new Dimension (32, 200)); - this.iconColumn.setPreferredSize (new Dimension (32, 200)); - this.iconColumn.setMaximumSize (new Dimension (32, Integer.MAX_VALUE)); - - JPanel p = new ScrollablePanel (new BorderLayout ()); - p.add (b); - - return p; - - } - - public void doFillToolsPopupMenu (ActionEvent ev, - JPopupMenu p) - { - - } - - @Override - public void fillToolBar (JToolBar acts, - final boolean fullScreen) - { - - final AbstractEditorPanel _this = this; - - this.doFillToolBar (acts); - - acts.add (this.createToolbarButton (Constants.EDIT_PROPERTIES_ICON_NAME, - getUIString (editors,project,commentspanel,toolbar,textproperties,tooltip), - //"Click to edit the text properties", - EDIT_TEXT_PROPERTIES_ACTION_NAME)); - - } - - public void doFillToolBar (JToolBar acts) - { - - final EditorChapterPanel _this = this; - - ActionAdapter aa = new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.performAction (ev); - - } - - }; - - final JButton b = UIUtils.createToolBarButton ("new", - getUIString (editors,project,commentspanel,toolbar,newcomment,tooltip), - //"Click to add a new {Comment}", - "new", - null); - - ActionAdapter ab = new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - JPopupMenu m = new JPopupMenu (); - - _this.addNewItemsForPopupMenu (m, - b, - -1, - false); - - Component c = (Component) ev.getSource (); - - m.show (c, - 10, - 10); - - } - - }; - - b.addActionListener (ab); - - acts.add (b); - - } - - private void performAction (ActionEvent ev, - String c, - int pos) - { - - if (c == null) - { - - return; - - } - - if (c.equals (NEW_COMMENT_ACTION_NAME)) - { - - new CommentActionHandler (this.obj, - this, - pos).actionPerformed (ev); - - return; - - } - - } - - private void performAction (ActionEvent ev, - int pos) - { - - String c = ev.getActionCommand (); - - this.performAction (ev, - c, - pos); - - } - - private void addNewItemsForPopupMenu (final JComponent popup, - Component showAt, - int pos, - boolean compress) - { - - final EditorChapterPanel _this = this; - - final PositionActionAdapter aa = new PositionActionAdapter (pos) - { - - public void actionPerformed (ActionEvent ev) - { - - _this.performAction (ev, - this.pos); - - } - - }; - - if (compress) - { - - List buts = new ArrayList (); - - buts.add (this.createButton (Constants.COMMENT_ICON_NAME, - Constants.ICON_MENU, - getUIString (editors,project,commentspanel,popupmenu,_new,items,comment,tooltip), - //String.format ("Add a new {Comment}"), - NEW_COMMENT_ACTION_NAME, - aa)); - - if (popup instanceof JPopupMenu) - { - - JPopupMenu pm = (JPopupMenu) popup; - - pm.addSeparator (); - - popup.add (UIUtils.createPopupMenuButtonBar (getUIString (editors,project,commentspanel,popupmenu,_new,compresstext), - //"New", - pm, - buts)); - - } - - } else { - - String pref = getUIString (general,shortcutprefix); - //"Shortcut: Ctrl+Shift+"; - - JMenuItem mi = null; - - mi = this.createMenuItem (getUIString (editors,project,commentspanel,popupmenu,_new,items,comment,text), - //"Comment", - Constants.COMMENT_ICON_NAME, - NEW_COMMENT_ACTION_NAME, - null, - aa); - - popup.add (mi); - - char fc = 'C'; - - mi.setMnemonic (fc); - mi.setToolTipText (pref + fc); - - } - - } - - public void setEditPosition (int textPos) - { - - try - { - - int tl = Utils.stripEnd (this.editor.getText ()).length (); - - if (textPos > tl) - { - - textPos = tl; - - } - - this.iconColumn.setEditPosition (textPos); - - // See if we are on the last line (it may be that the user is in the icon - // column). - Rectangle pp = this.editor.modelToView (textPos); - - if (UserProperties.getAsBoolean (Constants.SET_CHAPTER_AS_EDIT_COMPLETE_WHEN_EDIT_POSITION_IS_AT_END_OF_CHAPTER_PROPERTY_NAME)) - { - - if (textPos < tl) - { - - Rectangle ep = this.editor.modelToView (tl); - - boolean complete = false; - - if (ep.y == pp.y) - { - - complete = true; - - } - - // Last line. - this.obj.setEditComplete (complete); - - } - - } - - this.projectViewer.reloadChapterTree (); - - this.projectViewer.saveObject (this.obj, - false); - - } catch (Exception e) { - - Environment.logError ("Unable to set edit position for chapter: " + - this.obj, - e); - - } - - } - - public void setEditPosition (Point mouseP) - { - - this.setEditPosition (this.editor.viewToModel (mouseP)); - - } - - public void removeEditPosition () - { - - try - { - - this.iconColumn.setEditPosition (-1); - - this.setEditComplete (false); - - this.projectViewer.saveObject (this.obj, - false); - - this.projectViewer.reloadChapterTree (); - - } catch (Exception e) { - - Environment.logError ("Unable to set edit position for chapter: " + - this.obj, - e); - - } - - } - - public void setEditComplete (boolean v) - { - - try - { - - this.obj.setEditComplete (v); - - if (v) - { - - int tl = Utils.stripEnd (this.editor.getText ()).length (); - - this.iconColumn.setEditPosition (tl); - - } - - this.projectViewer.saveObject (this.obj, - false); - - this.iconColumn.init (); - - this.projectViewer.reloadChapterTree (); - - } catch (Exception e) { - - Environment.logError ("Unable to set edit complete for chapter: " + - this.obj, - e); - - } - - } - - public void fillPopupMenu (final MouseEvent ev, - final JPopupMenu popup) - { - - boolean compress = UserProperties.getAsBoolean (Constants.COMPRESS_CHAPTER_CONTEXT_MENU_PROPERTY_NAME); - - this.doFillPopupMenu (ev, - popup, - compress); - - } - - public void doFillPopupMenu (final MouseEvent ev, - final JPopupMenu popup, - boolean compress) - { - - final EditorChapterPanel _this = this; - - final QTextEditor editor = this.editor; - - JMenuItem mi = null; - - // Get the mouse position, don't get it later since the mouse could have moved. - Point mP = this.editor.getMousePosition (); - - if (mP == null) - { - - mP = this.iconColumn.getMousePosition (); - - } - - final Point mouseP = mP; - - int pos = this.getTextPositionForMousePosition (ev.getPoint ()); - - // This is needed to move to the correct character, the call above seems to get the character - // before what was clicked on. - // pos++; - java.util.List prefix = Arrays.asList (editors,project,commentspanel,popupmenu,Chapter.OBJECT_TYPE); - - if (compress) - { - - List buts = new ArrayList (); - - buts.add (UIUtils.createButton (Constants.EDIT_IN_PROGRESS_ICON_NAME, - Constants.ICON_MENU, - getUIString (prefix,items,seteditposition,tooltip), - //"Set Edit Point", - new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.setEditPosition (mouseP); - - } - - })); - - if (this.obj.getEditPosition () > 0) - { - - buts.add (this.createButton (Constants.REMOVE_EDIT_POINT_ICON_NAME, - Constants.ICON_MENU, - getUIString (prefix,items,removeeditposition,tooltip), - //"Remove Edit Point", - REMOVE_EDIT_POINT_ACTION_NAME)); - - } - - if (!this.obj.isEditComplete ()) - { - - buts.add (this.createButton (Constants.EDIT_COMPLETE_ICON_NAME, - Constants.ICON_MENU, - getUIString (prefix,items,seteditcomplete,tooltip), - //"Set as Edit Complete", - SET_EDIT_COMPLETE_ACTION_NAME)); - - } - - buts.add (this.createButton (Constants.FIND_ICON_NAME, - Constants.ICON_MENU, - getUIString (prefix,items,find,tooltip), - //"Find", - Constants.SHOW_FIND_ACTION)); - - popup.add (UIUtils.createPopupMenuButtonBar (getUIString (prefix,compresstext), - //"{Chapter}", - popup, - buts)); - - this.addNewItemsForPopupMenu (popup, - this, - pos, - compress); - - } else { - - // Save. - - JMenu m = new JMenu (getUIString (prefix,text)); - //Environment.replaceObjectNames ("{Chapter} Edit")); - m.setIcon (Environment.getIcon (Constants.EDIT_ICON_NAME, - Constants.ICON_MENU)); - - popup.add (m); - - mi = UIUtils.createMenuItem (getUIString (prefix,items,seteditposition,tooltip), - //"Set Edit Point", - Constants.EDIT_IN_PROGRESS_ICON_NAME, - new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.setEditPosition (mouseP); - - } - - }); - - m.add (mi); - - if (this.obj.getEditPosition () > 0) - { - - m.add (this.createMenuItem (getUIString (prefix,items,removeeditposition,tooltip), - //"Remove Edit Point", - Constants.REMOVE_EDIT_POINT_ICON_NAME, - REMOVE_EDIT_POINT_ACTION_NAME, - null)); - - } - - if (!this.obj.isEditComplete ()) - { - - m.add (this.createMenuItem (getUIString (prefix,items,seteditcomplete,tooltip), - //"Set as Edit Complete", - Constants.EDIT_COMPLETE_ICON_NAME, - SET_EDIT_COMPLETE_ACTION_NAME, - null)); - - } - - JMenu nm = new JMenu (getUIString (editors,project,commentspanel,popupmenu,_new,text)); - //"New"); - nm.setIcon (Environment.getIcon (Constants.NEW_ICON_NAME, - Constants.ICON_MENU)); - - popup.add (nm); - - this.addNewItemsForPopupMenu (nm, - this, - pos, - compress); - - } - - } - - public IconColumn getIconColumn () - { - - return this.iconColumn; - - } - - public QTextEditor getEditor () - { - - return this.editor; - - } - - public void removeItem (ChapterItem c) - { - - this.iconColumn.removeItem (c); - - } - - public void addItem (ChapterItem c) - throws GeneralException - { - - this.iconColumn.addItem (c); - - } - - public void scrollToItem (ChapterItem i) - throws GeneralException - { - - this.scrollToPosition (i.getPosition ()); - - } - - public void editNote (Note n) - throws GeneralException - { - - this.scrollToNote (n); - - new CommentActionHandler (n, - this).actionPerformed (new ActionEvent (this, - 0, - "edit")); - - } - - public void showNote (Note n, - ActionListener doAfterShow) - throws GeneralException - { - - this.scrollToNote (n); - - this.iconColumn.showItem (n); - - if (doAfterShow != null) - { - - doAfterShow.actionPerformed (new ActionEvent (this, 1, "noteshown")); - - } - - } - - public void removeItemHighlightTextFromEditor (ChapterItem it) - { - - this.editor.removeAllHighlights (this.highlight); - - } - - public void highlightItemTextInEditor (ChapterItem it) - { - - this.editor.removeAllHighlights (this.highlight); - this.editor.addHighlight (it.getStartPosition (), - it.getEndPosition (), - this.highlight, - false); - - } - - public void scrollToNote (Note n) - throws GeneralException - { - - this.scrollToPosition (n.getPosition ()); - - } - - public List getTopLevelComponents () - { - - List l = new ArrayList (); - l.add (this.iconColumn); - l.add (this.editor); - - return l; - - } - - public void refresh (NamedObject n) - { - - // No need to do anything. - - } - - @Override - public void init () - throws GeneralException - { - - super.init (); - - try - { - - this.iconColumn.init (); - - } catch (Exception e) { - - throw new GeneralException ("Unable to init icon column", - e); - - } - - this.setCaretPosition (0); - - this.setReadyForUse (true); - - } - - public void restoreBackgroundColor () - { - - super.restoreBackgroundColor (); - - //this.iconColumn.setBackground (IconColumn.defaultBGColor); - - } - - public void setBackgroundColor (Color c) - { - - super.setBackgroundColor (c); -/* - if (c.equals (Color.white)) - { - - this.iconColumn.setBackground (IconColumn.defaultBGColor); - - } else - { - - this.iconColumn.setBackground (c); - - } -*/ - } - - private static class CutNPasteTransferHandler extends TransferHandler - { - public void exportToClipboard(JComponent comp, Clipboard clipboard, - int action) - throws IllegalStateException - { - - if (comp instanceof JTextComponent) - { - - JTextComponent text = (JTextComponent)comp; - int p0 = text.getSelectionStart(); - int p1 = text.getSelectionEnd(); - if (p0 != p1) { - try { - Document doc = text.getDocument(); - String srcData = doc.getText(p0, p1 - p0); - - StringSelection contents =new StringSelection(srcData); - - // this may throw an IllegalStateException, - // but it will be caught and handled in the - // action that invoked this method - clipboard.setContents(contents, null); - - if (action == TransferHandler.MOVE) { - doc.remove(p0, p1 - p0); - } - } catch (BadLocationException ble) {} - } - } - } - - public boolean importData(JComponent comp, Transferable t) - { - - if (comp instanceof JTextComponent) { - DataFlavor flavor = getFlavor(t.getTransferDataFlavors()); - - if (flavor != null) { - InputContext ic = comp.getInputContext(); - if (ic != null) { - ic.endComposition(); - } - try { - String data = (String)t.getTransferData(flavor); - - ((JTextComponent)comp).replaceSelection(data); - return true; - } catch (UnsupportedFlavorException ufe) { - } catch (IOException ioe) { - } - } - } - return false; - } - - public boolean canImport(JComponent comp, - DataFlavor[] transferFlavors) - { - - JTextComponent c = (JTextComponent)comp; - if (!(c.isEditable() && c.isEnabled())) { - return false; - } - return (getFlavor(transferFlavors) != null); - } - - public int getSourceActions(JComponent c) - { - - return NONE; - - } - - private DataFlavor getFlavor(DataFlavor[] flavors) - { - if (flavors != null) { - for (int counter = 0; counter < flavors.length; counter++) { - if (flavors[counter].equals(DataFlavor.stringFlavor)) { - return flavors[counter]; - } - } - } - return null; - } - } - -} diff --git a/src/com/quollwriter/editors/ui/sidebars/EditorPanel.java b/src/com/quollwriter/editors/ui/sidebars/EditorPanel.java deleted file mode 100644 index f82b3c2c..00000000 --- a/src/com/quollwriter/editors/ui/sidebars/EditorPanel.java +++ /dev/null @@ -1,723 +0,0 @@ -package com.quollwriter.editors.ui.sidebars; - -import java.awt.Component; -import java.awt.Dimension; -import java.awt.Color; -import java.awt.CardLayout; -import java.awt.image.*; - -import java.awt.event.*; - -import java.io.*; - -import java.util.Date; -import java.util.List; -import java.util.Map; -import java.util.TreeMap; -import java.util.Set; -import java.util.LinkedHashSet; -import java.util.ArrayList; -import java.util.GregorianCalendar; -import java.util.Calendar; - -import javax.swing.*; -import javax.swing.border.*; - -import org.josql.*; - -import com.quollwriter.*; -import com.quollwriter.data.*; -import com.quollwriter.data.editors.*; -import com.quollwriter.editors.*; -import com.quollwriter.editors.ui.*; -import com.quollwriter.editors.messages.*; -import com.quollwriter.ui.*; -import com.quollwriter.events.*; -import com.quollwriter.ui.components.ActionAdapter; -import com.quollwriter.ui.components.ImagePanel; -import com.quollwriter.ui.components.ScrollableBox; -import com.quollwriter.ui.components.Header; - -import static com.quollwriter.LanguageStrings.*; -import static com.quollwriter.Environment.getUIString; - -public class EditorPanel extends Box implements EditorMessageListener -{ - - private AbstractViewer viewer = null; - private EditorsSideBar sideBar = null; - private EditorChatBox chatBox = null; - //private JTextArea message = null; - private boolean typed = false; - private EditorEditor editor = null; - private Map chatHistory = new TreeMap (); - private Box chatHistoryBox = null; - private JTextField find = null; - private Box findBox = null; - private Box findResults = null; - private JScrollPane chatHistoryScrollPane = null; - - private Set messages = null; - private Timer dateLabelsUpdate = null; - private JPanel cards = null; - private Project project = null; - private ProjectEditor projectEditor = null; - - private boolean showChatBox = true; - - - - public EditorPanel (EditorsSideBar sb, - EditorEditor ed, - Set messages) - throws GeneralException - { - - super (BoxLayout.Y_AXIS); - - this.viewer = sb.getViewer (); - this.sideBar = sb; - this.editor = ed; - this.messages = messages; - - if (viewer instanceof AbstractProjectViewer) - { - - AbstractProjectViewer pv = (AbstractProjectViewer) viewer; - this.project = pv.getProject (); - this.projectEditor = this.project.getProjectEditor (this.editor); - - } - - EditorsEnvironment.addEditorMessageListener (this); - - Project np = null; - - this.createAboutBox (); - - this.cards = new JPanel (); - this.cards.setLayout (new CardLayout ()); - this.cards.setOpaque (false); - this.cards.setAlignmentX (Component.LEFT_ALIGNMENT); - - this.add (this.cards); - - this.cards.add (this.createChatHistoryCard (), - "chathistory"); - - } - - public EditorPanel (EditorsSideBar sb, - EditorEditor ed) - throws GeneralException - { - - this (sb, - ed, - ed.getMessages ()); - - } - - public void handleMessage (EditorMessageEvent ev) - { - - if (!EditorsUIUtils.getDefaultViewableMessageFilter ().accept (ev.getMessage ())) - { - - return; - - } - - if (ev.getType () == EditorMessageEvent.MESSAGE_ADDED) - { - - this.addMessage (ev.getMessage ()); - - return; - - } - - } - - public void addMessage (EditorMessage mess) - { - - if (mess instanceof EditorChatMessage) - { - - EditorChatMessage cmess = (EditorChatMessage) mess; - - if (this.isShowing ()) - { - - cmess.setDealtWith (true); - - try - { - - EditorsEnvironment.updateMessage (cmess); - - } catch (Exception e) { - - Environment.logError ("Unable to update message: " + - cmess, - e); - - } - - } - - Date w = Utils.zeroTimeFields (cmess.getWhen ()); - - // See if we have a "today" history box. - ChatMessageAccordionItem it = this.chatHistory.get (w); - - Set messages = null; - - if (it == null) - { - - messages = new LinkedHashSet (); - messages.add (cmess); - - it = new ChatMessageAccordionItem (this.viewer, - w, - messages); - - it.init (); - it.setBorder (UIUtils.createPadding (0, 0, 0, 5)); - - this.chatHistoryBox.add (it); - - this.chatHistory.put (w, - it); - - } else { - - it.addMessage (cmess); - - } - - final EditorPanel _this = this; - - UIUtils.doLater (new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - JScrollBar vertical = _this.chatHistoryScrollPane.getVerticalScrollBar (); - vertical.setValue (vertical.getMaximum ()); - - } - - }); - - } - - } - - public EditorEditor getEditor () - { - - return this.editor; - - } - - private Map> sortChatMessages (Set messages) - { - - Map> ret = new TreeMap (); - - if (messages == null) - { - - return ret; - - } - - for (EditorChatMessage m : messages) - { - - Date w = Utils.zeroTimeFields (m.getWhen ()); - - Set mess = ret.get (w); - - if (mess == null) - { - - mess = new LinkedHashSet (); - ret.put (w, - mess); - - } - - mess.add (m); - - } - - return ret; - - } - - private ChatMessageAccordionItem createChatMessages (Date d, - Set messages) - { - - ChatMessageAccordionItem it = new ChatMessageAccordionItem (this.viewer, - d, - messages); - - this.chatHistory.put (d, - it); - - return it; - - } - - public void showSearch () - { - - // TODO: Not sure about the best way for this since each message is a container around the actual text. - - if (true) - { - - return; - - } - - this.findBox.setVisible (true); - - this.find.selectAll (); - - this.find.grabFocus (); - - } - - private void search () - { - - String f = this.find.getText ().trim (); - - // Ask all messages. - Set matches = this.editor.getMessages (new EditorMessageFilter () - { - - public boolean accept (EditorMessage m) - { - - return true; - - } - - }); - - - } - - private JComponent createChatHistoryCard () - { - - final EditorPanel _this = this; - - Box card = new Box (BoxLayout.Y_AXIS); - card.setAlignmentX (Component.LEFT_ALIGNMENT); - card.setOpaque (false); - - this.find = UIUtils.createSearchBox (750, - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.search (); - - } - - }); - - this.find.setMaximumSize (new Dimension (Short.MAX_VALUE, - this.find.getPreferredSize ().height)); - - this.findBox = new Box (BoxLayout.Y_AXIS); - this.findBox.add (this.find); - - this.findResults = new ScrollableBox (BoxLayout.Y_AXIS); - - this.findBox.add (this.findResults); - - this.findBox.setVisible (false); - - //card.add (this.findBox); - - this.chatHistoryBox = new ScrollableBox (BoxLayout.Y_AXIS); - this.chatHistoryBox.setAlignmentX (Component.LEFT_ALIGNMENT); - - ChatMessageAccordionItem hist = null; - - // Waaaay too much type information here... - // Sort the messages, if present, into date buckets. - - Set fmessages = new LinkedHashSet (); - - int undealtWithCount = 0; - - Project np = null; - - EditorMessageFilter filter = new DefaultEditorMessageFilter (np, - EditorChatMessage.MESSAGE_TYPE); - - for (EditorMessage m : this.messages) - { - - if (filter.accept (m)) - { - - fmessages.add ((EditorChatMessage) m); - - } - - } - - Map> messages = this.sortChatMessages (fmessages); - - Set>> entries = messages.entrySet (); - - long dontShowBefore = System.currentTimeMillis () - (7 * 24 * 60 * 60 *1000); - - for (Map.Entry> en : entries) - { - - hist = this.createChatMessages (en.getKey (), - en.getValue ()); - - hist.setAlignmentX (Component.LEFT_ALIGNMENT); - hist.init (); - hist.setBorder (UIUtils.createPadding (0, 0, 0, 5)); - this.chatHistoryBox.add (hist); - - if (en.getKey ().getTime () < (dontShowBefore)) - { - - hist.setContentVisible (false); - - } - - } - - // Last one should always be visible regardless of age. - if (hist != null) - { - - hist.setContentVisible (true); - - } - - this.chatHistoryScrollPane = UIUtils.createScrollPane (this.chatHistoryBox); - - this.chatHistoryScrollPane.setBorder (null); - - card.add (this.chatHistoryScrollPane); - - if (this.showChatBox) - { - - card.add (Box.createVerticalStrut (5)); - - card.add (this.createChatBox ()); - - } - - return card; - - } - - private void createAboutBox () - throws GeneralException - { - - final EditorPanel _this = this; - - final EditorInfoBox infBox = new EditorInfoBox (this.editor, - this.viewer, - false); - - infBox.setToolTipText (getUIString (editors,LanguageStrings.editor,view,info,tooltip,general)); - //"Right click to see the menu"); - - infBox.addFullPopupListener (); - - infBox.setAlignmentX (Component.LEFT_ALIGNMENT); - - infBox.setBorder (UIUtils.createBottomLineWithPadding (5, 0, 5, 5)); - - infBox.setMaximumSize (new Dimension (Short.MAX_VALUE, - infBox.getPreferredSize ().height)); - infBox.setBorder (new CompoundBorder (UIUtils.createPadding (0, 0, 0, 2), - infBox.getBorder ())); - - infBox.init (); - - this.add (infBox); - - } - - private EditorChatBox createChatBox () - { - - final EditorPanel _this = this; - - this.chatBox = new EditorChatBox (this.editor, - this.viewer).init (); - this.chatBox.setBorder (new CompoundBorder (UIUtils.createPadding (0, 0, 0, 5), - UIUtils.createLineBorder ())); - this.chatBox.setMaximumSize (new Dimension (Short.MAX_VALUE, - this.chatBox.getPreferredSize ().height + 7)); - - if (this.editor.isPrevious ()) - { - - this.chatBox.setVisible (false); - - } - - return this.chatBox; - - } - - public void showChatHistory () - { - - ((CardLayout) this.cards.getLayout ()).show (this.cards, - "chathistory"); - - } - - public void showChatBox () - { - - this.showChatHistory (); - - this.chatBox.grabFocus (); - - } - - private void showMessagesInCard (String cardId, - String title, - String iconType, - String help, - Set messages, - boolean showAttentionBorder) - { - - final EditorPanel _this = this; - - try - { - - // Sort the messages in descending when order or newest first. - Query q = new Query (); - q.parse (String.format ("SELECT * FROM %s ORDER BY when DESC", - EditorMessage.class.getName ())); - - QueryResults qr = q.execute (messages); - - messages = new LinkedHashSet (qr.getResults ()); - - } catch (Exception e) { - - Environment.logError ("Unable to sort messages", - e); - - } - - Box b = new ScrollableBox (BoxLayout.Y_AXIS); - b.setAlignmentX (Component.LEFT_ALIGNMENT); - - for (EditorMessage m : messages) - { - - MessageBox mb = null; - - try - { - - mb = MessageBoxFactory.getMessageBoxInstance (m, - this.viewer); - //mb.setShowAttentionBorder (showAttentionBorder); - - mb.init (); - - } catch (Exception e) { - - Environment.logError ("Unable to get message box for message: " + - m, - e); - - } - - mb.setAlignmentX (Component.LEFT_ALIGNMENT); - - Box wb = new Box (BoxLayout.Y_AXIS); - wb.setAlignmentX (Component.LEFT_ALIGNMENT); - wb.setBorder (UIUtils.createPadding (0, 0, 10, 0)); - wb.add (mb); - - b.add (wb); - - } - - final JScrollPane sp = UIUtils.createScrollPane (b); - - sp.setBorder (null); - sp.setAlignmentX (Component.LEFT_ALIGNMENT); - sp.setBorder (new EmptyBorder (1, 0, 0, 0)); - - Box wrapper = new Box (BoxLayout.Y_AXIS); - wrapper.setAlignmentX (Component.LEFT_ALIGNMENT); - - Header h = new Header (title, - Environment.getIcon (iconType, - Constants.ICON_SIDEBAR), - null); - - JButton close = UIUtils.createButton (Constants.CLOSE_ICON_NAME, - Constants.ICON_MENU, - getUIString (actions,clicktoclose), - //"Click to close", - new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.showChatHistory (); - - } - - }); - - List buts = new ArrayList (); - buts.add (close); - - h.setControls (UIUtils.createButtonBar (buts)); - - h.setFont (h.getFont ().deriveFont ((float) UIUtils.getScaledFontSize (14)).deriveFont (java.awt.Font.PLAIN)); - h.setAlignmentX (Component.LEFT_ALIGNMENT); - - wrapper.add (h); - - if (help != null) - { - - JLabel info = UIUtils.createInformationLabel (help); - info.setBorder (UIUtils.createPadding (0, 5, 5, 5)); - - wrapper.add (info); - - } - - wrapper.add (sp); - - sp.getVerticalScrollBar ().addAdjustmentListener (new AdjustmentListener () - { - - public void adjustmentValueChanged (AdjustmentEvent ev) - { - - if (sp.getVerticalScrollBar ().getValue () > 0) - { - - sp.setBorder (new MatteBorder (1, 0, 0, 0, - UIUtils.getInnerBorderColor ())); - - } else { - - sp.setBorder (new EmptyBorder (1, 0, 0, 0)); - - } - - } - - }); - - this.cards.add (wrapper, - cardId); - - ((CardLayout) this.cards.getLayout ()).show (this.cards, - cardId); - - UIUtils.doLater (new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - sp.getVerticalScrollBar ().setValue (0); - - } - - }); - - } - - public boolean isShowChatBox () - { - - return this.showChatBox; - - } - - public void setShowChatBox (boolean v) - { - - this.showChatBox = v; - - } - - public void init () - throws GeneralException - { - - final EditorPanel _this = this; - - UIUtils.doLater (new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - JScrollBar vertical = _this.chatHistoryScrollPane.getVerticalScrollBar (); - vertical.setValue (vertical.getMaximum ()); - - } - - }); - - // Fire a timer once a minute that updates the history boxes date labels. - // TODO: Schedule so that it only fires just after midnight. - this.dateLabelsUpdate = new Timer (60 * 1000, - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - for (Date d : _this.chatHistory.keySet ()) - { - - _this.chatHistory.get (d).updateHeaderTitle (); - - } - - } - - }); - - this.dateLabelsUpdate.start (); - - } - -} diff --git a/src/com/quollwriter/editors/ui/sidebars/EditorProjectSideBar.java b/src/com/quollwriter/editors/ui/sidebars/EditorProjectSideBar.java deleted file mode 100644 index b53887bb..00000000 --- a/src/com/quollwriter/editors/ui/sidebars/EditorProjectSideBar.java +++ /dev/null @@ -1,679 +0,0 @@ -package com.quollwriter.editors.ui.sidebars; - -import java.awt.Component; -import java.awt.Dimension; -import java.awt.event.*; - -import java.util.Date; -import java.util.Map; -import java.util.HashMap; -import java.util.List; -import java.util.ArrayList; -import java.util.Set; -import java.util.HashSet; -import java.util.LinkedHashSet; -import java.util.Vector; -import java.util.Arrays; - -import javax.swing.*; -import javax.swing.event.*; -import javax.swing.tree.*; -import javax.swing.border.*; - -import org.josql.*; - -import com.quollwriter.*; -import com.quollwriter.ui.*; -import com.quollwriter.ui.sidebars.*; -import com.quollwriter.data.*; -import com.quollwriter.data.editors.*; -import com.quollwriter.events.*; -import com.quollwriter.editors.ui.*; -import com.quollwriter.editors.*; -import com.quollwriter.ui.components.Header; -import com.quollwriter.ui.components.QPopup; - -import static com.quollwriter.LanguageStrings.*; -import static com.quollwriter.Environment.getUIString; - -public class EditorProjectSideBar extends AbstractSideBar -{ - - public static final String ID = "editorproject"; - - private EditorChaptersAccordionItem chapters = null; - private EditorInfoBox editorInfoBox = null; - private EditorEditor editor = null; - private JComponent content = null; - private JLabel unsentLabel = null; - private JLabel otherVersionsLabel = null; - - public EditorProjectSideBar (EditorProjectViewer v) - { - - super (v); - - this.content = new Box (BoxLayout.Y_AXIS); - - this.content.setOpaque (false); - this.content.setAlignmentX (Component.LEFT_ALIGNMENT); - this.setMinimumSize (new Dimension (200, - 200)); - - final EditorProjectSideBar _this = this; - - v.addProjectEventListener (new ProjectEventListener () - { - - public void eventOccurred (ProjectEvent ev) - { - - if (ev.getContextObject () instanceof Note) - { - - _this.showUnsentNotification (); - - } - - } - - }); - - } - - @Override - public String getId () - { - - return ID; - - } - - private void showUnsentNotification () - { - - if (this.editor.isPrevious ()) - { - - this.unsentLabel.setVisible (false); - - return; - - } - - // Get the unsent note count for the project (for this version). - Set notes = null; - - try - { - - notes = this.viewer.getUnsentComments (); - - } catch (Exception e) { - - Environment.logError ("Unable to show unsent comments notification", - e); - - return; - - } - - int count = notes.size (); - - if (count > 0) - { -/* - String l = ""; - - if (count == 1) - { - - l = "1 {comment} hasn't been sent, click to review/send it now"; - - } else { - - l = count + " {comments} haven't been sent, click to review/send them now"; - - } -*/ - this.unsentLabel.setText (String.format (getUIString (editors,project,sidebar,comments,unsent), - Environment.formatNumber (count))); - //l); - - } - - this.unsentLabel.setVisible (count > 0); - - } - - public JComponent getContent () - { - - return this.content; - - } - - private void showOtherVersionsSelector () - { - - final EditorProjectSideBar _this = this; - - java.util.List pvs = null; - - try - { - - // TODO: Encapsulate this better. - pvs = (java.util.List) this.viewer.getObjectManager ().getObjects (ProjectVersion.class, - this.viewer.getProject (), - null, - false); - - } catch (Exception e) { - - Environment.logError ("Unable to get project versions for project: " + - this.viewer.getProject (), - e); - - return; - - } - - int c = 0; - - // Order in descending order. - try - { - - Query q = new Query (); - q.parse (String.format ("SELECT * FROM %s ORDER BY dateCreated DESC", - ProjectVersion.class.getName ())); - - QueryResults qr = q.execute (pvs); - - pvs = new ArrayList (qr.getResults ()); - - } catch (Exception e) { - - Environment.logError ("Unable to sort project versions: " + - pvs, - e); - - } - - ProjectVersion currPv = this.viewer.getProject ().getProjectVersion (); - - Set others = new LinkedHashSet (); - - for (ProjectVersion pv : pvs) - { - - if ((currPv != null) - && - (pv.equals (currPv)) - ) - { - - continue; - - } - - others.add (pv); - - c++; - - } - - if (c == 0) - { - - return; - - } - - if (c == 1) - { - - this.viewer.switchToProjectVersion (others.iterator ().next ()); - - } else { - - final Vector projVers = new Vector (others); - - final JList projVersL = new JList (projVers); - - projVersL.setSelectedValue (projVersL, - false); - - projVersL.addListSelectionListener (new ListSelectionListener () - { - - public void valueChanged (ListSelectionEvent ev) - { - - ProjectVersion pv = projVersL.getSelectedValue (); - - _this.viewer.switchToProjectVersion (pv); - - UIUtils.closePopupParent (projVersL); - - } - - }); - - projVersL.setCellRenderer (new DefaultListCellRenderer () - { - - private Map images = new HashMap (); - - public Component getListCellRendererComponent (JList list, - Object value, - int index, - boolean isSelected, - boolean cellHasFocus) - { - - Box b = new Box (BoxLayout.Y_AXIS); - - if (index < projVers.size () - 1) - { - - b.setBorder (UIUtils.createBottomLineWithPadding (3, 3, 3, 3)); - - } else { - - b.setBorder (UIUtils.createPadding (3, 3, 3, 3)); - - } - - java.util.List prefix = Arrays.asList (editors,project,sidebar,comments,otherversions,popup,labels); - - ProjectVersion pv = (ProjectVersion) value; - - Header h = UIUtils.createBoldSubHeader ((pv.getName () != null ? pv.getName () : getUIString (prefix,noversion)), - //"No version"), - null); - - b.add (h); - - h.setPreferredSize (new Dimension (Short.MAX_VALUE, - h.getPreferredSize ().height)); - - StringBuilder s = new StringBuilder (); - - if (pv.getDueDate () != null) - { - - s.append (String.format (getUIString (prefix,dueby), - //"Due by: %s. ", - Environment.formatDate (pv.getDueDate ()))); - - } - - try - { - - Set comms = _this.viewer.getNotesForVersion (pv); - - int unsent = 0; - - for (Note n : comms) - { - - if (!n.isDealtWith ()) - { - - unsent++; - - } - - } - - String t = String.format (getUIString (prefix,comments), - //"%s {comment%s}", - Environment.formatNumber (comms.size ())); - //(comms.size () == 1 ? "" : "s")); - - if (unsent > 0) - { - - t += String.format (getUIString (prefix,LanguageStrings.unsent), - //", %s unsent", - Environment.formatNumber (unsent)); - - } else { - - t += getUIString (prefix,sent); - //", all sent"; - - } - - s.append (t); - - JLabel info = UIUtils.createInformationLabel (s.toString ()); - - info.setBorder (UIUtils.createPadding (0, 5, 0, 5)); - - b.add (info); - - } catch (Exception e) { - - Environment.logError ("Unable to get unsent comments for project version: " + - pv, - e); - - } - - b.setToolTipText (String.format (getUIString (prefix,clicktoview), - //"Click to view version %s.", - pv.getName ())); - - return b; - - } - - }); - - final QPopup qp = UIUtils.createClosablePopup (getUIString (editors,project,sidebar,comments,otherversions,popup,title), - //"Select a version to view", - Environment.getIcon (Constants.VIEW_ICON_NAME, - Constants.ICON_POPUP), - null); - - Box content = new Box (BoxLayout.Y_AXIS); - - UIUtils.setAsButton (projVersL); - - content.add (projVersL); - content.setBorder (UIUtils.createPadding (10, 10, 10, 10)); - qp.setContent (content); - - content.setPreferredSize (new Dimension (UIUtils.getPopupWidth (), - content.getPreferredSize ().height)); - - _this.viewer.showPopupAt (qp, - otherVersionsLabel, - false); - - qp.setDraggable (_this.viewer); - - } - - } - - private void showOtherVersionsLabel () - { - - java.util.List pvs = null; - - try - { - - // TODO: Encapsulate this better. - pvs = (java.util.List) this.viewer.getObjectManager ().getObjects (ProjectVersion.class, - this.viewer.getProject (), - null, - false); - - } catch (Exception e) { - - Environment.logError ("Unable to get project versions for project: " + - this.viewer.getProject (), - e); - - return; - - } - - int c = 0; - - ProjectVersion currPv = this.viewer.getProject ().getProjectVersion (); - - ProjectVersion otherPv = null; - - for (ProjectVersion pv : pvs) - { - - if ((currPv != null) - && - (pv.equals (currPv)) - ) - { - - continue; - - } - - otherPv = pv; - - c++; - - } - - if (c > 0) - { -/* - String l = ""; - - if (c == 1) - { - - l = String.format ("1 other version%s is available, click to view it", - (otherPv.getName () != null ? String.format (" (%s)", otherPv.getName ()) : "")); - - } else { - - l = c + " other versions are available, click to select one"; - - } -*/ - this.otherVersionsLabel.setText (String.format (getUIString (editors,project,sidebar,comments,labels,otherversions), - Environment.formatNumber (c))); - //l); - - } - - this.otherVersionsLabel.setVisible (c > 0); - - } - - @Override - public void init (String saveState) - throws GeneralException - { - - super.init (saveState); - - this.editor = this.viewer.getProject ().getForEditor (); - - this.editorInfoBox = new EditorInfoBox (this.editor, - this.viewer, - true); - - this.editorInfoBox.init (); - - this.editorInfoBox.addFullPopupListener (); - - this.editorInfoBox.setMaximumSize (new Dimension (Short.MAX_VALUE, - this.editorInfoBox.getPreferredSize ().height)); - this.editorInfoBox.setBorder (UIUtils.createPadding (5, 5, 5, 0)); - - this.chapters = new EditorChaptersAccordionItem (this.viewer); - this.chapters.init (); - - this.content.add (this.editorInfoBox); - - ProjectVersion projVer = this.viewer.getProject ().getProjectVersion (); - - if (projVer != null) - { - - JComponent pvp = EditorsUIUtils.getProjectVersionPanel (projVer, - this.viewer); - - pvp.setBorder (UIUtils.createPadding (5, 5, 5, 5)); - - this.content.add (pvp); - - } - - final EditorProjectSideBar _this = this; - - //Get the due by/response message (properties from the project) - //Get the project description (sent by editor) - - // Create a box to indicate when there are comments to send. - this.unsentLabel = UIUtils.createClickableLabel ("", - Environment.getIcon (Constants.COMMENT_ICON_NAME, - Constants.ICON_MENU), - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - EditorsUIUtils.showSendUnsentComments (_this.viewer, - null); - - } - - }); - - this.unsentLabel.setBorder (UIUtils.createPadding (5, 10, 5, 5)); - - this.showUnsentNotification (); - - this.content.add (this.unsentLabel); - - this.otherVersionsLabel = UIUtils.createClickableLabel ("", - Environment.getIcon (Constants.VIEW_ICON_NAME, - Constants.ICON_MENU), - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.showOtherVersionsSelector (); - - } - - }); - - this.otherVersionsLabel.setBorder (UIUtils.createPadding (5, 10, 5, 5)); - - this.showOtherVersionsLabel (); - - this.content.add (this.otherVersionsLabel); - - JComponent sp = this.wrapInScrollPane (this.chapters); - sp.setBorder (null); - sp.setMinimumSize (new Dimension (200, - 300)); - - this.content.add (sp); - this.content.setBorder (UIUtils.createPadding (0, 5, 0, 5)); - - } - - public void reloadTreeForObjectType (String objType) - { - - this.chapters.update (); - - } - - public void panelShown (MainPanelEvent ev) - { - - this.chapters.setObjectSelectedInTree (ev.getForObject ()); - - } - - public void showObjectInTree (String treeObjType, - NamedObject obj) - { - - JTree tree = this.getTreeForObjectType (treeObjType); - - if (tree == null) - { - - return; - - } - - DefaultTreeModel dtm = (DefaultTreeModel) tree.getModel (); - - DefaultMutableTreeNode root = (DefaultMutableTreeNode) dtm.getRoot (); - - tree.expandPath (UIUtils.getTreePathForUserObject (root, - obj)); - - } - - public JTree getTreeForObjectType (String objType) - { - - return this.chapters.getTree (); - - } - - @Override - public void sideBarShown (SideBarEvent ev) - { - - this.otherSideBarsButton.setVisible (false); - - } - - @Override - public void onHide () - { - - } - - @Override - public void onShow () - { - - } - - @Override - public void onClose () - { - - - } - - public boolean canClose () - { - - return false; - - } - - public String getTitle () - { - - return getUIString (editors,project,sidebar,comments,title); - //"Editing for"; - - } - - public String getIconType () - { - - return null;//Constants.EDITORS_ICON_NAME; - - } - - @Override - public List getHeaderControls () - { - - return null; - - } - -} diff --git a/src/com/quollwriter/editors/ui/sidebars/EditorsSideBar.java b/src/com/quollwriter/editors/ui/sidebars/EditorsSideBar.java deleted file mode 100644 index 1dd26f5c..00000000 --- a/src/com/quollwriter/editors/ui/sidebars/EditorsSideBar.java +++ /dev/null @@ -1,2165 +0,0 @@ -package com.quollwriter.editors.ui.sidebars; - -import java.awt.Dimension; -import java.awt.Component; -import java.awt.Font; -import java.awt.Color; -import java.awt.event.*; -import java.awt.Image; -import java.awt.image.*; - -import javax.swing.*; -import javax.swing.border.*; -import javax.swing.event.*; - -import java.util.List; -import java.util.Map; -import java.util.HashMap; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.Date; -import java.util.Collection; -import java.util.Set; -import java.util.Vector; -import java.util.Arrays; -import java.util.LinkedHashSet; -import java.util.LinkedHashMap; - -import org.jivesoftware.smack.*; -import org.jivesoftware.smack.packet.*; - -import com.jgoodies.forms.builder.*; -import com.jgoodies.forms.factories.*; -import com.jgoodies.forms.layout.*; - -import com.gentlyweb.utils.*; - -import com.quollwriter.data.*; -import com.quollwriter.data.editors.*; -import com.quollwriter.*; -import com.quollwriter.ui.*; -import com.quollwriter.ui.sidebars.*; -import com.quollwriter.ui.panels.*; -import com.quollwriter.db.*; -import com.quollwriter.events.*; -import com.quollwriter.ui.components.ChangeAdapter; -import com.quollwriter.ui.components.Header; -import com.quollwriter.ui.components.DnDTabbedPane; -import com.quollwriter.ui.components.TabHeader; -import com.quollwriter.ui.components.ScrollableBox; -import com.quollwriter.ui.components.QPopup; -import com.quollwriter.editors.*; -import com.quollwriter.editors.messages.*; -import com.quollwriter.editors.ui.*; -import com.quollwriter.ui.events.*; - -import static com.quollwriter.LanguageStrings.*; -import static com.quollwriter.Environment.getUIString; - -public class EditorsSideBar extends AbstractSideBar implements EditorChangedListener, - EditorMessageListener, - UserOnlineStatusListener -{ - - public static final String ID = "editors"; - - //public static final String NAME = "editors"; - - private DnDTabbedPane tabs = null; - private EditorFindPanel editorFindPanel = null; - private JComponent noEditors = null; - private JComponent firstLogin = null; - private JButton statusButton = null; - - private JComponent notification = null; - - private EditorsSection otherEditors = null; - private EditorsSection invitesForMe = null; - private EditorsSection invitesIveSent = null; - - private Map specialTabs = new HashMap (); - - public EditorsSideBar (AbstractViewer v) - { - - super (v); - - EditorsEnvironment.addEditorChangedListener (this); - EditorsEnvironment.addEditorMessageListener (this); - EditorsEnvironment.addUserOnlineStatusListener (this); - - } - - @Override - public String getId () - { - - return ID; - - } - - @Override - public void handleMessage (EditorMessageEvent ev) - { - - this.updateView (); - - } - - @Override - public void editorChanged (EditorChangedEvent ev) - { - - EditorEditor ed = ev.getEditor (); - - this.updateView (); - - for (int i = 0; i < this.tabs.getTabCount (); i++) - { - - Component comp = this.tabs.getComponentAt (i); - - if (comp instanceof EditorPanel) - { - - if (ed == ((EditorPanel) comp).getEditor ()) - { - - JLabel th = (JLabel) this.tabs.getTabComponentAt (i); - - BufferedImage av = ed.getDisplayAvatar (); - - if (av != null) - { - - BufferedImage nim = UIUtils.getScaledImage (av, - 28); - - if (nim.getHeight () > 28) - { - - nim = UIUtils.getScaledImage (av, - 28, - 28); - - } - - th.setIcon (new ImageIcon (nim)); - th.setText (null); - - } else { - - th.setIcon (null); - th.setText (ed.getShortName ()); - } - - String tt = ed.getShortName (); - - if (ed.getOnlineStatus () != null) - { - - tt += ", " + ed.getOnlineStatus ().getName (); - - } - - th.setToolTipText (String.format ("%s", - tt)); - - } - - } - - } - - } - - public boolean canClose () - { - - return true; - - } - - @Override - public void onShow () - { - - // TODO - - } - - @Override - public void onHide () - { - - } - - @Override - public void onClose () - { - - EditorsEnvironment.removeEditorChangedListener (this); - EditorsEnvironment.removeUserOnlineStatusListener (this); - - } - - public boolean removeOnClose () - { - - return false; - - } - - public String getIconType () - { - - return Constants.EDITORS_ICON_NAME; - - } - - public String getTitle () - { - - return getUIString (editors,sidebar,title); - //"{Contacts}"; // {Editors} - - } - - public void panelShown (MainPanelEvent ev) - { - - } - - private void update () - { - - if (!this.isVisible ()) - { - - return; - - } - - } - - private JMenuItem createStatusMenuItem (final EditorEditor.OnlineStatus status) - { - - final EditorsSideBar _this = this; - - JMenuItem mi = UIUtils.createMenuItem (status.getName (), - this.getStatusIconName (status), - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - try - { - - EditorsEnvironment.setUserOnlineStatus (status); - - } catch (Exception e) { - - Environment.logError ("Unable to set user status to: " + - status, - e); - - UIUtils.showErrorMessage (_this.viewer, - getUIString (editors,sidebar,headercontrols,items,onlinestatus,update,actionerror)); - //"Unable to change your status, please contact Quoll Writer support for assistance."); - - } - - } - - }); - - return mi; - - } - - private void updateUserOnlineStatus (EditorEditor.OnlineStatus status) - { - - if (status == null) - { - - status = EditorEditor.OnlineStatus.offline; - - } - - String iconName = this.getStatusIconName (status); - String toolTip = null; - String info = null; - - if (status == EditorEditor.OnlineStatus.offline) - { - - toolTip = getUIString (editors,sidebar,headercontrols,items,onlinestatus,online,button,tooltip); - //"Click to go online"; - - info = getUIString (editors,sidebar,headercontrols,items,onlinestatus,offline,LanguageStrings.notification); - //"You have been logged out."; - - } else { - - toolTip = String.format (getUIString (editors,sidebar,headercontrols,items,onlinestatus,button,tooltip), - status.getName ()); - //status.getName () + ", click to change your status"; - - info = String.format (getUIString (editors,sidebar,headercontrols,items,onlinestatus,update,LanguageStrings.notification), - //"Your status is now %s.", - status.getName ()); - - } - - this.statusButton.setIcon (Environment.getIcon (iconName, - Constants.ICON_SIDEBAR)); - this.statusButton.setToolTipText (toolTip); - - if (this.statusButton.isShowing ()) - { - - this.showNotification (iconName, - info, - 2, - this.statusButton); - - } - - } - - public void userOnlineStatusChanged (UserOnlineStatusEvent ev) - { - - this.updateUserOnlineStatus (ev.getStatus ()); - - } - - @Override - public List getHeaderControls () - { - - final EditorsSideBar _this = this; - - List buts = new ArrayList (); - - this.statusButton = UIUtils.createButton (this.getStatusIconName (EditorEditor.OnlineStatus.offline), - Constants.ICON_SIDEBAR, - getUIString (editors,sidebar,headercontrols,items,onlinestatus,offline,button,tooltip), - //"Click to go online", - null); - - this.userOnlineStatusChanged (new UserOnlineStatusEvent (EditorsEnvironment.getUserOnlineStatus ())); - - this.statusButton.addActionListener (new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - if (EditorsEnvironment.isUserLoggedIn ()) - { - - JPopupMenu m = new JPopupMenu (); - - Set statuses = new LinkedHashSet (); - statuses.add (EditorEditor.OnlineStatus.online); - statuses.add (EditorEditor.OnlineStatus.busy); - statuses.add (EditorEditor.OnlineStatus.away); - statuses.add (EditorEditor.OnlineStatus.snooze); - - for (EditorEditor.OnlineStatus v : statuses) - { - - m.add (_this.createStatusMenuItem (v)); - - } - - JMenuItem mi = UIUtils.createMenuItem (getUIString (editors,sidebar,headercontrols,items,onlinestatus,popupmenu,items,logout), - //"Logout", - _this.getStatusIconName (null), - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - EditorsEnvironment.goOffline (); - - } - - }); - - m.add (mi); - - m.show (_this.statusButton, - 10, - 10); - - } else { - - QPopup np = null; - - if (EditorsEnvironment.hasLoginCredentials ()) - { - - np = _this.showNotification (Constants.LOADING_GIF_NAME, - getUIString (editors,sidebar,headercontrols,items,onlinestatus,online,LanguageStrings.notification), - //"Logging in...", - -1, - _this.statusButton); - - } - - // TODO: Very nasty, fix. - final QPopup fnp = np; - - EditorsEnvironment.goOnline (null, - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - if (fnp != null) - { - - fnp.removeFromParent (); - - } - - _this.updateView (); - - } - - }, - // On cancel - null, - // On error - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.hideNotification (); - - if (fnp != null) - { - - fnp.removeFromParent (); - - } - - EditorsUIUtils.showLoginError (getUIString (editors,login,errors,invalidcredentials), - //"Unable to login, please check your email and password.", - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - EditorsEnvironment.goOnline (null, - null, - null, - null); - - } - - }, - null); - - } - - }); - - } - - } - - }); - - buts.add (this.statusButton); -/* - b = UIUtils.createButton (Constants.FIND_ICON_NAME, - Constants.ICON_SIDEBAR, - "Click to find editors", - new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.toggleFindEditorsTab (); - - } - - }); - - buts.add (b); - */ - JButton b = UIUtils.createButton (Constants.NEW_ICON_NAME, - Constants.ICON_SIDEBAR, - getUIString (editors,sidebar,headercontrols,items,sendinvite,tooltip), - //"Click to send an invite", - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - EditorsUIUtils.showInviteEditor (_this.viewer); - - } - - }); - - buts.add (b); - - b = UIUtils.createButton (Constants.OPTIONS_ICON_NAME, - Constants.ICON_SIDEBAR, - getUIString (editors,sidebar,headercontrols,items,config,tooltip), - //"Click to view the config options", - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - JMenuItem mi = null; - - JPopupMenu popup = new JPopupMenu (); - - // Get all previous editors. - int prevCount = 0; - - for (EditorEditor ed : EditorsEnvironment.getEditors ()) - { - - if (ed.isPrevious ()) - { - - prevCount++; - - } - - } - - if (prevCount > 0) - { - - popup.add (UIUtils.createMenuItem (String.format (getUIString (editors,sidebar,headercontrols,items,config,popupmenu,items,previouscontacts,text), - //"View the previous {contacts} (%s)", - Environment.formatNumber (prevCount)), - Constants.STOP_ICON_NAME, - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.showPreviousEditors (); - - } - - })); - - } - - popup.add (UIUtils.createMenuItem (getUIString (editors,sidebar,headercontrols,items,config,popupmenu,items,updatenameavatar,text), - //"Update your name/avatar", - Constants.EDIT_ICON_NAME, - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - EditorsUIUtils.updateYourInfo (_this.viewer); - - } - - })); - - popup.add (UIUtils.createMenuItem (getUIString (editors,sidebar,headercontrols,items,config,popupmenu,items,changepassword,text), - //"Change your password", - Constants.EDIT_ICON_NAME, - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - EditorsUIUtils.showChangePassword (_this.viewer); - - } - - })); - - if (!EditorsEnvironment.getEditorsPropertyAsBoolean (Constants.QW_EDITORS_SERVICE_HAS_LOGGED_IN_PROPERTY_NAME)) - { - - popup.add (UIUtils.createMenuItem (getUIString (editors,sidebar,headercontrols,items,config,popupmenu,items,resendaccountconfirmationemail,text), - //"Resend confirmation email", - Constants.SEND_ICON_NAME, - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - UIUtils.openURL (_this.viewer, - String.format (Environment.getQuollWriterWebsiteLink ("editor-mode/send-account-confirmation-email?email=%s", - EditorsEnvironment.getUserAccount ().getEmail ()))); - - } - - })); - - } else { - - // If they have their password stored then display it. - final String edPass = EditorsEnvironment.getEditorsProperty (Constants.QW_EDITORS_SERVICE_PASSWORD_PROPERTY_NAME); - - if (edPass != null) - { - - popup.add (UIUtils.createMenuItem (getUIString (editors,sidebar,headercontrols,items,config,popupmenu,items,displaypassword,text), - //"Display your password", - Constants.VIEW_ICON_NAME, - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - String extra = ""; - - if (Environment.isDebugModeEnabled ()) - { - - extra = String.format ("
    Messaging Username: %s", - EditorsEnvironment.getUserAccount ().getMessagingUsername ()); - - } - - UIUtils.showMessage ((PopupsSupported) _this.viewer, - getUIString (editors,user,displaypassword,LanguageStrings.popup,title), - //)"Your Editors service password", - String.format (getUIString (editors,user,displaypassword,LanguageStrings.popup,text) + extra, - //"Note: your password is being displayed because you have checked the Save password box for logging into the Editors service.

    Your login details are:

    Email address: %s
    Password: %s%s", - EditorsEnvironment.getUserAccount ().getEmail (), - edPass)); - //extra)); - - } - - })); - - } else { - - popup.add (UIUtils.createMenuItem (getUIString (editors,sidebar,headercontrols,items,config,popupmenu,items,resetpassword,text), - //"Reset your password", - Constants.CANCEL_ICON_NAME, - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - UIUtils.openURL (_this.viewer, - String.format (Environment.getQuollWriterWebsiteLink ("editor-mode/send-password-reset-email?email=%s", - null), - EditorsEnvironment.getUserAccount ().getEmail ())); - - } - - })); - - } - - } - - popup.add (UIUtils.createMenuItem (getUIString (editors,sidebar,headercontrols,items,config,popupmenu,items,preferences,text), - //"Preferences", - Constants.CONFIG_ICON_NAME, - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - AbstractViewer viewer = Environment.getFocusedViewer (); - - viewer.showOptions ("editors"); - - } - - })); - - popup.add (UIUtils.createMenuItem (getUIString (editors,sidebar,headercontrols,items,config,popupmenu,items,help,text), - //"Help", - Constants.HELP_ICON_NAME, - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - UIUtils.openURL (_this, - Environment.getQuollWriterHelpLink ("editor-mode/overview", - null)); - - } - - })); - - popup.add (UIUtils.createMenuItem (getUIString (editors,sidebar,headercontrols,items,config,popupmenu,items,deleteaccount,text), - //"Delete your account", - Constants.DELETE_ICON_NAME, - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - EditorsUIUtils.showDeleteAccount (_this.viewer); - - } - - })); - - JComponent s = (JComponent) ev.getSource (); - - popup.show (s, - s.getWidth () / 2, - s.getHeight ()); - - } - - }); - - buts.add (b); - - return buts; - - } - - private void createWelcomeTab () - { - - try - { - - this.viewer.showHelpText ("Welcome to the Editors Service", - StringUtils.replaceString (Environment.getResourceFileAsString (Constants.EDITORS_SIDEBAR_FIRST_USE_HELP_FILE), - "\n", - ""), - Constants.EDITORS_ICON_NAME, - "editors-service-first-help"); - - } catch (Exception e) { - - Environment.logError ("Unable to get editors sidebar first use help file", - e); - - return; - - } - - } - - private void createEditorList () - { - - final EditorsSideBar _this = this; - - // Get all our editors. - List editors = EditorsEnvironment.getEditors (); - - Box edBox = new ScrollableBox (BoxLayout.Y_AXIS); - - edBox.setOpaque (true); - edBox.setBackground (UIUtils.getComponentColor ()); - - edBox.setBorder (UIUtils.createPadding (0, 0, 0, 0)); - - this.firstLogin = new Box (BoxLayout.Y_AXIS); - - this.firstLogin.add (UIUtils.createBoldSubHeader (getUIString (LanguageStrings.editors,sidebar,firstlogin,title), - //"Checked your email?", - null)); - - JComponent firstLoginHelp = UIUtils.createHelpTextPane (getUIString (LanguageStrings.editors,sidebar,firstlogin,text), - //"Once you've validated your email address click on the button below to login.", - this.viewer); - firstLoginHelp.setBorder (null); - this.firstLogin.setBorder (new EmptyBorder (5, 5, 5, 5)); - - Box bfirstLoginHelp = new Box (BoxLayout.Y_AXIS); - bfirstLoginHelp.setAlignmentX (Component.LEFT_ALIGNMENT); - bfirstLoginHelp.setBorder (UIUtils.createPadding (0, 5, 0, 5)); - bfirstLoginHelp.add (firstLoginHelp); - - this.firstLogin.add (bfirstLoginHelp); - - this.firstLogin.add (Box.createVerticalStrut (10)); - - JButton but = UIUtils.createToolBarButton (this.getStatusIconName (null), - getUIString (LanguageStrings.editors,sidebar,firstlogin,buttons,login,tooltip), - //"Click to go online", - null, - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - EditorsEnvironment.goOnline (null, - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.updateView (); - - } - - }, - // On cancel - null, - // On error - null); - - } - - }); - - but.setFont (but.getFont ().deriveFont (UIUtils.getScaledFontSize (12))); - - but.setText (getUIString (LanguageStrings.editors,sidebar,firstlogin,buttons,login,text)); - //"Click to Login"); - List buts = new ArrayList (); - buts.add (but); - - Box bbar = new Box (BoxLayout.X_AXIS); - bbar.setAlignmentX (Component.LEFT_ALIGNMENT); - - bbar.add (Box.createHorizontalGlue ()); - bbar.add (UIUtils.createButtonBar (buts)); - bbar.add (Box.createHorizontalGlue ()); - - this.firstLogin.add (bbar); - - edBox.add (this.firstLogin); - - this.noEditors = new Box (BoxLayout.Y_AXIS); - - this.noEditors.add (UIUtils.createBoldSubHeader (getUIString (LanguageStrings.editors,sidebar,nocontacts,title), - //"No current {contacts}", - null)); - - JComponent noedsHelp = UIUtils.createHelpTextPane (getUIString (LanguageStrings.editors,sidebar,nocontacts,text), - //"You currently have no {contacts}. Click on the button below to invite someone to be {an editor} for your {project}.", - this.viewer); - noedsHelp.setBorder (null); - this.noEditors.setBorder (new EmptyBorder (5, 5, 5, 5)); - - Box bnoedsHelp = new Box (BoxLayout.Y_AXIS); - bnoedsHelp.setAlignmentX (Component.LEFT_ALIGNMENT); - bnoedsHelp.setBorder (UIUtils.createPadding (0, 5, 0, 5)); - bnoedsHelp.add (noedsHelp); - - this.noEditors.add (bnoedsHelp); - - this.noEditors.add (Box.createVerticalStrut (10)); - - but = UIUtils.createToolBarButton (Constants.NEW_ICON_NAME, - getUIString (LanguageStrings.editors,sidebar,nocontacts,buttons,sendinvite,tooltip), - //"Click to invite someone to be {an editor} for your {project}", - null, - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - EditorsUIUtils.showInviteEditor (_this.viewer); - - } - - }); - - but.setFont (but.getFont ().deriveFont (UIUtils.getScaledFontSize (12))); - - but.setText (getUIString (LanguageStrings.editors,sidebar,nocontacts,buttons,sendinvite,text)); - //"Send an invite"); - buts = new ArrayList (); - buts.add (but); - - bbar = new Box (BoxLayout.X_AXIS); - bbar.setAlignmentX (Component.LEFT_ALIGNMENT); - - bbar.add (Box.createHorizontalGlue ()); - bbar.add (UIUtils.createButtonBar (buts)); - bbar.add (Box.createHorizontalGlue ()); - - this.noEditors.add (bbar); - - edBox.add (this.noEditors); - - this.invitesForMe = new EditorsSection (getUIString (LanguageStrings.editors,sidebar,invitesfromothers,title), - //"Invites from others", - getUIString (LanguageStrings.editors,sidebar,invitesfromothers,text), - //"Invites I've received from other people.", - null, - this.viewer); - - this.invitesForMe.init (); - - edBox.add (this.invitesForMe); - - this.invitesIveSent = new EditorsSection (getUIString (LanguageStrings.editors,sidebar,pendinginvites,title), - //"Pending invites", - getUIString (LanguageStrings.editors,sidebar,pendinginvites,text), - //"Invites I've sent to other people.", - null, - this.viewer); - - this.invitesIveSent.init (); - - edBox.add (this.invitesIveSent); - - this.otherEditors = new EditorsSection (getUIString (LanguageStrings.editors,sidebar,allcontacts,title), - //"All {Contacts}", - null, - null, - this.viewer); - - this.otherEditors.init (); - - edBox.add (this.otherEditors); - - final JScrollPane sp = UIUtils.createScrollPane (edBox); - sp.setBorder (null); - - this.tabs.add (sp, - 0); - this.tabs.setIconAt (0, - Environment.getIcon ("editors-list", - Constants.ICON_EDITORS_LIST_TAB_HEADER)); - - this.updateView (); - - UIUtils.doLater (new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - sp.getHorizontalScrollBar ().setValue (0); - sp.getVerticalScrollBar ().setValue (0); - - } - - }); - - } - - private void updateView () - { - - Set invitesForMe = new LinkedHashSet (); - Set projEds = new LinkedHashSet (); - Set others = new LinkedHashSet (); - Set invitesIveSent = new LinkedHashSet (); - - int edsSize = 0; - - for (EditorEditor ed : EditorsEnvironment.getEditors ()) - { - - if (ed.isPrevious ()) - { - - continue; - - } - - if (ed.isRejected ()) - { - - continue; - - } - - edsSize++; - - if (ed.isPending ()) - { - - if (!ed.isInvitedByMe ()) - { - - invitesForMe.add (ed); - - } else { - - invitesIveSent.add (ed); - - } - - } else { - - others.add (ed); -/* - ProjectEditor pe = this.projectViewer.getProject ().getProjectEditor (ed); - - if (pe != null) - { - - projEds.add (pe); - - } else { - - others.add (ed); - - } - */ - } - - } - - this.otherEditors.setVisible (others.size () > 0); - - try - { - - this.otherEditors.update (others); - - } catch (Exception e) { - - Environment.logError ("Unable to update other editors section with editors: " + - others, - e); - - this.otherEditors.setVisible (false); - - UIUtils.showErrorMessage (this.viewer, - getUIString (editors,vieweditorserror)); - //"Unable to display others section, please contact Quoll Writer support for assistance."); - - } - - this.invitesForMe.setVisible (invitesForMe.size () > 0); - - try - { - - this.invitesForMe.update (invitesForMe); - - } catch (Exception e) { - - Environment.logError ("Unable to update invites for me editors section with editors: " + - invitesForMe, - e); - - this.invitesForMe.setVisible (false); - - UIUtils.showErrorMessage (this.viewer, - getUIString (editors,vieweditorserror)); - //"Unable to display invites from others section, please contact Quoll Writer support for assistance."); - - } - - this.invitesIveSent.setVisible (invitesIveSent.size () > 0); - - try - { - - this.invitesIveSent.update (invitesIveSent); - - } catch (Exception e) { - - Environment.logError ("Unable to update invites ive sent section with editors: " + - invitesIveSent, - e); - - this.invitesIveSent.setVisible (false); - - UIUtils.showErrorMessage (this.viewer, - getUIString (editors,vieweditorserror)); - //"Unable to display invites I've sent section, please contact Quoll Writer support for assistance."); - - } - - this.noEditors.setVisible (edsSize == 0); - - this.firstLogin.setVisible (false); - - // May not have an account anymore. - if ((EditorsEnvironment.getUserAccount () != null) - && - (EditorsEnvironment.getUserAccount ().getLastLogin () == null) - ) - { - - this.firstLogin.setVisible (true); - this.noEditors.setVisible (false); - - } - - this.validate (); - this.repaint (); - - } - - private void hideNotification () - { - - if (this.notification != null) - { - - this.notification.setVisible (false); - - } - - } - - private QPopup showNotification (String iconType, - String message, - int duration, - Component showAt) - { - - final EditorsSideBar _this = this; - - final QPopup p = new QPopup (message, - Environment.getIcon (iconType, - Constants.ICON_EDITOR_MESSAGE), - null); - - p.getHeader ().setFont (p.getHeader ().getFont ().deriveFont (UIUtils.getScaledFontSize (12))); - - p.getHeader ().setBorder (UIUtils.createPadding (10, 10, 10, 10)); - - this.viewer.showPopupAt (p, - showAt, - true); - - if (duration > 0) - { - - javax.swing.Timer timer = new javax.swing.Timer (duration * 1000, - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - p.removeFromParent (); - - } - - }); - - timer.setRepeats (false); - timer.start (); - - } - - return p; - - } - - public JComponent getContent () - { - - final EditorsSideBar _this = this; - - Box box = new Box (BoxLayout.Y_AXIS); - box.setAlignmentX (Component.LEFT_ALIGNMENT); - // Turn off the auto border. - box.setBorder (UIUtils.createPadding (0, 0, 0, 0)); - box.setOpaque (true); - box.setBackground (UIUtils.getComponentColor ()); - - this.notification = new Box (BoxLayout.Y_AXIS); - this.notification.setAlignmentX (Component.LEFT_ALIGNMENT); - this.notification.setVisible (false); - this.notification.setBorder (UIUtils.createPadding (5, 5, 5, 5)); - - box.add (this.notification); - - this.tabs = new DnDTabbedPane (); - - this.tabs.putClientProperty(com.jgoodies.looks.Options.NO_CONTENT_BORDER_KEY, Boolean.TRUE); - //this.tabs.putClientProperty(com.jgoodies.looks.Options.EMBEDDED_TABS_KEY, Boolean.TRUE); - this.tabs.setAlignmentX (Component.LEFT_ALIGNMENT); - this.tabs.setTabLayoutPolicy (JTabbedPane.SCROLL_TAB_LAYOUT); - this.tabs.setBorder (UIUtils.createPadding (5, 2, 0, 0)); - this.tabs.addChangeListener (new ChangeAdapter () - { - - public void stateChanged (ChangeEvent ev) - { - - } - - }); - - box.add (this.tabs); - - this.createEditorList (); - -/* - // See if this is the first time the user has seen the side bar. - if (!EditorsEnvironment.getEditorsPropertyAsBoolean (Constants.QW_EDITORS_SERVICE_EDITORS_SIDEBAR_SEEN_PROPERTY_NAME)) - { - - try - { - - EditorsEnvironment.setEditorsProperty (Constants.QW_EDITORS_SERVICE_EDITORS_SIDEBAR_SEEN_PROPERTY_NAME, - true); - - } catch (Exception e) { - - Environment.logError ("Unable to set editors sidebar seen property", - e); - - } - - this.createWelcomeTab (); - - } -*/ - return box; - - } - - private void addTabCloseListener (final JComponent header, - final JComponent content) - { - - final EditorsSideBar _this = this; - - header.addMouseListener (new MouseEventHandler () - { - - @Override - public void handlePress (MouseEvent ev) - { - - _this.tabs.setSelectedComponent (content); - - } - - @Override - public void handleMiddlePress (MouseEvent ev) - { - - _this.tabs.remove (content); - - } - - @Override - public void fillPopup (JPopupMenu menu, - MouseEvent ev) - { - - menu.add (UIUtils.createMenuItem (getUIString (buttons,close), - //"Close", - Constants.CLOSE_ICON_NAME, - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.tabs.remove (content); - - } - - })); - - } - - }); - - } - - public void showPreviousEditors () - { - - JComponent c = this.specialTabs.get ("previous-editors"); - - if (c != null) - { - - this.tabs.remove (c); - - } - - final Box edBox = new ScrollableBox (BoxLayout.Y_AXIS); - - edBox.setAlignmentX (Component.LEFT_ALIGNMENT); - edBox.setBorder (UIUtils.createPadding (0, 10, 0, 5)); - edBox.setOpaque (true); - edBox.setBackground (UIUtils.getComponentColor ()); - - JComponent nc = UIUtils.createInformationLabel (getUIString (LanguageStrings.editors,sidebar,previouscontacts,text)); - //"{Contacts} you have removed or have removed you in the past."); - - nc.setBorder (UIUtils.createPadding (0, 0, 5, 0)); - - edBox.add (nc); - - int prevCount = 0; - - List eds = EditorsEnvironment.getEditors (); - - try - { - - for (int i = 0; i < eds.size (); i++) - { - - EditorEditor ed = eds.get (i); - - if (!ed.isPrevious ()) - { - - continue; - - } - - prevCount++; - - EditorInfoBox infBox = this.getEditorBox (ed); - - if (i < eds.size () - 1) - { - - infBox.setBorder (UIUtils.createBottomLineWithPadding (5, 0, 5, 0)); - - } else { - - infBox.setBorder (UIUtils.createPadding (5, 0, 5, 0)); - - } - - edBox.add (infBox); - - i++; - - } - - } catch (Exception e) { - - Environment.logError ("Unable to show editors: " + - eds, - e); - - UIUtils.showErrorMessage (this.viewer, - getUIString (LanguageStrings.editors,vieweditorserror)); - //"Unable to build list of previous {contacts}, please contact Quoll Writer support for assistance."); - - return; - - } - - if (prevCount == 0) - { - - return; - - } - - edBox.add (Box.createVerticalGlue ()); - - AccordionItem prev = new AccordionItem (String.format (getUIString (LanguageStrings.editors,sidebar,previouscontacts,title), - //"Previous {contacts} (%s)", - Environment.formatNumber (prevCount))) - { - - @Override - public JComponent getContent () - { - - return edBox; - - } - - }; - - prev.setBorder (UIUtils.createPadding (0, 0, 0, 0)); - prev.init (); - - Box wrapper = new ScrollableBox (BoxLayout.Y_AXIS); - wrapper.setAlignmentX (Component.LEFT_ALIGNMENT); - wrapper.add (prev); - - JScrollPane sp = UIUtils.createScrollPane (wrapper); - sp.setBorder (null); - - this.tabs.add (sp, - 1); - - JLabel l = UIUtils.createLabel (null, - Environment.getIcon (Constants.STOP_ICON_NAME, - Constants.ICON_EDITORS_LIST_TAB_HEADER), - null); - - l.setToolTipText (getUIString (LanguageStrings.editors,sidebar,previouscontacts,tooltip)); - //"Previous {contacts}")); - - this.tabs.setTabComponentAt (1, - l); - - this.addTabCloseListener (l, - sp); - - this.tabs.setSelectedComponent (sp); - this.tabs.revalidate (); - this.tabs.repaint (); - - this.specialTabs.put ("previous-editors", - prev); - - } -/* - private void showMessagesInSpecialTab (Set messages, - String iconName, - String toolTipText, - String tabName, - String desc, - ActionListener onDescClose) - throws GeneralException - { - - final EditorsSideBar _this = this; - - // Split the messages into Editor->Messages - Map> edmessages = new LinkedHashMap (); - - for (EditorMessage m : messages) - { - - EditorEditor ed = m.getEditor (); - - Set edm = edmessages.get (ed); - - if (edm == null) - { - - edm = new LinkedHashSet (); - - edmessages.put (ed, - edm); - - } - - edm.add (m); - - } - - final Box content = new ScrollableBox (BoxLayout.Y_AXIS); - - JScrollPane sp = UIUtils.createScrollPane (content); - sp.setBorder (null); - - this.tabs.add (sp, - 1); - - JLabel l = new JLabel (Environment.getIcon (iconName, - Constants.ICON_EDITORS_LIST_TAB_HEADER)); - - l.setToolTipText (Environment.replaceObjectNames (toolTipText)); - - this.tabs.setTabComponentAt (1, - l); - - this.addTabCloseListener (l, - sp); - - if (desc != null) - { - - JComponent nc = UIUtils.createInformationLabel (desc); - - nc.setBorder (UIUtils.createPadding (5, 5, 5, 5)); - - content.add (nc); - - } - - for (EditorEditor ed : edmessages.keySet ()) - { - - Header h = UIUtils.createBoldSubHeader (String.format ("%s messages from", - Environment.formatNumber (edmessages.get (ed).size ())), - null); - - h.setBorder (UIUtils.createPadding (0, 5, 0, 0)); - - content.add (h); - - EditorPanel ep = new EditorPanel (this, - ed, - edmessages.get (ed)); - ep.setShowChatBox (false); - ep.init (); - - ep.setOpaque (true); - ep.setBackground (UIUtils.getComponentColor ()); - ep.setAlignmentX (Component.LEFT_ALIGNMENT); - ep.setBorder (UIUtils.createPadding (5, 5, 5, 0)); - - content.add (ep); - - } - - this.tabs.setSelectedComponent (sp); - this.tabs.revalidate (); - this.tabs.repaint (); - - this.specialTabs.put (tabName, - sp); - - } -*/ - public void toggleFindEditorsTab () - { - - if ((this.editorFindPanel != null) - && - (this.editorFindPanel.getParent () != null) - ) - { - - this.hideFindEditorsTab (); - - return; - - } - - this.showFindEditorsTab (); - - } - - public void hideFindEditorsTab () - { - - if (this.editorFindPanel == null) - { - - return; - - } - - this.tabs.remove (this.editorFindPanel); - - } - - public void showFindEditorsTab () - { - - if ((this.editorFindPanel != null) - && - (this.editorFindPanel.getParent () != null) - ) - { - - this.tabs.setSelectedComponent (this.editorFindPanel); - this.tabs.revalidate (); - this.tabs.repaint (); - - return; - - } - - if (this.editorFindPanel == null) - { - - // Add the editor find panel. - this.editorFindPanel = new EditorFindPanel (this); - - this.editorFindPanel.init (); - - this.editorFindPanel.setOpaque (true); - this.editorFindPanel.setBackground (UIUtils.getComponentColor ()); - this.editorFindPanel.setAlignmentX (Component.LEFT_ALIGNMENT); - this.editorFindPanel.setBorder (new EmptyBorder (5, 5, 5, 5)); - - } - - JLabel add = new JLabel (Environment.getIcon (Constants.FIND_ICON_NAME, - Constants.ICON_TAB_HEADER)); - - this.tabs.add (this.editorFindPanel, - 1); - this.tabs.setTabComponentAt (1, - add); - - this.showFindEditorsTab (); - - } - - public EditorPanel getEditorPanel (EditorEditor ed) - { - - for (int i = 0; i < this.tabs.getTabCount (); i++) - { - - Component comp = this.tabs.getComponentAt (i); - - if (comp instanceof EditorPanel) - { - - if (ed == ((EditorPanel) comp).getEditor ()) - { - - return (EditorPanel) comp; - - } - - } - - } - - return null; - - } - - public void showChatBox (final EditorEditor ed) - throws GeneralException - { - - this.showEditor (ed); - - final EditorsSideBar _this = this; - - UIUtils.doLater (new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - EditorPanel edPanel = _this.getEditorPanel (ed); - - if (edPanel != null) - { - - edPanel.showChatBox (); - - } - - } - - }); - - } - - public void showEditor (EditorEditor ed) - throws GeneralException - { - - final EditorsSideBar _this = this; - - EditorPanel edPanel = this.getEditorPanel (ed); - - if (edPanel != null) - { - - this.editorChanged (new EditorChangedEvent (ed, - EditorChangedEvent.EDITOR_CHANGED)); - - this.tabs.setSelectedComponent (edPanel); - this.tabs.revalidate (); - this.tabs.repaint (); - - return; - - } - - if (!ed.messagesLoaded ()) - { - - try - { - - EditorsEnvironment.loadMessagesForEditor (ed); - - } catch (Exception e) { - - throw new GeneralException ("Unable to load messages for editor: " + - ed, - e); - - } - - } - - EditorPanel ep = new EditorPanel (this, - ed); - ep.init (); - - ep.setOpaque (true); - ep.setBackground (UIUtils.getComponentColor ()); - ep.setAlignmentX (Component.LEFT_ALIGNMENT); - ep.setBorder (UIUtils.createPadding (5, 5, 5, 0)); - - int ind = this.tabs.getTabCount (); - - this.tabs.add (ep); - - final JLabel th = new JLabel (); - th.setBorder (new CompoundBorder (UIUtils.createPadding (2, 0, 0, 0), - UIUtils.createLineBorder ())); - - th.setMaximumSize (new Dimension (100, 100)); - - this.tabs.setTabComponentAt (ind, - th); - - this.addTabHeaderMouseHandler (th, - ep); - - this.showEditor (ed); - - } - - @Override - public void init (String saveState) - throws GeneralException - { - - super.init (saveState); - - } - - private void addTabHeaderMouseHandler (final JComponent tabHeader, - final JComponent tab) - { - - final EditorsSideBar _this = this; - - tabHeader.addMouseListener (new MouseEventHandler () - { - - @Override - public void handlePress (MouseEvent ev) - { - - _this.tabs.setSelectedComponent (tab); - - } - - @Override - public void handleMiddlePress (MouseEvent ev) - { - - _this.tabs.remove (tab); - - } - - @Override - public void fillPopup (JPopupMenu menu, - MouseEvent ev) - { - - menu.add (UIUtils.createMenuItem (getUIString (buttons,close), - //"Close", - Constants.CLOSE_ICON_NAME, - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.tabs.remove (tab); - - } - - })); - - } - - }); - - } - - public String getStatusIconName (EditorEditor.OnlineStatus status) - { - - String type = "offline"; - - if (status != null) - { - - type = status.getType (); - - } - - return Constants.ONLINE_STATUS_ICON_NAME_PREFIX + type; - - } - - private boolean isPendingInviteForMe (EditorEditor ed) - { - - return ed.isPending () && !ed.isInvitedByMe (); - - } - - /** - * Always 250, 200. - */ - @Override - public Dimension getMinimumSize () - { - - return new Dimension (UIUtils.getScreenScaledWidth (250), - 200); - } - - public JComponent createEditorsFindList (List editors) - { - - Box b = new Box (BoxLayout.Y_AXIS); - b.setAlignmentX (Component.LEFT_ALIGNMENT); - - for (int i = 0; i < editors.size (); i++) - { - - EditorEditor ed = editors.get (i); - - EditorFindInfoBox infBox = this.getEditorFindBox (ed); - - if (i < editors.size () - 1) - { - - infBox.setBorder (new CompoundBorder (new MatteBorder (0, - 0, - 1, - 0, - UIUtils.getBorderColor ()), - new EmptyBorder (5, 0, 5, 0))); - - } else { - - infBox.setBorder (new EmptyBorder (5, 0, 5, 0)); - - } - - infBox.setMaximumSize (new Dimension (Short.MAX_VALUE, - infBox.getPreferredSize ().height + 10)); - /* - infBox.setMinimumSize (new Dimension (300, - infBox.getPreferredSize ().height)); - */ - b.add (infBox); - - } - - b.setBorder (new EmptyBorder (0, 10, 0, 5)); - - return b; - - } - - private EditorInfoBox getEditorBox (final EditorEditor ed) - throws GeneralException - { - - EditorInfoBox b = new EditorInfoBox (ed, - this.viewer, - false); - - b.setAlignmentX (Component.LEFT_ALIGNMENT); - - b.addFullPopupListener (); - - b.init (); - - return b; - - } - - private EditorFindInfoBox getEditorFindBox (final EditorEditor ed) - { - - EditorFindInfoBox b = new EditorFindInfoBox (ed); - b.setAlignmentX (Component.LEFT_ALIGNMENT); - - final EditorsSideBar _this = this; - - b.addMouseListener (new MouseEventHandler () - { - - @Override - public void handlePress (MouseEvent ev) - { - - // Show the editor. - try - { - - _this.showChatBox (ed); - - } catch (Exception e) { - - Environment.logError ("Unable to show editor: " + - ed, - e); - - UIUtils.showErrorMessage (_this.viewer, - getUIString (editors,view,actionerror)); - //"Unable to show {editor}."); - - } - - } - - }); - - UIUtils.setAsButton (b); - - return b; - - } - - private class EditorsSection extends AccordionItem - { - - private Box editorsListWrapper = null; - private AbstractViewer viewer = null; - private String title = null; - private JLabel help = null; - private JLabel noEditorsHelp = null; - private ComponentListener listener = null; - private JComponent content = null; - - public EditorsSection (String title, - String help, - String noEditorsHelp, - AbstractViewer viewer) - { - - super (""); - - this.title = title; - this.viewer = viewer; - - final EditorsSection _this = this; - - this.listener = new ComponentAdapter () - { - - @Override - public void componentResized (ComponentEvent ev) - { - - int count = _this.editorsListWrapper.getComponentCount (); - - for (int i = 0; i < count; i++) - { - - EditorInfoBox infBox = (EditorInfoBox) _this.editorsListWrapper.getComponent (i); - - if (infBox == ev.getSource ()) - { - - _this.setBorder (infBox, - i == (count - 1)); - - } - - } - - } - - }; - - Box content = new Box (BoxLayout.Y_AXIS); - content.setAlignmentX (Component.LEFT_ALIGNMENT); - content.setBorder (UIUtils.createPadding (0, 10, 0, 5)); - - if (help != null) - { - - this.help = UIUtils.createInformationLabel (help); - this.help.setBorder (UIUtils.createPadding (0, 0, 5, 5)); - - content.add (this.help); - - } - - if (noEditorsHelp != null) - { - - this.noEditorsHelp = UIUtils.createInformationLabel (noEditorsHelp); - this.noEditorsHelp.setBorder (UIUtils.createPadding (0, 0, 5, 5)); - - content.add (this.noEditorsHelp); - - } - - this.editorsListWrapper = new Box (BoxLayout.Y_AXIS); - - content.add (this.editorsListWrapper); - - this.content = content; - - } - - @Override - public JComponent getContent () - { - - return this.content; - - } - - private EditorInfoBox getEditorBox (EditorEditor ed) - throws GeneralException - { - - EditorInfoBox b = new EditorInfoBox (ed, - this.viewer, - false); - - b.setAlignmentX (Component.LEFT_ALIGNMENT); - - b.addFullPopupListener (); - - b.init (); - - b.addComponentListener (this.listener); - - return b; - - } - /* - public void updateForEditor (EditorEditor ed) - { - - int count = this.editorsListWrapper.getComponentCount (); - - for (int i = 0; i < count; i++) - { - - EditorInfoBox infBox = (EditorInfoBox) this.editorsListWrapper.getComponent (i); - - if (infBox.getEditor () == ed) - { - - this.setBorder (infBox, - i == (count - 1)); - - } - - } - - } - */ - public void update (Set eds) - throws GeneralException - { - - this.setTitle (String.format (//"%s (%s)", - this.title, - Environment.formatNumber (eds.size ()))); - - if (this.help != null) - { - - this.help.setVisible (eds.size () > 0); - - } - - if (this.noEditorsHelp != null) - { - - this.noEditorsHelp.setVisible (eds.size () == 0); - - } - - this.editorsListWrapper.removeAll (); - - EditorInfoBox last = null; - - for (EditorEditor ed : eds) - { - - EditorInfoBox infBox = this.getEditorBox (ed); - - last = infBox; - - this.editorsListWrapper.add (infBox); - - this.setBorder (infBox, - false); - - } - - if (last != null) - { - - this.setBorder (last, - true); - - } - - } - - private void setBorder (EditorInfoBox b, - boolean isLast) - { - - b.setBorder (isLast ? UIUtils.createPadding (5, 0, 5, 0) : UIUtils.createBottomLineWithPadding (5, 0, 5, 0)); -/* - if (b.isShowAttentionBorder ()) - { - - b.setBorder (new CompoundBorder (new CompoundBorder (new MatteBorder (0, 2, 0, 0, UIUtils.getColor ("#ff0000")), - UIUtils.createPadding (0, 5, 0, 0)), - isLast ? UIUtils.createPadding (5, 0, 5, 0) : UIUtils.createBottomLineWithPadding (5, 0, 5, 0))); - - } else { - - b.setBorder (isLast ? UIUtils.createPadding (5, 0, 5, 0) : UIUtils.createBottomLineWithPadding (5, 0, 5, 0)); - - } - */ - } - - public void updateForProjectEditors (Set pes) - throws GeneralException - { - - Set eds = new LinkedHashSet (); - - for (ProjectEditor pe : pes) - { - - eds.add (pe.getEditor ()); - - } - - this.update (eds); - - } - - } - -} diff --git a/src/com/quollwriter/editors/ui/sidebars/ProjectCommentsSideBar.java b/src/com/quollwriter/editors/ui/sidebars/ProjectCommentsSideBar.java deleted file mode 100644 index 16f1b646..00000000 --- a/src/com/quollwriter/editors/ui/sidebars/ProjectCommentsSideBar.java +++ /dev/null @@ -1,486 +0,0 @@ -package com.quollwriter.editors.ui.sidebars; - -import java.util.Vector; -import java.util.Set; -import java.util.Arrays; - -import java.awt.event.*; -import java.awt.Component; -import java.awt.Dimension; - -import javax.swing.*; -import javax.swing.event.*; - -import com.jgoodies.forms.builder.*; -import com.jgoodies.forms.factories.*; -import com.jgoodies.forms.layout.*; - -import com.quollwriter.*; -import com.quollwriter.events.*; -import com.quollwriter.ui.*; -import com.quollwriter.text.*; -import com.quollwriter.ui.sidebars.*; -import com.quollwriter.editors.*; -import com.quollwriter.editors.ui.*; -import com.quollwriter.editors.messages.*; -import com.quollwriter.ui.components.QPopup; -import com.quollwriter.ui.components.Header; - -import static com.quollwriter.LanguageStrings.*; -import static com.quollwriter.Environment.getUIString; - -public class ProjectCommentsSideBar extends ProjectSentReceivedSideBar -{ - - private JLabel otherCommentsLabel = null; - - public ProjectCommentsSideBar (ProjectCommentsViewer viewer, - ProjectCommentsMessage message) - { - - super (viewer, - message); - - } - - @Override - public void onHide () - { - - } - - @Override - public void onShow () - { - - } - - @Override - public String getTitle () - { - - return getUIString (editors,projectcomments,sidebar,comments,(this.message.isSentByMe () ? sent : received),title); - - //return String.format ("{Comments} %s", - // (this.message.isSentByMe () ? "to" : "from")); - - } - - @Override - public String getItemsIconType () - { - - return Constants.COMMENT_ICON_NAME; - - } - - @Override - public int getItemCount () - { - - return this.message.getComments ().size (); - - } - - @Override - public String getItemsTitle () - { - - return "{Comments}"; - - } - - @Override - public String getIconType () - { - - return null; - - } - - @Override - public JComponent getMessageDetails (ProjectCommentsMessage message) - { - - final ProjectCommentsSideBar _this = this; - - String rows = "p"; - - String verName = this.viewer.getProject ().getProjectVersion ().getName (); - - if (verName != null) - { - - rows += ", 6px, p"; - - } - - final String genComments = message.getGeneralComment (); - - if (genComments != null) - { - - rows += ", 6px, top:p"; - - } - - FormLayout fl = new FormLayout ("right:p, 6px, fill:100px:grow", - rows); - - fl.setHonorsVisibility (true); - PanelBuilder builder = new PanelBuilder (fl); - - CellConstraints cc = new CellConstraints (); - - java.util.List prefix = Arrays.asList (editors,projectcomments,sidebar,comments,labels); - - int row = 1; - - builder.addLabel ("" + getUIString (prefix,(this.message.isSentByMe () ? sent : received)) + "", - //(this.message.isSentByMe () ? "Sent" : "Received"))), - cc.xy (1, - row)); - - builder.addLabel (Environment.formatDateTime (message.getWhen ()), - cc.xy (3, - row)); - - row += 2; - - if (verName != null) - { - - builder.addLabel ("" + getUIString (prefix,version) + "", - //"Version"), - cc.xy (1, - row)); - - builder.addLabel (verName, - cc.xy (3, - row)); - - row += 2; - - } - - if (genComments != null) - { - - builder.addLabel ("" + getUIString (prefix,notes) + "", - //>{Notes}"), - cc.xy (1, - row)); - - String commText = genComments; - - TextIterator ti = new TextIterator (commText); - - final int sc = ti.getSentenceCount (); - - if (sc > 1) - { - - commText = ti.getFirstSentence ().getText (); - - commText += getUIString (prefix,more); - //"
    More, click to view all."; - - } - - JComponent mess = UIUtils.createHelpTextPane (commText, - this.viewer); - - if (sc > 1) - { - - mess.addMouseListener (new MouseEventHandler () - { - - public void handlePress (MouseEvent ev) - { - - UIUtils.showMessage ((PopupsSupported) _this.viewer, - getUIString (editors,projectcomments,sidebar,comments,notes,popup,title), - //"Notes", - genComments); - - } - - }); - - } - - mess.setBorder (null); - - builder.add (mess, - cc.xy (3, - row)); - - row += 2; - - } - - JPanel bp = builder.getPanel (); - bp.setAlignmentX (Component.LEFT_ALIGNMENT); - - Box b = new Box (BoxLayout.Y_AXIS); - - b.add (bp); - - this.otherCommentsLabel = UIUtils.createClickableLabel ("", - Environment.getIcon (Constants.VIEW_ICON_NAME, - Constants.ICON_MENU), - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.showOtherCommentsSelector (); - - } - - }); - - this.otherCommentsLabel.setBorder (UIUtils.createPadding (5, 5, 5, 5)); - - b.add (this.otherCommentsLabel); - - this.showOtherCommentsLabel (); - - return b; - - } - - private void showOtherCommentsSelector () - { - - final ProjectCommentsSideBar _this = this; - - final Vector pcms = new Vector (); - - Set messages = this.getMessage ().getEditor ().getMessages (this.getMessage ().getForProjectId (), - ProjectCommentsMessage.MESSAGE_TYPE); - - for (EditorMessage m : messages) - { - - ProjectCommentsMessage pcm = (ProjectCommentsMessage) m; - - if (pcm.equals (this.getMessage ())) - { - - continue; - - } - - pcms.add (pcm); - - } - - if (pcms.size () == 0) - { - - return; - - } - - if (pcms.size () == 1) - { - - EditorsUIUtils.showProjectComments (pcms.get (0), - _this.viewer, - null); - - } else { - - final JList projCmsL = new JList (pcms); - - projCmsL.addListSelectionListener (new ListSelectionListener () - { - - public void valueChanged (ListSelectionEvent ev) - { - - ProjectCommentsMessage pcm = projCmsL.getSelectedValue (); - - EditorsUIUtils.showProjectComments (pcm, - _this.viewer, - null); - - UIUtils.closePopupParent (projCmsL); - - } - - }); - - projCmsL.setCellRenderer (new DefaultListCellRenderer () - { - - public Component getListCellRendererComponent (JList list, - Object value, - int index, - boolean isSelected, - boolean cellHasFocus) - { - - Box b = new Box (BoxLayout.Y_AXIS); - - if (index < pcms.size () - 1) - { - - b.setBorder (UIUtils.createBottomLineWithPadding (3, 3, 3, 3)); - - } else { - - b.setBorder (UIUtils.createPadding (3, 3, 3, 3)); - - } - - ProjectCommentsMessage pcm = (ProjectCommentsMessage) value; - - int c = pcm.getComments ().size (); - - Header h = UIUtils.createBoldSubHeader (String.format (getUIString (editors,projectcomments,sidebar,comments,othercomments,item,title), - //"%s {comment%s}", - Environment.formatNumber (c)), - //(c == 1 ? "" : "s")), - null); - - b.add (h); - - h.setPreferredSize (new Dimension (Short.MAX_VALUE, - h.getPreferredSize ().height)); - - if (pcm.getProjectVersion ().getName () != null) - { - - JLabel l = UIUtils.createLabel (String.format (getUIString (editors,projectcomments,sidebar,comments,othercomments,item,version), - pcm.getProjectVersion ().getName ())); - l.setBorder (UIUtils.createPadding (0, 5, 0, 5)); - - b.add (l); - - } - - // Get the first line of the notes, if provided. - String genComm = pcm.getGeneralComment (); - - if (genComm != null) - { - - TextIterator ti = new TextIterator (genComm); - - if (ti.getSentenceCount () > 1) - { - - genComm = ti.getFirstSentence ().getText (); - - } - - JComponent mess = UIUtils.createHelpTextPane (genComm, - _this.viewer); - - Box mb = new Box (BoxLayout.X_AXIS); - - mb.setAlignmentX (Component.LEFT_ALIGNMENT); - - mess.setBorder (null); - - mb.add (mess); - - mb.setBorder (UIUtils.createPadding (0, 5, 0, 5)); - - b.add (mb); - - } - - JLabel info = UIUtils.createInformationLabel (String.format (getUIString (editors,projectcomments,sidebar,comments,othercomments,item,(_this.getMessage ().isSentByMe () ? sent : received)), - //"Received: %s", - Environment.formatDate (pcm.getWhen ()))); - - info.setBorder (UIUtils.createPadding (0, 5, 0, 5)); - - b.add (info); - - b.setToolTipText (getUIString (editors,projectcomments,sidebar,comments,othercomments,item,tooltip)); - //"Click to view the {comments}."); - - return b; - - } - - }); - - final QPopup qp = UIUtils.createClosablePopup (getUIString (editors,projectcomments,sidebar,comments,othercomments,popup,title), - //"Select a set of comments to view", - Environment.getIcon (Constants.COMMENT_ICON_NAME, - Constants.ICON_POPUP), - null); - - Box content = new Box (BoxLayout.Y_AXIS); - - UIUtils.setAsButton (projCmsL); - - content.add (projCmsL); - content.setBorder (UIUtils.createPadding (10, 10, 10, 10)); - qp.setContent (content); - - content.setPreferredSize (new Dimension (UIUtils.getPopupWidth (), - content.getPreferredSize ().height)); - - _this.viewer.showPopupAt (qp, - this.otherCommentsLabel, - false); - - qp.setDraggable (_this); - - } - - } - - private void showOtherCommentsLabel () - { - - Set messages = this.getMessage ().getEditor ().getMessages (this.getMessage ().getForProjectId (), - ProjectCommentsMessage.MESSAGE_TYPE); - - int otherC = 0; - - for (EditorMessage m : messages) - { - - ProjectCommentsMessage pcm = (ProjectCommentsMessage) m; - - if (!pcm.equals (this.getMessage ())) - { - - otherC += pcm.getComments ().size (); - - } - - } - - String l = String.format (getUIString (editors,projectcomments,sidebar,comments,labels,othercomments), - Environment.formatNumber (otherC)); -/* - if (c == 1) - { - - l = "1 other {comment} is available for this version, click to view it."; - - } else { - - l = String.format ("%s other {comments} are available for this version, click to select other {comments} to view.", - Environment.formatNumber (c)); - - } -*/ - - this.otherCommentsLabel.setText (l); - - this.otherCommentsLabel.setVisible (otherC > 0); - - } - -}; diff --git a/src/com/quollwriter/editors/ui/sidebars/ProjectSentReceivedSideBar.java b/src/com/quollwriter/editors/ui/sidebars/ProjectSentReceivedSideBar.java deleted file mode 100644 index 6d098ed4..00000000 --- a/src/com/quollwriter/editors/ui/sidebars/ProjectSentReceivedSideBar.java +++ /dev/null @@ -1,265 +0,0 @@ -package com.quollwriter.editors.ui.sidebars; - -import java.awt.Component; -import java.awt.Dimension; -import java.awt.event.*; - -import java.util.Map; -import java.util.HashMap; -import java.util.List; -import java.util.ArrayList; -import java.util.Set; -import java.util.HashSet; - -import javax.swing.*; -import javax.swing.tree.*; -import javax.swing.border.*; - -import com.jgoodies.forms.builder.*; -import com.jgoodies.forms.factories.*; -import com.jgoodies.forms.layout.*; - -import com.quollwriter.*; -import com.quollwriter.ui.*; -import com.quollwriter.ui.sidebars.*; -import com.quollwriter.data.*; -import com.quollwriter.data.editors.*; -import com.quollwriter.events.*; -import com.quollwriter.editors.ui.*; -import com.quollwriter.editors.*; -import com.quollwriter.editors.messages.*; -import com.quollwriter.text.*; - -public abstract class ProjectSentReceivedSideBar extends AbstractSideBar -{ - - public static final String ID = "projectsentreceived"; - - private ProjectCommentsChaptersAccordionItem chapters = null; - private EditorInfoBox editorInfoBox = null; - private EditorEditor editor = null; - private JComponent content = null; - protected E message = null; - - public ProjectSentReceivedSideBar (V v, - E message) - { - - super (v); - - this.editor = message.getEditor (); - this.message = message; - this.content = new Box (BoxLayout.Y_AXIS); - - this.content.setOpaque (false); - this.content.setAlignmentX (Component.LEFT_ALIGNMENT); - this.setMinimumSize (new Dimension (200, - 200)); - - } - - public E getMessage () - { - - return this.message; - - } - - @Override - public String getId () - { - - return ID; - - } - - public abstract String getItemsTitle (); - - public abstract int getItemCount (); - - public abstract String getItemsIconType (); - - public abstract JComponent getMessageDetails (E message); - - public JComponent getContent () - { - - return this.content; - - } - - @Override - public void init (String saveState) - throws GeneralException - { - - final ProjectSentReceivedSideBar _this = this; - - super.init (saveState); - - this.editorInfoBox = new EditorInfoBox (this.editor, - this.viewer, - true).init (); - this.editorInfoBox.setMaximumSize (new Dimension (Short.MAX_VALUE, - this.editorInfoBox.getPreferredSize ().height)); - this.editorInfoBox.setBorder (UIUtils.createPadding (5, 5, 5, 0)); - - this.chapters = new ProjectCommentsChaptersAccordionItem (this.viewer) - { - - @Override - public boolean isAllowObjectPreview () - { - - return false; - - } - - @Override - public int getItemCount () - { - - return _this.getItemCount (); - - } - - }; - - this.chapters.setIconType (this.getItemsIconType ()); - this.chapters.setTitle (this.getItemsTitle ()); - - this.chapters.init (); - - this.content.add (this.editorInfoBox); - - JComponent messageC = this.getMessageDetails (this.message); - - if (messageC != null) - { - - messageC.setMaximumSize (new Dimension (Short.MAX_VALUE, - messageC.getPreferredSize ().height)); - messageC.setOpaque (false); - messageC.setAlignmentX (JComponent.LEFT_ALIGNMENT); - messageC.setBorder (UIUtils.createPadding (5, 0, 0, 5)); - - this.content.add (messageC); - - } - - final Border topLineBorder = new MatteBorder (1, 0, 0, 0, - UIUtils.getInnerBorderColor ()); - final Border noBorder = UIUtils.createPadding (1, 0, 0, 0); - - final JScrollPane sp = this.wrapInScrollPane (this.chapters); - - sp.setBorder (noBorder); - - sp.getVerticalScrollBar ().addAdjustmentListener (new AdjustmentListener () - { - - public void adjustmentValueChanged (AdjustmentEvent ev) - { - - if (sp.getVerticalScrollBar ().getValue () > 0) - { - - sp.setBorder (topLineBorder); - - } else { - - sp.setBorder (noBorder); - - } - - } - - }); - sp.setMinimumSize (new Dimension (200, - 300)); - - this.content.add (sp); - this.chapters.setBorder (UIUtils.createPadding (0, 0, 0, 0)); - - } - - public void reloadTreeForObjectType (String objType) - { - - this.chapters.update (); - - } - - public void showObjectInTree (String treeObjType, - NamedObject obj) - { - - JTree tree = this.getTreeForObjectType (treeObjType); - - if (tree == null) - { - - return; - - } - - DefaultTreeModel dtm = (DefaultTreeModel) tree.getModel (); - - DefaultMutableTreeNode root = (DefaultMutableTreeNode) dtm.getRoot (); - - tree.expandPath (UIUtils.getTreePathForUserObject (root, - obj)); - - } - - public JTree getTreeForObjectType (String objType) - { - - return this.chapters.getTree (); - - } - - public boolean removeOnClose () - { - - return false; - - } - - public void onClose () - { - - - } - - @Override - public String getIconType () - { - - return null; - - } - - public void panelShown (MainPanelEvent ev) - { - - this.chapters.setObjectSelectedInTree (ev.getForObject ()); - - } - - public boolean canClose () - { - - return false; - - } - - @Override - public List getHeaderControls () - { - - return null; - - } - -} diff --git a/src/com/quollwriter/exporter/DocumentExporter.java b/src/com/quollwriter/exporter/DocumentExporter.java deleted file mode 100644 index 8aee105d..00000000 --- a/src/com/quollwriter/exporter/DocumentExporter.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.quollwriter.exporter; - -import java.io.*; - -import com.quollwriter.*; - -import com.quollwriter.data.*; - -import com.quollwriter.ui.*; - - -public interface DocumentExporter -{ - - public void exportProject (File dir) - throws GeneralException; - - public String getStartStage (); - - public WizardStep getStage (String stage); - - public String getNextStage (String currStage); - - public String getPreviousStage (String currStage); - - public void setProject (Project p); - -} diff --git a/src/com/quollwriter/text/ProblemFinder.java b/src/com/quollwriter/text/ProblemFinder.java deleted file mode 100644 index 84901bd4..00000000 --- a/src/com/quollwriter/text/ProblemFinder.java +++ /dev/null @@ -1,1227 +0,0 @@ -package com.quollwriter.text; - -import java.awt.Color; -import java.awt.Component; -import java.awt.Dimension; -import java.awt.event.*; - -import java.text.*; - -import java.util.*; - -import javax.swing.*; -import javax.swing.border.*; -import javax.swing.text.*; - -import com.quollwriter.*; -import com.quollwriter.events.*; -import com.quollwriter.text.rules.*; - -import com.quollwriter.ui.*; -import com.quollwriter.ui.panels.*; -import com.quollwriter.ui.components.BlockPainter; -import com.quollwriter.ui.components.QTextEditor; -import com.quollwriter.ui.components.TextUnderlinePainter; -import com.quollwriter.ui.components.ActionAdapter; - -import static com.quollwriter.LanguageStrings.*; -import static com.quollwriter.Environment.getUIString; - -public class ProblemFinder extends Box -{ - - private QuollEditorPanel editor = null; - private int lastCaret = -1; - private List ignores = new ArrayList (); - private ActionListener showIgnores = null; - private boolean endReached = false; - private boolean startReached = false; - private boolean doSentences = false; - private boolean donePara = false; - private String currPara = null; - private Paragraph paragraph = null; - private Sentence sentence = null; - private TextIterator textIter = null; - private TextBlockIterator iter = null; - private int start = 0; - private int end = -1; - private JLabel limitLabel = null; - private JLabel noProblemsLabel = null; - private int origStart = -1; - private int origEnd = -1; - private Box issuesBox = null; - private boolean inited = false; - private BlockPainter lineHighlight = null; - private TextUnderlinePainter issueHighlight = null; - private ProjectViewer viewer = null; - - public ProblemFinder (QuollEditorPanel editor, - ProjectViewer viewer) - { - - super (BoxLayout.Y_AXIS); - - this.lineHighlight = ProblemFinder.getTextBlockHighlighter (); - this.issueHighlight = ProblemFinder.getIssueHighlighter (); - - this.setAlignmentX (Component.LEFT_ALIGNMENT); - this.setMaximumSize (new Dimension (Short.MAX_VALUE, - Short.MAX_VALUE)); - - this.editor = editor; - this.viewer = viewer; - - // Load the ignores. - try - { - - this.editor.getChapter ().initProblemFinderIgnoreDocumentPositions (this.editor.getEditor ().getDocument ()); - -/* - ((ProjectViewer) this.editor.getViewer ()).getProblemFinderIgnores (this.editor.getChapter (), - this.editor.getEditor ().getDocument ()); -*/ - } catch (Exception e) - { - - Environment.logError ("Unable to load problem finder ignores for chapter: " + - this.editor.getChapter (), - e); - - } - - final ProblemFinder _this = this; - - this.editor.getEditor ().getCaret ().addChangeListener (new javax.swing.event.ChangeListener () - { - - public void stateChanged (javax.swing.event.ChangeEvent ev) - { - - if (!_this.isShowing ()) - { - - return; - - } - - _this.inited = false; - - _this.start = _this.editor.getEditor ().getSelectionStart (); - _this.end = _this.editor.getEditor ().getSelectionEnd (); - - } - - }); - - java.util.List prefix = new ArrayList<> (); - prefix.add (LanguageStrings.project); - prefix.add (LanguageStrings.editorpanel); - prefix.add (LanguageStrings.actions); - prefix.add (LanguageStrings.problemfinder); - - this.limitLabel = new JLabel (Environment.getUIString (prefix, - LanguageStrings.limit), - //"Limiting find to selected text.", - Environment.getIcon ("information", - Constants.ICON_MENU), - SwingConstants.TRAILING); - - this.limitLabel.setVisible (false); - - this.limitLabel.setBorder (UIUtils.createPadding (5, 10, 3, 3)); - - this.noProblemsLabel = new JLabel (Environment.getUIString (prefix, - LanguageStrings.noproblemsfound), - //"No problems found.", - Environment.getIcon ("information", - Constants.ICON_MENU), - SwingConstants.TRAILING); - - this.noProblemsLabel.setAlignmentX (Component.LEFT_ALIGNMENT); - this.noProblemsLabel.setOpaque (false); - this.noProblemsLabel.setBorder (UIUtils.createPadding (5, 10, 3, 3)); - this.noProblemsLabel.setVisible (false); - - this.issuesBox = new Box (BoxLayout.Y_AXIS); - this.issuesBox.setAlignmentX (Component.LEFT_ALIGNMENT); - - this.add (this.limitLabel); - this.add (this.noProblemsLabel); - this.add (this.issuesBox); - - } - - public void removeAllIgnores () - { - - this.editor.getChapter ().getProblemFinderIgnores ().clear (); - - try - { - - this.viewer.saveProblemFinderIgnores (this.editor.getChapter ()); - - } catch (Exception e) { - - Environment.logError ("Unable to save problem finder ignores for chapter: " + - this.editor.getChapter (), - e); - - UIUtils.showErrorMessage (this.viewer, - Environment.getUIString (LanguageStrings.project, - LanguageStrings.editorpanel, - LanguageStrings.actions, - LanguageStrings.problemfinder, - LanguageStrings.unignoreall, - LanguageStrings.actionerror)); - //"Unable to remove all ignores."); - - return; - - } - - if (this.showIgnores != null) - { - - this.showIgnores.actionPerformed (new ActionEvent (this, - 0, - "")); - - } - - this.viewer.fireProjectEvent (ProjectEvent.PROBLEM_FINDER, - ProjectEvent.UNIGNORE); - - } - - public Set getIgnoredIssues () - { - - return this.editor.getChapter ().getProblemFinderIgnores (); - - } - - public void saveIgnores () - { - - // Check to see if they are still valid. - try - { - - this.viewer.saveProblemFinderIgnores (this.editor.getChapter ()); - - } catch (GeneralException e) - { - - Environment.logError ("Unable to save problem finder ignores for chapter: " + - this.editor.getChapter (), - e); - - } - - } - - public void reset () - { - - this.getIgnores (); - - this.clearHighlights (); - - } - - private void init (int start, - int end) - { - - this.start = start; - this.end = end; - - this.getIgnores (); - this.clearHighlights (); - - if (this.end < this.start) - { - - this.end = -1; - - } - - if (this.start == this.end) - { - - this.end = -1; - - } - - this.noProblemsLabel.setVisible (false); - this.clearIssuesBox (); - - this.limitLabel.setVisible (this.end > -1); - - this.iter = new TextBlockIterator (this.editor.getEditor ().getText (), - this.start, - this.end); - - this.inited = true; - - } - - public int start () - throws Exception - { - - this.origStart = this.editor.getEditor ().getSelectionStart (); - this.origEnd = this.editor.getEditor ().getSelectionEnd (); - - this.init (this.origStart, - this.origEnd); - - return this.next (); - - } - - private void clearHighlights () - { - - this.editor.getEditor ().removeAllHighlights (this.lineHighlight); - this.editor.getEditor ().removeAllHighlights (this.issueHighlight); - - } - - private int processTextBlock (TextBlock b) - throws Exception - { - - if (b == null) - { - - return 0; - - } - - if (b instanceof Paragraph) - { - - return this.handleParagraph ((Paragraph) b); - - } - - if (b instanceof Sentence) - { - - return this.handleSentence ((Sentence) b); - - } - - throw new GeneralException ("Type: " + - b.getClass ().getName () + - " not supported."); - - } - - private int handleParagraph (Paragraph p) - throws Exception - { - - List issues = RuleFactory.getParagraphIssues (p, - this.viewer.getProject ().getProperties ()); - - this.setPositions (issues); - - if ((issues.size () != 0) - && - (!this.allIgnores (issues)) - ) - { - - this.handleIssues (issues, - p); - - return issues.size (); - - } - - return 0; - - } - - private int handleSentence (Sentence s) - throws Exception - { - - List issues = RuleFactory.getSentenceIssues (s, - this.viewer.getProject ().getProperties ()); - - this.setPositions (issues); - - if ((issues.size () != 0) - && - (!this.allIgnores (issues)) - ) - { - - this.handleIssues (issues, - s); - - return issues.size (); - - } - - return 0; - - } - - public int next () - throws Exception - { - - if (!this.inited) - { - - this.init (this.start, - this.end); - - } - - this.noProblemsLabel.setVisible (false); - - // Prevent the block being highlighted but ensure that inited is still true since the caret - // change will set it to false. - this.editor.getEditor ().setSelectionEnd (this.start); - - this.inited = true; - - final ProblemFinder _this = this; - - this.getIgnores (); - - this.clearHighlights (); - - TextBlock b = null; - - while ((b = this.iter.next ()) != null) - { - - Environment.logDebugMessage ("Looking for problems in: " + b); - - int c = this.processTextBlock (b); - - if (c > 0) - { - - Environment.logDebugMessage ("Got: " + c + " problems for text: " + b); - - return c; - - } - - } - - this.addNoProblems (); - - if (this.end > -1) - { - - java.util.List prefix = Arrays.asList (project,editorpanel,actions,problemfinder,nomoreproblems,selected,LanguageStrings.end); - - UIUtils.showMessage (this.viewer, - getUIString (prefix,title), - //"No more problems found", - getUIString (prefix,text), - //"No more problems found in selected text.", - getUIString (buttons,finish), - //"Finish", - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.editor.getEditor ().select (_this.start, - _this.end); - - _this.inited = false; - - } - - }); - - return 0; - - } - - ActionListener onCancel = new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.reset (); - - } - - }; - - final java.util.List prefix = new ArrayList<> (); - prefix.add (LanguageStrings.project); - prefix.add (LanguageStrings.editorpanel); - prefix.add (LanguageStrings.actions); - prefix.add (LanguageStrings.problemfinder); - prefix.add (LanguageStrings.nomoreproblems); - prefix.add (LanguageStrings.end); - - UIUtils.createQuestionPopup (this.viewer, - Environment.getUIString (prefix, - LanguageStrings.title), - //"No more problems found", - Constants.INFO_ICON_NAME, - Environment.getUIString (prefix, - LanguageStrings.text), - //"No more problems found. Return to the start of the {chapter}?", - Environment.getUIString (prefix, - LanguageStrings.buttons, - LanguageStrings.confirm), - //"Yes, return to the start", - Environment.getUIString (prefix, - LanguageStrings.buttons, - LanguageStrings.cancel), - //null, - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - UIUtils.doLater (new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - try - { - - _this.init (0, - -1); - - _this.next (); - - } catch (Exception e) { - - Environment.logError ("Unable to move back to start", - e); - - UIUtils.showErrorMessage (_this.viewer, - Environment.getUIString (prefix, - LanguageStrings.actionerror)); - //"Unable to move back to start of {chapter}"); - - } - - } - - }); - - } - - }, - onCancel, - onCancel, - null); - - return 0; - - } - - public int previous () - throws Exception - { - - if (!this.inited) - { - - this.init (this.start, - this.end); - - } - - this.noProblemsLabel.setVisible (false); - - final ProblemFinder _this = this; - - this.getIgnores (); - - this.clearHighlights (); - - TextBlock b = null; - - while ((b = this.iter.previous ()) != null) - { - - Environment.logDebugMessage ("Looking for problems in: " + b); - - int c = this.processTextBlock (b); - - if (c > 0) - { - - Environment.logDebugMessage ("Got: " + c + " problems for text: " + b); - - return c; - - } - - } - - this.addNoProblems (); - - if (this.end > -1) - { - - java.util.List prefix = Arrays.asList (project,editorpanel,actions,problemfinder,nomoreproblems,selected,LanguageStrings.end); - - UIUtils.showMessage (this.viewer, - getUIString (prefix,title), - //"No more problems found", - getUIString (prefix,text), - //"No more problems found in selected text.", - getUIString (buttons,finish), - //"Finish", - null); - - return 0; - - } - - final java.util.List prefix = new ArrayList<> (); - prefix.add (LanguageStrings.project); - prefix.add (LanguageStrings.editorpanel); - prefix.add (LanguageStrings.actions); - prefix.add (LanguageStrings.problemfinder); - prefix.add (LanguageStrings.nomoreproblems); - prefix.add (LanguageStrings.start); - - UIUtils.showMessage ((PopupsSupported) this.editor, - Environment.getUIString (prefix, - LanguageStrings.title), - //"No more problems", - Environment.getUIString (prefix, - LanguageStrings.text)); - //"No more problems found"); - - return 0; - - } - - private void addNoProblems () - { - - this.clearIssuesBox (); - - this.noProblemsLabel.setVisible (true); - - this.getParent ().getParent ().validate (); - this.getParent ().getParent ().repaint (); - - } - - public void removeCheckboxesForRule (Rule r) - { - - for (IgnoreCheckbox b : this.ignores) - { - - if (r.getId ().equals (b.issue.getRule ().getId ())) - { - - this.remove (b); - - } - - } - - this.getParent ().getParent ().validate (); - this.getParent ().getParent ().repaint (); - - } - - private void getIgnores () - { - - for (IgnoreCheckbox b : this.ignores) - { - - if (b.isSelected ()) - { - - this.editor.getChapter ().getProblemFinderIgnores ().add (b.issue); - - this.viewer.fireProjectEvent (ProjectEvent.PROBLEM_FINDER, - ProjectEvent.IGNORE); - - } else { - - if (this.editor.getChapter ().getProblemFinderIgnores ().remove (b.issue)) - { - - this.viewer.fireProjectEvent (ProjectEvent.PROBLEM_FINDER, - ProjectEvent.UNIGNORE); - - } - - } - - } - - this.ignores = new ArrayList (); - - } - - private IgnoreCheckbox createIssueItem (Issue iss) - { - - IgnoreCheckbox cb = new IgnoreCheckbox (iss.getDescription (), - iss, - this.editor, - this.viewer); - cb.setAlignmentX (Component.LEFT_ALIGNMENT); - cb.setOpaque (false); - cb.setBorder (new EmptyBorder (5, - 10, - 3, - 3)); - - final ProblemFinder _this = this; - - final QTextEditor ed = this.editor.getEditor (); - - final Issue issue = iss; - - cb.addMouseListener (new MouseEventHandler () - { - - @Override - public void mouseEntered (MouseEvent ev) - { - - try - { - - ed.addHighlight (iss.getStartIssuePosition (), - iss.getEndIssuePosition (), - _this.issueHighlight, - false); - - } catch (Exception e) - { - - // Ignore. - - } - - } - - @Override - public void mouseExited (MouseEvent ev) - { - - ed.removeAllHighlights (_this.issueHighlight); - - } - - }); - - this.ignores.add (cb); - - return cb; - - } - - private void setPositions (List issues) - { - - try - { - - for (Issue i : issues) - { - - i.setStartPosition (this.editor.getEditor ().getDocument ().createPosition (i.getStartIssuePosition ())); - - // Set the end position of the sentence. - i.setEndPosition (this.editor.getEditor ().getDocument ().createPosition (i.getEndIssuePosition ())); - - } - - } catch (Exception e) - { - - // Ignore. - - } - - } - - private void clearIssuesBox () - { - - this.issuesBox.removeAll (); - - } - - private void handleIssues (final List issues, - final TextBlock textBlock) - throws Exception - { - - Collections.sort (issues, - new IssueSorter ()); - - List ignored = this.removeIgnores (issues); - - if (issues.size () > 0) - { - - this.clearIssuesBox (); - - final ProblemFinder _this = this; - - this.lastCaret = this.editor.getEditor ().getSelectionStart (); - - // Convert to the view. - int height = -1; - - UIUtils.doLater (new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - try - { - - _this.editor.scrollToPosition (textBlock.getAllTextStartOffset ());//selStart);//_this.sentIter.getOffset ()); - - } catch (Exception e) { - - Environment.logError ("Unable to scroll to: " + - textBlock.getAllTextStartOffset (), //selStart, //_this.sentIter.getOffset (), - e); - - } - - } - - }); - - final QTextEditor ed = this.editor.getEditor (); - - for (Issue i : issues) - { - - this.issuesBox.add (this.createIssueItem (i)); -/* - if (i.getRule () instanceof SentenceRule) - { - - this.issuesBox.add (this.createSentenceIssueItem (i, - (Sentence) textBlock)); - - } else { - - this.issuesBox.add (this.createIssueItem (i)); - - } -*/ - } - - if (ignored.size () > 0) - { - - java.util.List prefix = new ArrayList<> (); - prefix.add (LanguageStrings.project); - prefix.add (LanguageStrings.editorpanel); - prefix.add (LanguageStrings.actions); - prefix.add (LanguageStrings.problemfinder); - prefix.add (LanguageStrings.unignoreissues); - - String t = null; - - if (ignored.size () == 1) - { - - t = Environment.getUIString (prefix, - LanguageStrings.single); - - } else { - - t = String.format (Environment.getUIString (prefix, - LanguageStrings.plural), - Environment.formatNumber (ignored.size ())); - - } - - final JLabel l = UIUtils.createClickableLabel (t, - Environment.getIcon ("warning", - Constants.ICON_MENU)); - - l.setBorder (new EmptyBorder (5, - 10, - 3, - 3)); - - this.issuesBox.add (l); - - final java.util.List ignoredItems = new ArrayList (); - - for (Issue i : ignored) - { - - IgnoreCheckbox icb = this.createIssueItem (i); - - ignoredItems.add (icb); - icb.setVisible (false); - icb.setSelected (true); - this.issuesBox.add (icb); - - } - - this.showIgnores = new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - for (IgnoreCheckbox icb : ignoredItems) - { - - icb.setVisible (true); - - icb.setSelected ("selected".equals (ev.getActionCommand ())); - - //_this.issuesToIgnore.remove (icb.issue); - - } - - l.setVisible (false); - - _this.viewer.fireProjectEvent (ProjectEvent.PROBLEM_FINDER, - ProjectEvent.UNIGNORE); - - _this.getParent ().getParent ().validate (); - _this.getParent ().getParent ().repaint (); - - } - - }; - - l.addMouseListener (new MouseAdapter () - { - - public void mousePressed (MouseEvent ev) - { - - _this.showIgnores.actionPerformed (new ActionEvent (l, - 0, - "selected")); - - _this.viewer.fireProjectEvent (ProjectEvent.PROBLEM_FINDER, - ProjectEvent.UNIGNORE); - - } - - }); - - } - - int end = textBlock.getAllTextEndOffset () + 1; - - if (textBlock instanceof Sentence) - { - - end = ((Sentence) textBlock).getLastWord ().getAllTextEndOffset (); - - } - - ed.addHighlight (textBlock.getAllTextStartOffset (), - end, - this.lineHighlight, - false); - - this.getParent ().getParent ().validate (); - this.getParent ().getParent ().repaint (); - - } - - } - - private boolean allIgnores (List issues) - { - - for (Issue i : issues) - { - - if (!this.shouldIgnore (i)) - { - - return false; - - } - - } - - return true; - - } - - private List removeIgnores (List issues) - { - - Iterator iter = issues.iterator (); - - List ignored = new ArrayList (); - - while (iter.hasNext ()) - { - - Issue i = iter.next (); - - if (this.shouldIgnore (i)) - { - - ignored.add (i); - iter.remove (); - - } - - } - - return ignored; - - } - - private boolean shouldIgnore (Issue iss) - { - - for (Issue i : this.editor.getChapter ().getProblemFinderIgnores ()) - { - - if (i.equals (iss)) - { - - return true; - - } - - } - - return false; - - } - - private class TextBlockIterator - { - - private TextIterator iter = null; - private Paragraph para = null; - private Sentence sent = null; - private int endAt = -1; - private int startAt = -1; - private TextBlock current = null; - - public TextBlockIterator (String text, - int startAt, - int endAt) - { - - this.iter = new TextIterator (text); - this.startAt = startAt; - - this.endAt = endAt; - - } - - public TextBlock next () - { - - if (this.para == null) - { - - this.para = this.iter.getNextClosestParagraphTo (this.startAt); - - if (this.para == null) - { - - // At the end. - return null; - - } - - if (this.startAt > this.para.getStart ()) - { - - this.sent = this.para.getNextClosestSentenceTo (this.startAt - this.para.getStart ()); - - return this.sent; - - } - - } else { - - if (this.sent == null) - { - - this.sent = this.para.getFirstSentence (); - - } else { - - this.sent = this.sent.getNext (); - - } - - if (this.sent == null) - { - - // Get the next paragraph. - this.para = this.para.getNext (); - - } else { - - if ((this.sent.getAllTextStartOffset () > this.endAt) - && - (this.endAt > -1) - ) - { - - return null; - - } - - return this.sent; - - } - - if (this.para == null) - { - - // Reached the end; - return null; - - } - - } - - if ((this.para.getAllTextStartOffset () > this.endAt) - && - (this.endAt > -1) - ) - { - - return null; - - } - - return this.para; - - } - - public TextBlock previous () - { - - if (this.para == null) - { - - this.para = this.iter.getPreviousClosestParagraphTo (this.startAt); - - if (this.para == null) - { - - return null; - - } - - if (this.startAt > this.para.getEnd ()) - { - - this.sent = this.para.getLastSentence (); - - } else { - - this.sent = this.para.getPreviousClosestSentenceTo (this.startAt - this.para.getStart ()); - - } - - } else { - - if (this.sent == null) - { - - this.para = this.para.getPrevious (); - - if (this.para == null) - { - - return null; - - } - - this.sent = this.para.getLastSentence (); - - } else { - - this.sent = this.sent.getPrevious (); - - } - - if (this.sent == null) - { - - if ((this.startAt > this.para.getAllTextStartOffset ()) - && - (this.endAt > -1) - ) - { - - return null; - - } - - return this.para; - - } - - } - - if ((this.startAt > this.sent.getAllTextStartOffset ()) - && - (this.endAt > 1) - ) - { - - return null; - - } - - return this.sent; - - } - - } - - public static BlockPainter getTextBlockHighlighter () - { - - return new BlockPainter (Environment.getHighlightColor ()); - - } - - public static TextUnderlinePainter getIssueHighlighter () - { - - return new TextUnderlinePainter (Color.RED); - - } - -} diff --git a/src/com/quollwriter/text/Rule.java b/src/com/quollwriter/text/Rule.java deleted file mode 100644 index 6cece45f..00000000 --- a/src/com/quollwriter/text/Rule.java +++ /dev/null @@ -1,63 +0,0 @@ -package com.quollwriter.text; - -import java.util.*; -import java.awt.event.*; - -import javax.swing.*; - -import com.gentlyweb.xml.*; - -import com.quollwriter.ui.*; -import com.quollwriter.ui.forms.*; - -import org.jdom.*; - - -public interface Rule -{ - - public static final String WORD_CATEGORY = "word"; - public static final String SENTENCE_CATEGORY = "sentence"; - public static final String PARAGRAPH_CATEGORY = "paragraph"; - - public String getDescription (); - - public void setDescription (String d); - - public String getDefaultSummary (); - - public String getSummary (); - - public void setSummary (String i); -/* - public List getIssues (String sentence, - boolean inDialogue); -*/ - - public List getIssues (E block); - - public void init (Element root) - throws JDOMException; - - public Element getAsElement (); - - public String getId (); - - public void setId (String id); - - public String getCategory (); - - public void setUserRule (boolean u); - - public boolean isUserRule (); - - public String getEditFormTitle (boolean add); - - public Form getEditForm (ActionListener onSaveComplete, - ActionListener onCancel, - AbstractProjectViewer viewer, - boolean add); - - public void updateFromForm (); - -} diff --git a/src/com/quollwriter/text/TextBlockIterator.java b/src/com/quollwriter/text/TextBlockIterator.java deleted file mode 100644 index 4b8838b1..00000000 --- a/src/com/quollwriter/text/TextBlockIterator.java +++ /dev/null @@ -1,400 +0,0 @@ -package com.quollwriter.text; - -import java.util.*; - -public class TextBlockIterator implements Iterator -{ - - private TextBlock current = null; - private boolean firstDone = false; - - public TextBlockIterator (String t) - { - - if (t == null) - { - - return; - - } - - TextIterator ti = new TextIterator (t); - - this.current = ti.getFirstParagraph (); - - } - - public TextBlockIterator (TextIterator ti) - { - - if (ti == null) - { - - return; - - } - - this.current = ti.getFirstParagraph (); - - - } - - public TextBlockIterator (Sentence s) - { - - this.current = s; - - } - - public TextBlockIterator (Paragraph p) - { - - this.current = p; - - } - - public boolean hasNext () - { - - if (this.current == null) - { - - return false; - - } - - if (this.current instanceof Sentence) - { - - Sentence n = (Sentence) this.current.getNext (); - - if (n == null) - { - - n = (Sentence) this.current; - - return (Paragraph) n.getParagraph ().getNext () != null; - - } - - } - - return true; - - } - - public boolean hasPrevious () - { - - if (this.current == null) - { - - return false; - - } - - if (this.current instanceof Sentence) - { - - Sentence n = (Sentence) this.current.getPrevious (); - - if (n == null) - { - - n = (Sentence) this.current; - - return (Paragraph) n.getParagraph ().getPrevious () != null; - - } - - } - - return true; - - } - - public boolean hasNextSentence () - { - - if (this.current == null) - { - - return false; - - } - - if (this.current instanceof Sentence) - { - - Sentence n = (Sentence) this.current.getNext (); - - if (n == null) - { - - n = (Sentence) this.current; - - return (Paragraph) n.getParagraph ().getNext () != null; - - } - - } - - return true; - - } - - public boolean hasPreviousSentence () - { - - if (this.current == null) - { - - return false; - - } - - if (this.current instanceof Sentence) - { - - Sentence n = (Sentence) this.current.getPrevious (); - - if (n == null) - { - - n = (Sentence) this.current; - - return (Paragraph) n.getParagraph ().getPrevious () != null; - - } - - } - - return true; - - } - - public boolean hasNextParagraph () - { - - if (this.current == null) - { - - return false; - - } - - if (this.current instanceof Sentence) - { - - Sentence n = (Sentence) this.current; - - return (Paragraph) n.getParagraph ().getNext () != null; - - } - - if (this.current instanceof Paragraph) - { - - return ((Paragraph) this.current).getNext () != null; - - } - - return false; - - } - - public boolean hasPreviousParagraph () - { - - if (this.current == null) - { - - return false; - - } - - if (this.current instanceof Sentence) - { - - Sentence n = (Sentence) this.current; - - return (Paragraph) n.getParagraph ().getPrevious () != null; - - } - - if (this.current instanceof Paragraph) - { - - return ((Paragraph) this.current).getPrevious () != null; - - } - - return false; - - } - - public TextBlock current () - { - - return this.current; - - } - - public TextBlock next () - { - - if (!this.firstDone) - { - - this.firstDone = true; - - return this.current; - - } - - if (this.current instanceof Sentence) - { - - Sentence n = (Sentence) this.current.getNext (); - - if (n == null) - { - - n = (Sentence) this.current; - - this.current = (Paragraph) n.getParagraph ().getNext (); - - } else { - - this.current = n; - - } - - } - - if (this.current instanceof Paragraph) - { - - this.current = ((Paragraph) this.current).getFirstSentence (); - - } - - return this.current; - - } - - public TextBlock previous () - { - - if (!this.firstDone) - { - - this.firstDone = true; - - return this.current; - - } - - if (this.current instanceof Sentence) - { - - Sentence n = ((Sentence) this.current).getPrevious (); - - if (n == null) - { - - n = (Sentence) this.current; - - this.current = n.getParagraph ().getPrevious (); - - } else { - - this.current = n; - - } - - } - - if (this.current instanceof Paragraph) - { - - this.current = ((Paragraph) this.current).getPrevious ().getLastSentence (); - - } - - return this.current; - - } - - public Sentence previousSentence () - { - - TextBlock prev = this.previous (); - - if (prev instanceof Paragraph) - { - - this.current = ((Paragraph) prev).getLastSentence (); - - } - - return (Sentence) this.current; - - } - - public Sentence nextSentence () - { - - TextBlock next = this.next (); - - if (next instanceof Paragraph) - { - - this.current = ((Paragraph) next).getFirstSentence (); - - } - - return (Sentence) this.current; - - } - - public Paragraph nextParagraph () - { - - TextBlock next = this.next (); - - if (next instanceof Sentence) - { - - this.current = ((Sentence) next).getParagraph ().getNext (); - - } - - return (Paragraph) this.current; - - } - - public Paragraph previousParagraph () - { - - TextBlock prev = this.previous (); - - if (prev instanceof Sentence) - { - - this.current = ((Sentence) prev).getParagraph ().getPrevious (); - - } - - return (Paragraph) this.current; - - } - - public void remove () - { - - throw new UnsupportedOperationException ("Not supported."); - - } - -} \ No newline at end of file diff --git a/src/com/quollwriter/text/rules/AbstractRule.java b/src/com/quollwriter/text/rules/AbstractRule.java deleted file mode 100644 index a25b0ff4..00000000 --- a/src/com/quollwriter/text/rules/AbstractRule.java +++ /dev/null @@ -1,323 +0,0 @@ -package com.quollwriter.text.rules; - -import java.util.*; -import java.awt.event.*; - -import javax.swing.*; - -import com.gentlyweb.xml.*; - -import com.quollwriter.*; -import com.quollwriter.ui.*; -import com.quollwriter.ui.forms.*; -import com.quollwriter.text.*; - -import org.jdom.*; - - -public abstract class AbstractRule implements Rule -{ - - public class XMLConstants - { - - public static final String root = "rule"; - public static final String description = "description"; - public static final String id = "id"; - public static final String user = "user"; - public static final String summary = "summary"; - public static final String createType = "createType"; - - } - - protected String summary = null; - protected String desc = null; - protected String id = null; - protected boolean userRule = false; - private String defaultSummary = null; - - public AbstractRule () - { - - } - - public abstract String getEditFormTitle (boolean add); - - public abstract Set getFormItems (); - - public abstract String getFormError (); - - public String getDefaultSummary () - { - - return this.defaultSummary; - - } - - @Override - public void setSummary (String s) - { - - this.summary = s; - - } - - @Override - public String getSummary () - { - - return this.summary; - - } - - @Override - public void setUserRule (boolean u) - { - - this.userRule = u; - - } - - @Override - public boolean isUserRule () - { - - return this.userRule; - - } - - public void setDescription (String d) - { - - this.desc = d; - - } - - public void setId (String id) - { - - this.id = id; - - } - - public String getId () - { - - return this.id; - - } - - public String getDescription () - { - - return this.desc; - - } - - public void init (Element root) - throws JDOMException - { - - this.id = JDOMUtils.getAttributeValue (root, - XMLConstants.id); - - this.userRule = JDOMUtils.getAttributeValueAsBoolean (root, - XMLConstants.user, - false); - - this.desc = JDOMUtils.getChildElementContent (root, - XMLConstants.description, - false); - - this.summary = JDOMUtils.getChildElementContent (root, - XMLConstants.summary, - true); - - if (!this.userRule) - { - - this.defaultSummary = this.summary; - - } - - } - - public Element getAsElement () - { - - Element root = new Element (XMLConstants.root); - - root.setAttribute (XMLConstants.id, - this.id); - root.setAttribute (XMLConstants.createType, - this.getClass ().getName ()); - - if (this.userRule) - { - - root.setAttribute (XMLConstants.user, - Boolean.toString (this.userRule)); - - } - - Element summ = new Element (XMLConstants.summary); - - root.addContent (summ); - - summ.addContent (this.summary); - - if ((this.desc != null) - && - (this.desc.length () > 0) - ) - { - - Element desc = new Element (XMLConstants.description); - - root.addContent (desc); - - desc.addContent (this.desc); - - } - - return root; - - } - - public Form getEditForm (final ActionListener onSaveComplete, - final ActionListener onCancel, - final AbstractProjectViewer viewer, - final boolean add) - { - - final AbstractRule _this = this; - - Set items = new LinkedHashSet (); - - final TextFormItem summary = new TextFormItem (Environment.getUIString (LanguageStrings.form, - LanguageStrings.labels, - LanguageStrings.summary), - //"Summary", - this.getSummary ()); - - items.add (summary); - - items.addAll (this.getFormItems ()); - - final MultiLineTextFormItem desc = new MultiLineTextFormItem (Environment.getUIString (LanguageStrings.form, - LanguageStrings.labels, - LanguageStrings.description), - //"Description", - viewer, - 5); - desc.setText (this.getDescription ()); - desc.setCanFormat (false); - - items.add (desc); - - Map buttons = new LinkedHashMap (); - - buttons.put (Form.Button.save, - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - Form f = (Form) ev.getSource (); - - String error = _this.getFormError (); - - if (error != null) - { - - f.showError (error); - - return; - - } - - _this.setDescription (desc.getText ().trim ()); - - String summ = summary.getText (); - - if (summ == null) - { - - summ = ""; - - } else { - - summ = summ.trim (); - - } - - if (summ.length () == 0) - { - - summ = _this.getSummary (); - - } - - if (summ == null) - { - - summ = _this.getDefaultSummary (); - - } - - if (summ == null) - { - - f.showError (Environment.getUIString (LanguageStrings.problemfinder, - LanguageStrings.config, - LanguageStrings.entersummaryerror)); - - return; - - } - - _this.setSummary (summ); - - if (onSaveComplete != null) - { - - onSaveComplete.actionPerformed (new ActionEvent (_this, 1, "saved")); - - } - - } - - }); - - buttons.put (Form.Button.cancel, - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - if (onCancel != null) - { - - onCancel.actionPerformed (new ActionEvent (_this, 1, "cancelled")); - - } - - return; - - } - - }); - - Form f = new Form (Form.Layout.stacked, - items, - buttons); - - return f; - - } - -} diff --git a/src/com/quollwriter/text/rules/AdverbRule.java b/src/com/quollwriter/text/rules/AdverbRule.java deleted file mode 100644 index fc37dd2b..00000000 --- a/src/com/quollwriter/text/rules/AdverbRule.java +++ /dev/null @@ -1,398 +0,0 @@ -package com.quollwriter.text.rules; - -import java.awt.Component; -import java.awt.event.*; - -import java.util.*; - -import javax.swing.*; -import javax.swing.border.*; - -import com.gentlyweb.xml.*; - -import com.quollwriter.*; - -import com.quollwriter.synonyms.*; - -import com.quollwriter.text.*; -import com.quollwriter.ui.*; -import com.quollwriter.ui.forms.*; - -import org.jdom.*; - - -public class AdverbRule extends AbstractSentenceRule -{ - - public class XMLConstants - { - - public static final String speechVerbs = "speechVerbs"; - - } - - private Set speechVerbs = new HashSet (); - private JTextField newVerbs = null; - private DefaultListModel listModel = null; - - public AdverbRule () - { - - } - - @Override - public String getCategory () - { - - return Rule.SENTENCE_CATEGORY; - - } - - @Override - public void init (Element root) - throws JDOMException - { - - super.init (root); - - String sw = JDOMUtils.getAttributeValue (root, - XMLConstants.speechVerbs); - - StringTokenizer t = new StringTokenizer (sw, - ","); - - while (t.hasMoreTokens ()) - { - - this.speechVerbs.add (t.nextToken ().trim ().toLowerCase ()); - - } - - } - - public void setSpeechVerbs (Set verbs) - { - - this.speechVerbs = verbs; - - } - - public boolean isSpeechVerb (String w) - { - - if (w == null) - { - - return false; - - } - - return this.speechVerbs.contains (w.toLowerCase ()); - - } - - @Override - public Element getAsElement () - { - - Element root = super.getAsElement (); - - StringBuilder b = new StringBuilder (); - - for (String w : this.speechVerbs) - { - - if (b.length () > 0) - { - - b.append (","); - - } - - b.append (w); - - } - - root.setAttribute (XMLConstants.speechVerbs, - b.toString ()); - - return root; - - } - - @Override - public List getIssues (Sentence sentence) - { - - List issues = new ArrayList (); - - String adverbWT = String.valueOf (Synonyms.ADVERB); - - List swords = sentence.getWords (); - - for (Word w : swords) - { - - if (w.isInDialogue ()) - { - - continue; - - } - - if (this.isSpeechVerb (w.getText ())) - { - - Word nw = w.getNext (); - - if (nw != null) - { - - try - { - - String wt = Environment.getWordTypes (nw.getText (), - // We assume english for now - null); - - if (wt != null) - { - - // We are only interested in those that are purely adverbs (no other word types) - if (wt.equals (adverbWT)) - { - - // Maybe check to see if it's after a " - - // Add an issue. - Issue iss = new Issue (String.format (Environment.getUIString (LanguageStrings.problemfinder, - LanguageStrings.issues, - LanguageStrings.adverb, - LanguageStrings.text), - nw.getText (), - w.getText ()), - //"Use of adverb: " + nw.getText () + - //" to modify speech verb: " + w.getText () + "", - sentence, - sentence.getAllTextStartOffset () + "-" + nw.getText () + "-" + w.getText (), - this); - issues.add (iss); - - } - - } - - - } catch (Exception e) - { - - Environment.logError ("Unable to check for word: " + - nw + - " being an adverb."); - - } - - } - - } - - - } - - return issues; - - } - - @Override - public Set getFormItems () - { - - final AdverbRule _this = this; - - List pref = new ArrayList (); - pref.add (LanguageStrings.problemfinder); - pref.add (LanguageStrings.config); - pref.add (LanguageStrings.rules); - pref.add (LanguageStrings.adverb); - pref.add (LanguageStrings.labels); - - Set items = new LinkedHashSet (); - - Box b = new Box (BoxLayout.Y_AXIS); - - this.newVerbs = com.quollwriter.ui.UIUtils.createTextField (); - - b.add (newVerbs); - - JLabel label = new JLabel (Environment.getUIString (pref, - LanguageStrings.separate)); - //"(separate with , or ;)"); - label.setBorder (UIUtils.createPadding (0, 5, 0, 0)); - - b.add (label); - - items.add (new AnyFormItem (Environment.getUIString (pref, - LanguageStrings.newspeechverbs), - //"New Speech Verbs", - b)); - - Vector v = new Vector (this.speechVerbs); - - Collections.sort (v); - - this.listModel = new DefaultListModel (); - - for (int i = 0; i < v.size (); i++) - { - - this.listModel.addElement (v.get (i)); - - } - - b = new Box (BoxLayout.X_AXIS); - - final JList verbs = new JList (this.listModel); - - verbs.setVisibleRowCount (5); - verbs.setMaximumSize (verbs.getPreferredSize ()); - - b.add (new JScrollPane (verbs)); - - b.add (Box.createHorizontalStrut (5)); - - Box bb = new Box (BoxLayout.Y_AXIS); - - List buts = new ArrayList (); - - buts.add (UIUtils.createButton (Constants.DELETE_ICON_NAME, - Constants.ICON_MENU, - Environment.getUIString (LanguageStrings.problemfinder, - LanguageStrings.config, - LanguageStrings.rules, - LanguageStrings.adverb, - LanguageStrings.buttons, - LanguageStrings.removespeechverbs, - LanguageStrings.tooltip), - //"Click to remove the selected Speech Verbs", - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - // Get the selected items, remove them from the model. - int[] inds = verbs.getSelectedIndices (); - - if (inds != null) - { - - for (int i = inds.length - 1; i > -1; i--) - { - - _this.listModel.remove (inds[i]); - - } - - } - - } - - })); - -/* - - ImagePanel del = new ImagePanel (Environment.getIcon ("delete", - Constants.ICON_MENU), - null); - del.setBorder (null); - del.setOpaque (false); - del.setToolTipText ("Click to remove the selected Speech Verbs"); - com.quollwriter.ui.UIUtils.setAsButton (del); - del.setAlignmentY (Component.TOP_ALIGNMENT); - - del.addMouseListener (new MouseAdapter () - { - - public void mouseReleased (MouseEvent ev) - { - - // Get the selected items, remove them from the model. - int[] inds = verbs.getSelectedIndices (); - - if (inds != null) - { - - for (int i = inds.length - 1; i > -1; i--) - { - - _this.listModel.remove (inds[i]); - - } - - } - - } - - }); -*/ - bb.add (UIUtils.createButtonBar (buts)); - bb.add (Box.createVerticalGlue ()); - - b.add (bb); - b.add (Box.createHorizontalGlue ()); - - items.add (new AnyFormItem (Environment.getUIString (pref, - LanguageStrings.speechverbs), - //"Speech Verbs", - b)); - - return items; - - } - - @Override - public String getFormError () - { - - return null; - - } - - public void updateFromForm () - { - - // Reset the speech verbs. - Set verbs = new HashSet (); - - String n = this.newVerbs.getText (); - - if (n != null) - { - - StringTokenizer t = new StringTokenizer (n, - ";,"); - - while (t.hasMoreTokens ()) - { - - verbs.add (t.nextToken ().trim ().toLowerCase ()); - - } - - } - - Enumeration en = this.listModel.elements (); - - while (en.hasMoreElements ()) - { - - verbs.add ((String) en.nextElement ()); - - } - - this.speechVerbs = verbs; - - } - -} diff --git a/src/com/quollwriter/text/rules/ParagraphLengthRule.java b/src/com/quollwriter/text/rules/ParagraphLengthRule.java deleted file mode 100644 index ca4a8969..00000000 --- a/src/com/quollwriter/text/rules/ParagraphLengthRule.java +++ /dev/null @@ -1,276 +0,0 @@ -package com.quollwriter.text.rules; - -import java.util.*; - -import javax.swing.*; -import javax.swing.event.*; -import javax.swing.text.*; - -import com.gentlyweb.utils.*; - -import com.gentlyweb.xml.*; - -import com.quollwriter.*; -import com.quollwriter.text.*; - -import com.quollwriter.ui.forms.*; - -import org.jdom.Element; -import org.jdom.JDOMException; - -public class ParagraphLengthRule extends AbstractParagraphRule -{ - - public class XMLConstants - { - - public static final String wordCount = "wordCount"; - public static final String sentenceCount = "sentenceCount"; - - } - - private int sentenceCount = 0; - private int wordCount = 0; - private JSpinner sentCountF = null; - private JSpinner wordCountF = null; - - public ParagraphLengthRule () - { - - } - - public ParagraphLengthRule (int sentenceCount, - int wordCount, - boolean user) - { - - this.sentenceCount = sentenceCount; - this.wordCount = wordCount; - this.setUserRule (user); - - } - - public int getSentenceCount () - { - - return this.sentenceCount; - - } - - public void setSentenceCount (int c) - { - - this.sentenceCount = c; - - } - - public int getWordCount () - { - - return this.wordCount; - - } - - public void setWordCount (int c) - { - - this.wordCount = c; - - } - - @Override - public String getDescription () - { - - String d = super.getDescription (); - - d = StringUtils.replaceString (d, - "[SENTENCE_COUNT]", - this.sentenceCount + ""); - - d = StringUtils.replaceString (d, - "[WORD_COUNT]", - this.wordCount + ""); - - return d; - - } - - @Override - public String getSummary () - { - - String t = StringUtils.replaceString (super.getSummary (), - "[SENTENCE_COUNT]", - this.sentenceCount + ""); - - t = StringUtils.replaceString (t, - "[WORD_COUNT]", - this.wordCount + ""); - - return t; - - } - - @Override - public void init (Element root) - throws JDOMException - { - - super.init (root); - - this.sentenceCount = JDOMUtils.getAttributeValueAsInt (root, - XMLConstants.sentenceCount); - this.wordCount = JDOMUtils.getAttributeValueAsInt (root, - XMLConstants.wordCount); - - } - - @Override - public Element getAsElement () - { - - Element root = super.getAsElement (); - - root.setAttribute (XMLConstants.sentenceCount, - this.sentenceCount + ""); - root.setAttribute (XMLConstants.wordCount, - this.wordCount + ""); - - return root; - - } - - @Override - public List getIssues (Paragraph paragraph) - { - - List pref = new ArrayList (); - pref.add (LanguageStrings.problemfinder); - pref.add (LanguageStrings.issues); - pref.add (LanguageStrings.paragraphlength); - - List issues = new ArrayList (); - - int wc = paragraph.getWordCount (); - - if ((this.wordCount > 0) - && - (wc > this.wordCount) - ) - { - - Issue iss = new Issue (String.format (Environment.getUIString (pref, - LanguageStrings.wordtext), - Environment.formatNumber (wc), - Environment.formatNumber (this.wordCount)), - //"Paragraph word count is: " + Environment.formatNumber (wc) + ". (Max is: " + Environment.formatNumber (this.wordCount) + ")", - paragraph, - paragraph.getAllTextStartOffset () + "-wordcount-" + wc, - this); - - issues.add (iss); - - } - - int sc = paragraph.getSentenceCount (); - - if ((this.sentenceCount > 0) - && - (sc > this.sentenceCount) - ) - { - - Issue iss = new Issue (String.format (Environment.getUIString (pref, - LanguageStrings.sentencetext), - Environment.formatNumber (sc), - Environment.formatNumber (this.sentenceCount)), - //"Paragraph sentence count is: " + Environment.formatNumber (sc) + ". (Max is: " + Environment.formatNumber (this.sentenceCount) + ")", - paragraph, - paragraph.getAllTextStartOffset () + "-sentencecount-" + sc, - this); - - issues.add (iss); - - } - - return issues; - - } - - @Override - public String getCategory () - { - - return Rule.PARAGRAPH_CATEGORY; - - } - - @Override - public String getFormError () - { - - return null; - - } - - @Override - public Set getFormItems () - { - - List pref = new ArrayList (); - pref.add (LanguageStrings.problemfinder); - pref.add (LanguageStrings.config); - pref.add (LanguageStrings.rules); - pref.add (LanguageStrings.paragraphlength); - pref.add (LanguageStrings.labels); - - Set items = new LinkedHashSet (); - - this.wordCountF = new JSpinner (new SpinnerNumberModel (this.wordCount, - 1, - 500, - 1)); - - Box b = new Box (BoxLayout.X_AXIS); - b.add (this.wordCountF); - b.add (Box.createHorizontalGlue ()); - - this.wordCountF.setMaximumSize (this.wordCountF.getPreferredSize ()); - - items.add (new AnyFormItem (Environment.getUIString (pref, - LanguageStrings.words), - //"Words", - b)); - - this.sentCountF = new JSpinner (new SpinnerNumberModel (this.sentenceCount, - 1, - 500, - 1)); - - b = new Box (BoxLayout.X_AXIS); - - b.add (this.sentCountF); - b.add (Box.createHorizontalGlue ()); - - this.sentCountF.setMaximumSize (this.sentCountF.getPreferredSize ()); - - items.add (new AnyFormItem (Environment.getUIString (pref, - LanguageStrings.sentences), - //"Sentences", - b)); - - return items; - - } - - @Override - public void updateFromForm () - { - - this.sentenceCount = ((SpinnerNumberModel) this.sentCountF.getModel ()).getNumber ().intValue (); - this.wordCount = ((SpinnerNumberModel) this.wordCountF.getModel ()).getNumber ().intValue (); - - } - -} diff --git a/src/com/quollwriter/text/rules/ParagraphReadabilityRule.java b/src/com/quollwriter/text/rules/ParagraphReadabilityRule.java deleted file mode 100644 index 70cf772e..00000000 --- a/src/com/quollwriter/text/rules/ParagraphReadabilityRule.java +++ /dev/null @@ -1,309 +0,0 @@ -package com.quollwriter.text.rules; - -import java.util.*; - -import javax.swing.*; -import javax.swing.event.*; -import javax.swing.text.*; - -import com.gentlyweb.utils.*; - -import com.gentlyweb.xml.*; - -import com.quollwriter.*; -import com.quollwriter.data.*; -import com.quollwriter.text.*; - -import com.quollwriter.ui.forms.*; - -import org.jdom.Element; -import org.jdom.JDOMException; - -public class ParagraphReadabilityRule extends AbstractParagraphRule -{ - - public class XMLConstants - { - - public static final String fleschKincaid = "fleschKincaid"; - public static final String fleschReading = "fleschReading"; - public static final String gunningFog = "gunningFog"; - - } - - private int fleschKincaid = 0; - private int fleschReading = 0; - private int gunningFog = 0; - private JSpinner gfF = null; - private JSpinner fkF = null; - private JSpinner frF = null; - - public ParagraphReadabilityRule () - { - - } - - public ParagraphReadabilityRule (int fleschKincaid, - int fleschReading, - int gunningFog, - boolean user) - { - - this.fleschKincaid = fleschKincaid; - this.fleschReading = fleschReading; - this.gunningFog = gunningFog; - this.setUserRule (user); - - } - - @Override - public String getDescription () - { - - String d = super.getDescription (); - - d = StringUtils.replaceString (d, - "[FLESCH_KINCAID]", - this.fleschKincaid + ""); - - d = StringUtils.replaceString (d, - "[FLESCH_READING]", - this.fleschReading + ""); - - d = StringUtils.replaceString (d, - "[GUNNING_FOG]", - this.gunningFog + ""); - - return d; - - } - - @Override - public String getSummary () - { - - String t = StringUtils.replaceString (super.getSummary (), - "[FLESCH_KINCAID]", - this.fleschKincaid + ""); - - t = StringUtils.replaceString (t, - "[FLESCH_READING]", - this.fleschReading + ""); - - t = StringUtils.replaceString (t, - "[GUNNING_FOG]", - this.gunningFog + ""); - - return t; - - } - - @Override - public void init (Element root) - throws JDOMException - { - - super.init (root); - - this.fleschKincaid = JDOMUtils.getAttributeValueAsInt (root, - XMLConstants.fleschKincaid); - this.fleschReading = JDOMUtils.getAttributeValueAsInt (root, - XMLConstants.fleschReading); - this.gunningFog = JDOMUtils.getAttributeValueAsInt (root, - XMLConstants.gunningFog); - - } - - @Override - public Element getAsElement () - { - - Element root = super.getAsElement (); - - root.setAttribute (XMLConstants.fleschKincaid, - this.fleschKincaid + ""); - root.setAttribute (XMLConstants.fleschReading, - this.fleschReading + ""); - root.setAttribute (XMLConstants.gunningFog, - this.gunningFog + ""); - - return root; - - } - - @Override - public List getIssues (Paragraph paragraph) - { - - List issues = new ArrayList (); - - //int wc = TextUtilities.getWordCount (paragraph); - - if (paragraph.getWordCount () > 100) - { - - List pref = new ArrayList (); - pref.add (LanguageStrings.problemfinder); - pref.add (LanguageStrings.issues); - pref.add (LanguageStrings.paragraphreadability); - - ReadabilityIndices ri = new ReadabilityIndices (); - ri.add (paragraph.getText ()); - - if ((this.fleschKincaid > 0) - && - (ri.getFleschKincaidGradeLevel () > this.fleschKincaid) - ) - { - - Issue iss = new Issue (String.format (Environment.getUIString (pref, - LanguageStrings.fkfull), - Environment.formatNumber (ri.getFleschKincaidGradeLevel ()), - Environment.formatNumber (this.fleschKincaid)), - //"Paragraph has a Flesch Kincaid grade level of: " + Environment.formatNumber (ri.getFleschKincaidGradeLevel ()) + ". (Max is: " + Environment.formatNumber (this.fleschKincaid) + ")", - paragraph, - paragraph.getAllTextStartOffset () + "-fkgl-" + ri.getFleschKincaidGradeLevel (), - this); - - issues.add (iss); - - } - - if ((this.fleschReading > 0) - && - (ri.getFleschReadingEase () > this.fleschReading) - ) - { - - Issue iss = new Issue (String.format (Environment.getUIString (pref, - LanguageStrings.frfull), - Environment.formatNumber (ri.getFleschReadingEase ()), - Environment.formatNumber (this.fleschReading)), - //"Paragraph has a Flesch Reading ease level of: " + Environment.formatNumber (ri.getFleschReadingEase ()) + ". (Max is: " + Environment.formatNumber (this.fleschReading) + ")", - paragraph, - paragraph.getAllTextStartOffset () + "-fre-" + ri.getFleschReadingEase (), - this); - - issues.add (iss); - - } - - if ((this.gunningFog > 0) - && - (ri.getGunningFogIndex () > this.gunningFog) - ) - { - - Issue iss = new Issue (String.format (Environment.getUIString (pref, - LanguageStrings.gffull), - Environment.formatNumber (ri.getGunningFogIndex ()), - Environment.formatNumber (this.gunningFog)), - //"Paragraph has a Gunning Fog index of: " + Environment.formatNumber (ri.getGunningFogIndex ()) + ". (Max is: " + Environment.formatNumber (this.gunningFog) + ")", - paragraph, - paragraph.getAllTextStartOffset () + "-gfi-" + ri.getGunningFogIndex (), - this); - - issues.add (iss); - - } - - } - - return issues; - - } - - @Override - public String getCategory () - { - - return Rule.PARAGRAPH_CATEGORY; - - } - - @Override - public Set getFormItems () - { - - List pref = new ArrayList (); - pref.add (LanguageStrings.problemfinder); - pref.add (LanguageStrings.config); - pref.add (LanguageStrings.rules); - pref.add (LanguageStrings.paragraphreadability); - pref.add (LanguageStrings.labels); - - Set items = new LinkedHashSet (); - - this.fkF = new JSpinner (new SpinnerNumberModel (this.fleschKincaid, - 0, - 30, - 1)); - - Box b = new Box (BoxLayout.X_AXIS); - b.add (this.fkF); - b.add (Box.createHorizontalGlue ()); - - this.fkF.setMaximumSize (this.fkF.getPreferredSize ()); - - items.add (new AnyFormItem (Environment.getUIString (pref, - LanguageStrings.fk), - //"Flesch Kincaid Grade level", - b)); - - this.frF = new JSpinner (new SpinnerNumberModel (this.fleschReading, - 0, - 30, - 1)); - - b = new Box (BoxLayout.X_AXIS); - - b.add (this.frF); - b.add (Box.createHorizontalGlue ()); - - this.frF.setMaximumSize (this.frF.getPreferredSize ()); - - items.add (new AnyFormItem (Environment.getUIString (pref, - LanguageStrings.fr), - //"Flesch Reading ease level", - b)); - - this.gfF = new JSpinner (new SpinnerNumberModel (this.gunningFog, - 0, - 30, - 1)); - - b = new Box (BoxLayout.X_AXIS); - - b.add (this.gfF); - b.add (Box.createHorizontalGlue ()); - - this.gfF.setMaximumSize (this.gfF.getPreferredSize ()); - - items.add (new AnyFormItem (Environment.getUIString (pref, - LanguageStrings.gf), - //"Gunning Fog index", - b)); - - return items; - - } - - @Override - public String getFormError () - { - - return null; - - } - - @Override - public void updateFromForm () - { - - this.fleschKincaid = ((SpinnerNumberModel) this.fkF.getModel ()).getNumber ().intValue (); - this.fleschReading = ((SpinnerNumberModel) this.frF.getModel ()).getNumber ().intValue (); - this.gunningFog = ((SpinnerNumberModel) this.gfF.getModel ()).getNumber ().intValue (); - - } - -} diff --git a/src/com/quollwriter/text/rules/SentenceComplexityRule.java b/src/com/quollwriter/text/rules/SentenceComplexityRule.java deleted file mode 100644 index ef9ac958..00000000 --- a/src/com/quollwriter/text/rules/SentenceComplexityRule.java +++ /dev/null @@ -1,238 +0,0 @@ -package com.quollwriter.text.rules; - -import java.util.*; - -import javax.swing.*; -import javax.swing.event.*; -import javax.swing.text.*; - -import java.text.*; - -import com.gentlyweb.utils.*; - -import com.gentlyweb.xml.*; - -import com.quollwriter.*; -import com.quollwriter.text.*; - -import com.quollwriter.ui.forms.*; - -import org.jdom.Element; -import org.jdom.JDOMException; - - -public class SentenceComplexityRule extends AbstractSentenceRule -{ - - public class XMLConstants - { - - public static final String ratio = "ratio"; - public static final String wordCount = "wordCount"; - - } - - private float ratio = 0; - private int wordCount = 0; - private JSpinner ratioF = null; - private JSpinner wordCountF = null; - - public SentenceComplexityRule () - { - - } - - public SentenceComplexityRule (float syllableWordRatio, - int wordCount, - boolean user) - { - - this.ratio = syllableWordRatio; - this.wordCount = wordCount; - this.setUserRule (user); - - } - - @Override - public String getDescription () - { - - String d = super.getDescription (); - - d = StringUtils.replaceString (d, - "[RATIO]", - Environment.formatNumber (this.ratio) + ""); - - d = StringUtils.replaceString (d, - "[COUNT]", - this.wordCount + ""); - - return d; - - } - - @Override - public String getSummary () - { - - String t = StringUtils.replaceString (super.getSummary (), - "[RATIO]", - Environment.formatNumber (this.ratio) + ""); - - t = StringUtils.replaceString (t, - "[COUNT]", - this.wordCount + ""); - - return t; - - } - - @Override - public void init (Element root) - throws JDOMException - { - - super.init (root); - - this.ratio = JDOMUtils.getAttributeValueAsFloat (root, - XMLConstants.ratio); - this.wordCount = JDOMUtils.getAttributeValueAsInt (root, - XMLConstants.wordCount); - - } - - @Override - public Element getAsElement () - { - - Element root = super.getAsElement (); - - root.setAttribute (XMLConstants.ratio, - this.ratio + ""); - root.setAttribute (XMLConstants.wordCount, - this.wordCount + ""); - - return root; - - } - - @Override - public List getIssues (Sentence sentence) - { - - List issues = new ArrayList (); - - float wordC = (float) sentence.getWordCount (); - - if (wordC <= this.wordCount) - { - - return issues; - - } - - float syllC = (float) sentence.getSyllableCount (); - - float r = syllC / wordC; - - r = (float) Math.round (r * 10) / 10; - - if (r > this.ratio) - { - - DecimalFormat df = new DecimalFormat ("##.#"); - - String n = df.format (r); - - Issue iss = new Issue (String.format (Environment.getUIString (LanguageStrings.problemfinder, - LanguageStrings.issues, - LanguageStrings.sentencecomplexity, - LanguageStrings.text), - //"Sentence syllable/word ratio is: %s. (Max is: %s)", - n, - Environment.formatNumber (this.ratio)), - sentence, - sentence.getAllTextStartOffset () + "-sentencetoocomplex-" + r, - this); - - issues.add (iss); - - } - - return issues; - - } - - @Override - public String getCategory () - { - - return Rule.SENTENCE_CATEGORY; - - } - - @Override - public Set getFormItems () - { - - List pref = new ArrayList (); - pref.add (LanguageStrings.problemfinder); - pref.add (LanguageStrings.config); - pref.add (LanguageStrings.rules); - pref.add (LanguageStrings.sentencecomplexity); - pref.add (LanguageStrings.labels); - - Set items = new LinkedHashSet (); - - this.ratioF = new JSpinner (new SpinnerNumberModel (this.ratio, - 0.1f, - 3.0f, - 0.1)); - - Box b = new Box (BoxLayout.X_AXIS); - b.add (this.ratioF); - b.add (Box.createHorizontalGlue ()); - - this.ratioF.setMaximumSize (this.ratioF.getPreferredSize ()); - - items.add (new AnyFormItem (Environment.getUIString (pref, - LanguageStrings.ratio), - b)); - - this.wordCountF = new JSpinner (new SpinnerNumberModel (this.wordCount, - 1, - 500, - 1)); - - b = new Box (BoxLayout.X_AXIS); - - b.add (this.wordCountF); - b.add (Box.createHorizontalGlue ()); - - this.wordCountF.setMaximumSize (this.wordCountF.getPreferredSize ()); - - items.add (new AnyFormItem (Environment.getUIString (pref, - LanguageStrings.sentencelength), - //"Sentence length (words)", - b)); - - return items; - - } - - public String getFormError () - { - - return null; - - } - - public void updateFromForm () - { - - this.ratio = ((SpinnerNumberModel) this.ratioF.getModel ()).getNumber ().floatValue (); - this.wordCount = ((SpinnerNumberModel) this.wordCountF.getModel ()).getNumber ().intValue (); - - } - -} diff --git a/src/com/quollwriter/text/rules/SentenceLengthRule.java b/src/com/quollwriter/text/rules/SentenceLengthRule.java deleted file mode 100644 index c7a2ba1b..00000000 --- a/src/com/quollwriter/text/rules/SentenceLengthRule.java +++ /dev/null @@ -1,185 +0,0 @@ -package com.quollwriter.text.rules; - -import java.util.*; - -import javax.swing.*; -import javax.swing.event.*; -import javax.swing.text.*; - -import com.gentlyweb.utils.*; - -import com.gentlyweb.xml.*; - -import com.quollwriter.*; -import com.quollwriter.text.*; - -import com.quollwriter.ui.forms.*; - -import org.jdom.Element; -import org.jdom.JDOMException; - - -public class SentenceLengthRule extends AbstractSentenceRule -{ - - public class XMLConstants - { - - public static final String wordCount = "wordCount"; - - } - - private int wordCount = 0; - private JSpinner count = null; - - public SentenceLengthRule () - { - - } - - public SentenceLengthRule (int wordCount, - boolean user) - { - - this.wordCount = wordCount; - this.setUserRule (user); - - } - - @Override - public String getDescription () - { - - String d = super.getDescription (); - - return StringUtils.replaceString (d, - "[LIMIT]", - this.wordCount + ""); - - } - - @Override - public String getSummary () - { - - return StringUtils.replaceString (super.getSummary (), - "[LIMIT]", - this.wordCount + ""); - - } - - @Override - public void init (Element root) - throws JDOMException - { - - super.init (root); - - this.wordCount = JDOMUtils.getAttributeValueAsInt (root, - XMLConstants.wordCount); - - } - - @Override - public Element getAsElement () - { - - Element root = super.getAsElement (); - - root.setAttribute (XMLConstants.wordCount, - this.wordCount + ""); - - return root; - - } - - @Override - public List getIssues (Sentence sentence) - { - - // Check each word to make sure it's not punctuation. - List issues = new ArrayList (); - - int wc = sentence.getWordCount (); - - if (wc > this.wordCount) - { - - Issue iss = new Issue (String.format (Environment.getUIString (LanguageStrings.problemfinder, - LanguageStrings.issues, - LanguageStrings.sentencelength, - LanguageStrings.text), - Environment.formatNumber (wc), - Environment.formatNumber (this.wordCount)), - //"Sentence contains: " + wc + " words.", - sentence, - sentence.getAllTextStartOffset (), - sentence.getLastWord ().getAllTextEndOffset () - sentence.getAllTextStartOffset (), - sentence.getAllTextStartOffset () + "-toomanywords-" + wc, - this); - - issues.add (iss); - - } - - return issues; - - } - - @Override - public String getCategory () - { - - return Rule.SENTENCE_CATEGORY; - - } - - @Override - public Set getFormItems () - { - - List pref = new ArrayList (); - pref.add (LanguageStrings.problemfinder); - pref.add (LanguageStrings.config); - pref.add (LanguageStrings.rules); - pref.add (LanguageStrings.sentencelength); - pref.add (LanguageStrings.labels); - - Set items = new LinkedHashSet (); - - this.count = new JSpinner (new SpinnerNumberModel (this.wordCount, - 1, - 200, - 1)); - - Box b = new Box (BoxLayout.X_AXIS); - b.add (this.count); - b.add (Box.createHorizontalGlue ()); - - this.count.setMaximumSize (this.count.getPreferredSize ()); - - items.add (new AnyFormItem (Environment.getUIString (pref, - LanguageStrings.words), - //"No of Words", - b)); - - return items; - - } - - @Override - public String getFormError () - { - - return null; - - } - - public void updateFromForm () - { - - this.wordCount = ((SpinnerNumberModel) this.count.getModel ()).getNumber ().intValue (); - - } - -} diff --git a/src/com/quollwriter/text/rules/TooManyClausesRule.java b/src/com/quollwriter/text/rules/TooManyClausesRule.java deleted file mode 100644 index fdbbaa15..00000000 --- a/src/com/quollwriter/text/rules/TooManyClausesRule.java +++ /dev/null @@ -1,207 +0,0 @@ -package com.quollwriter.text.rules; - -import java.util.*; -import java.awt.event.*; - -import javax.swing.*; - -import com.gentlyweb.utils.*; - -import com.gentlyweb.xml.*; - -import com.quollwriter.*; -import com.quollwriter.text.*; - -import com.quollwriter.ui.forms.*; - -import org.jdom.*; - -public class TooManyClausesRule extends AbstractSentenceRule -{ - - public class XMLConstants - { - - public static final String clauseCount = "clauseCount"; - - } - - private int clauseCount = 0; - private JSpinner count = null; - private Map separators = new HashMap (); - - public TooManyClausesRule () - { - - this.separators.put (",", - ","); - this.separators.put ("-", - "-"); - - } - - public TooManyClausesRule (int clauseCount, - boolean user) - { - - this (); - - this.clauseCount = clauseCount; - this.setUserRule (user); - - } - - public String getDescription () - { - - String d = super.getDescription (); - - return StringUtils.replaceString (d, - "[LIMIT]", - this.clauseCount + ""); - - } - - @Override - public String getSummary () - { - - return StringUtils.replaceString (super.getSummary (), - "[LIMIT]", - this.clauseCount + ""); - - } - - @Override - public void init (Element root) - throws JDOMException - { - - super.init (root); - - this.clauseCount = JDOMUtils.getAttributeValueAsInt (root, - XMLConstants.clauseCount); - - } - - @Override - public Element getAsElement () - { - - Element root = super.getAsElement (); - - root.setAttribute (XMLConstants.clauseCount, - this.clauseCount + ""); - - return root; - - } - - @Override - public List getIssues (Sentence sentence) - { - - int c = 1; - int i = 0; - - for (Word w : sentence.getWords ()) - { - - if (this.separators.containsKey (w.getText ())) - { - - if (i > 0) - { - - c++; - - } - - } - - i++; - - } - - // Look for , ; or -. - List issues = new ArrayList (); - - if (c > this.clauseCount) - { - - Issue iss = new Issue (String.format (Environment.getUIString (LanguageStrings.problemfinder, - LanguageStrings.issues, - LanguageStrings.toomanyclauses, - LanguageStrings.text), - Environment.formatNumber (c), - Environment.formatNumber (this.clauseCount)), - //"Sentence contains: " + c + " clauses.", - sentence, - sentence.getAllTextStartOffset () + "-toomanyclauses-" + c, - this); - - issues.add (iss); - - } - - return issues; - - } - - @Override - public Set getFormItems () - { - - List pref = new ArrayList (); - pref.add (LanguageStrings.problemfinder); - pref.add (LanguageStrings.config); - pref.add (LanguageStrings.rules); - pref.add (LanguageStrings.toomanyclauses); - pref.add (LanguageStrings.labels); - - Set items = new LinkedHashSet (); - - this.count = new JSpinner (new SpinnerNumberModel (this.clauseCount, - 1, - 200, - 1)); - - Box b = new Box (BoxLayout.X_AXIS); - b.add (this.count); - b.add (Box.createHorizontalGlue ()); - - this.count.setMaximumSize (this.count.getPreferredSize ()); - - items.add (new AnyFormItem (Environment.getUIString (pref, - LanguageStrings.clauses), - //"No of Clauses", - b)); - - return items; - - } - - @Override - public String getFormError () - { - - return null; - - } - - @Override - public void updateFromForm () - { - - this.clauseCount = ((SpinnerNumberModel) this.count.getModel ()).getNumber ().intValue (); - - } - - public String getCategory () - { - - return Rule.SENTENCE_CATEGORY; - - } - -} diff --git a/src/com/quollwriter/text/rules/WordFinder.java b/src/com/quollwriter/text/rules/WordFinder.java deleted file mode 100644 index 06f71deb..00000000 --- a/src/com/quollwriter/text/rules/WordFinder.java +++ /dev/null @@ -1,483 +0,0 @@ -package com.quollwriter.text.rules; - -import java.util.*; -import java.awt.event.*; - -import javax.swing.*; - -import com.gentlyweb.utils.*; - -import com.gentlyweb.xml.*; - -import com.quollwriter.*; -import com.quollwriter.text.*; -import com.quollwriter.ui.forms.*; - -import org.jdom.*; - -public class WordFinder extends AbstractDialogueRule -{ - - public class XMLConstants - { - - public static final String word = "word"; - - } - - private String word = null; - - private TextFormItem words = null; - private List tWords = null; - private CheckboxFormItem ignoreInDialogueCB = null; - private CheckboxFormItem onlyInDialogueCB = null; - private ComboBoxFormItem whereCB = null; - - public WordFinder () - { - - } - - public boolean isForLanguage (String language) - { - - return Environment.isEnglish (language); - - } - - public String toString () - { - - return "rule(word=" + this.word + ")"; - - } - - public String getCategory () - { - - return Rule.WORD_CATEGORY; - - } - - public void setWord (String w) - { - - this.word = w; - - this.tWords = TextUtilities.getAsWords (this.word.toLowerCase ()); - - } - - @Override - public String getSummary () - { - - if (this.word == null) - { - - return null; - - } - - return String.format ("\"%s\" %s", - this.word, - this.getWhereDesc ()); - - } - - @Override - public String getEditFormTitle (boolean add) - { - - return (add ? Environment.getUIString (LanguageStrings.problemfinder, - LanguageStrings.config, - LanguageStrings.rules, - LanguageStrings.wordfinder, - LanguageStrings.addtitle) - : Environment.getUIString (LanguageStrings.problemfinder, - LanguageStrings.config, - LanguageStrings.rules, - LanguageStrings.wordfinder, - LanguageStrings.edittitle)); - - } - - private String getWhereDesc () - { - - String suffix = ""; - - if (this.where != null) - { - - List pref = new ArrayList (); - pref.add (LanguageStrings.problemfinder); - pref.add (LanguageStrings.config); - pref.add (LanguageStrings.rules); - pref.add (LanguageStrings.wordfinder); - pref.add (LanguageStrings.description); - - String s = (this.ignoreInDialogue ? Environment.getUIString (pref, - LanguageStrings.suffixes, - LanguageStrings.ignoreindialogue) : - Environment.getUIString (pref, - LanguageStrings.suffixes, - LanguageStrings.onlyindialogue)); - - if (this.where.equals (DialogueConstraints.ANYWHERE)) - { - - suffix = String.format (Environment.getUIString (pref, - LanguageStrings.anywhere), - s); - //"anywhere in a sentence"; - - } else - { - - suffix = String.format (Environment.getUIString (pref, - LanguageStrings.insentence), - //"at the %s of a sentence", - this.where, - s); - - } -/* - if (this.ignoreInDialogue) - { - - suffix += ", ignore in dialogue"; - - } - - if (this.onlyInDialogue) - { - - suffix += ", but only in dialogue"; - - } -*/ - } - - return suffix; - - } - - @Override - public void init (Element root) - throws JDOMException - { - - super.init (root); - - this.setWord (JDOMUtils.getAttributeValue (root, - XMLConstants.word)); - - } - - public String getWord () - { - - return this.word; - - } - - @Override - public Element getAsElement () - { - - Element root = super.getAsElement (); - - root.setAttribute (XMLConstants.word, - this.word); - - return root; - - } - - @Override - public List getIssues (Sentence sentence) - { - - // Check our list of words. - - List issues = new ArrayList (); - - Set inds = sentence.find (this.tWords, - this.getConstraints ()); - - if ((inds != null) - && - (inds.size () > 0) - ) - { - - for (Integer i : inds) - { - - Word w = sentence.getWord (i); - - int l = w.getText ().length (); - - if (this.tWords.size () > 1) - { - - Word nw = w.getWordsAhead (this.tWords.size () - 1); - - l = nw.getAllTextEndOffset () - w.getAllTextStartOffset (); - - } - - String suffix = ""; - - List pref = new ArrayList (); - - pref.add (LanguageStrings.problemfinder); - pref.add (LanguageStrings.issues); - pref.add (LanguageStrings.wordfinder); - - if (this.onlyInDialogue) - { - - suffix = Environment.getUIString (pref, - LanguageStrings.suffixes, - LanguageStrings.onlyindialogue); - //" (in dialogue)"; - - } - - if (!this.where.equals (DialogueConstraints.ANYWHERE)) - { - - if (this.onlyInDialogue) - { - - suffix = Environment.getUIString (pref, - LanguageStrings.suffixes, - LanguageStrings.indialogue); - - } else { - - suffix = Environment.getUIString (pref, - LanguageStrings.suffixes, - LanguageStrings.notindialogue); - - } - - suffix = String.format (suffix, - this.where); - - } - - Issue iss = new Issue (String.format (Environment.getUIString (pref, - LanguageStrings.text), - this.word, - suffix), - //"Contains: " + this.word + "" + suffix, - sentence, - w.getAllTextStartOffset (), - l, - w.getAllTextStartOffset () + "-" + this.word, - this); - issues.add (iss); - - } - - } - - return issues; - - } - - public void updateFromForm () - { - - this.setOnlyInDialogue (this.onlyInDialogueCB.isSelected ()); - this.setIgnoreInDialogue (this.ignoreInDialogueCB.isSelected ()); - - int ws = this.whereCB.getSelectedIndex (); - - if (ws == 0) - { - - this.setWhere (DialogueConstraints.ANYWHERE); - - } - - if (ws == 1) - { - - this.setWhere (DialogueConstraints.START); - - } - - if (ws == 2) - { - - this.setWhere (DialogueConstraints.END); - - } - - this.setWord (this.words.getText ().trim ()); - - } - - @Override - public String getDescription () - { - - String d = super.getDescription (); - - if (d == null) - { - - return null; - - } - - return StringUtils.replaceString (d, - "[WORD]", - ((this.word == null) ? "[WORD]" : this.word)); - - } - - @Override - public Set getFormItems () - { - - Set items = new LinkedHashSet (); - - List pref = new ArrayList (); - pref.add (LanguageStrings.problemfinder); - pref.add (LanguageStrings.config); - pref.add (LanguageStrings.rules); - pref.add (LanguageStrings.wordfinder); - pref.add (LanguageStrings.labels); - - this.words = new TextFormItem (Environment.getUIString (pref, - LanguageStrings.wordphrase), - //"Word/Phrase", - this.word); - - items.add (this.words); - - Vector whereVals = new Vector (); - whereVals.add (Environment.getUIString (pref, - LanguageStrings.anywhere)); - //"Anywhere"); - whereVals.add (Environment.getUIString (pref, - LanguageStrings.startofsentence)); - //"Start of sentence"); - whereVals.add (Environment.getUIString (pref, - LanguageStrings.endofsentence)); - //"End of sentence"); - - String selected = whereVals.get (0); - - String loc = this.getWhere (); - - if (loc.equals (DialogueConstraints.START)) - { - - selected = whereVals.get (1); - - } - - if (loc.equals (DialogueConstraints.END)) - { - - selected = whereVals.get (2); - - } - - this.whereCB = new ComboBoxFormItem (Environment.getUIString (pref, - LanguageStrings.where), - //"Where", - whereVals, - selected, - null); - - final WordFinder _this = this; - - items.add (this.whereCB); - - this.ignoreInDialogueCB = new CheckboxFormItem (null, - Environment.getUIString (pref, - LanguageStrings.ignoreindialogue)); - //"Ignore in dialogue"); - this.onlyInDialogueCB = new CheckboxFormItem (null, - Environment.getUIString (pref, - LanguageStrings.onlyindialogue)); - //"Only in dialogue"); - - this.ignoreInDialogueCB.addItemListener (new ItemListener () - { - - @Override - public void itemStateChanged (ItemEvent ev) - { - - if (_this.ignoreInDialogueCB.isSelected ()) - { - - _this.onlyInDialogueCB.setSelected (false); - - } - - } - - }); - - this.onlyInDialogueCB.addItemListener (new ItemListener () - { - - @Override - public void itemStateChanged (ItemEvent ev) - { - - if (_this.onlyInDialogueCB.isSelected ()) - { - - _this.ignoreInDialogueCB.setSelected (false); - - } - - } - - }); - - this.ignoreInDialogueCB.setSelected (this.isIgnoreInDialogue ()); - this.onlyInDialogueCB.setSelected (this.isOnlyInDialogue ()); - - items.add (this.ignoreInDialogueCB); - - items.add (this.onlyInDialogueCB); - - return items; - - } - - public String getFormError () - { - - String newWords = this.words.getText (); - - if ((newWords == null) - || - (newWords.trim ().length () == 0) - ) - { - - return Environment.getUIString (LanguageStrings.problemfinder, - LanguageStrings.config, - LanguageStrings.rules, - LanguageStrings.wordfinder, - LanguageStrings.nowordserror); - - } - - return null; - - } - -} diff --git a/src/com/quollwriter/tools/CreateObfuscatedString.java b/src/com/quollwriter/tools/CreateObfuscatedString.java deleted file mode 100644 index b4ad999d..00000000 --- a/src/com/quollwriter/tools/CreateObfuscatedString.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.quollwriter.tools; - -import de.schlichtherle.util.*; - - -public class CreateObfuscatedString -{ - - public static void main (String[] argv) - { - - try - { - - System.out.println (ObfuscatedString.obfuscate (argv[0])); - - } catch (Exception e) - { - - e.printStackTrace (); - - } - - } - -} diff --git a/src/com/quollwriter/tools/EncodeStrings.java b/src/com/quollwriter/tools/EncodeStrings.java deleted file mode 100644 index bb474a7d..00000000 --- a/src/com/quollwriter/tools/EncodeStrings.java +++ /dev/null @@ -1,275 +0,0 @@ -package com.quollwriter.tools; - -import java.io.*; - -import java.security.*; - -import java.util.*; -import java.util.zip.*; - -import javax.media.jai.*; -import javax.media.jai.operator.*; - -import com.gentlyweb.utils.*; - -import com.quollwriter.*; - -import com.sun.media.jai.codec.*; - - -public class EncodeStrings -{ - - public static void main (String[] argv) - { - - try - { - - StringBuilder outData = new StringBuilder (); - - File mappingFile = new File (System.getProperty ("user.dir") + "/" + argv[0]); - - BufferedReader in = new BufferedReader (new FileReader (mappingFile)); - - String line = null; - - while ((line = in.readLine ()) != null) - { - - String[] items = line.split (","); - - // 0 -> input file. - // 1 -> input image file. - // 2 -> output image file. - - File dataFile = new File (System.getProperty ("user.dir") + "/" + items[0]); - - if (outData.length () > 0) - { - - outData.append ("|"); - - } - - outData.append (dataFile.getName ().substring (0, - dataFile.getName ().length () - "-strings.txt".length ())); - outData.append (","); - - String file = IOUtils.getFile (dataFile); - - File inFile = new File (System.getProperty ("user.dir") + "/" + items[1]); - File outFile = new File (System.getProperty ("user.dir") + "/" + items[2]); - - outData.append ("/" + items[2]); - - EncodeStrings.writeToFile (file.getBytes (), - inFile, - outFile); - - System.out.println ("Written: " + items[0] + " to: " + outFile); - - } - - in.close (); - System.out.println ("OUTDATA: " + outData); - EncodeStrings.writeToFile (outData.toString ().getBytes (), - new File (System.getProperty ("user.dir") + "/" + argv[1]), - new File (System.getProperty ("user.dir") + "/" + argv[2])); - - System.out.println ("Mapping file written: " + argv[0] + " to: " + argv[2]); - - EncodeStrings.writeToFile (IOUtils.getFileAsArray (new File (System.getProperty ("user.dir") + "/quollwriter-publickeys.store")), - new File (System.getProperty ("user.dir") + "/imgs/logo.png"), - new File (System.getProperty ("user.dir") + "/imgs/logo2.png")); - - System.out.println ("Written: quollwriter-publickeys.store to: /imgs/logo2.png"); - - } catch (Exception e) - { - - e.printStackTrace (); - - } - - } - - private static void writeToFile (byte[] file, - File inFile, - File outFile) - throws Exception - { - - IOUtils.copyFile (inFile, - outFile, - 4096); - - String fileStr = com.quollwriter.Base64.encodeBytes (file); - - // Get the digest. - MessageDigest md = MessageDigest.getInstance ("SHA-256"); - - md.update (fileStr.getBytes ()); - - byte[] digest = md.digest (); - - // Get the input file. - PNGDecodeParam param = new PNGDecodeParam (); - param.setGenerateEncodeParam (true); - - RenderedOp inOp = PNGDescriptor.create (new FileSeekableStream (outFile), - param, - null); - - // Need to do this ourselves. - PNGEncodeParam.getDefaultEncodeParam (inOp); - - PNGEncodeParam eparam = param.getEncodeParam (); - - eparam.addPrivateChunk ("mkBR", - EncodeStrings.zipData (fileStr.getBytes ())); - eparam.addPrivateChunk ("mkBf", - digest); - - JAI.create ("filestore", - inOp, - outFile.getPath (), - "PNG", - eparam); - - } - - public static byte[] getPNGData (String resource) - throws Exception - { - - return EncodeStrings.getPNGData (Environment.getResourceStream (resource)); - - } - - public static byte[] getPNGData (File f) - throws Exception - { - - return EncodeStrings.getPNGData (new FileInputStream (f)); - - } - - public static byte[] getPNGData (InputStream in) - throws Exception - { - - PNGDecodeParam param = new PNGDecodeParam (); - param.setGenerateEncodeParam (true); - - RenderedOp op = PNGDescriptor.create (new ForwardSeekableStream (in), - param, - null); - - // Need to do this ourselves. - PNGEncodeParam.getDefaultEncodeParam (op); - - PNGEncodeParam eparam = param.getEncodeParam (); - - boolean has = false; - - byte[] digest = null; - byte[] ndigest = null; - - byte[] data = null; - - for (int i = 0; i < eparam.getNumPrivateChunks (); i++) - { - - String t = eparam.getPrivateChunkType (i); - - if (t.equals ("mkBf")) - { - - digest = eparam.getPrivateChunkData (i); - - } - - if (t.equals ("mkBR")) - { - - has = true; - - data = EncodeStrings.getChunkData (eparam.getPrivateChunkData (i)); - - MessageDigest md = MessageDigest.getInstance ("SHA-256"); - - md.update (data); - - ndigest = md.digest (); - - String str = new String (data); - - str = StringUtils.replaceString (str, - String.valueOf ('\n'), - ""); - str = StringUtils.replaceString (str, - String.valueOf ('\r'), - ""); - - data = com.quollwriter.Base64.decode (str); - - } - - } - - if ((data == null) || - (digest == null)) - { - - return null; - - } - - if (!MessageDigest.isEqual (digest, - ndigest)) - { - - return null; - - } - - return data; - - } - - private static byte[] zipData (byte[] data) - throws Exception - { - - ByteArrayOutputStream bout = new ByteArrayOutputStream (); - GZIPOutputStream gout = new GZIPOutputStream (bout); - - gout.write (data, - 0, - data.length); - - gout.flush (); - gout.close (); - - return bout.toByteArray (); - - } - - private static byte[] getChunkData (byte[] data) - throws Exception - { - - GZIPInputStream gin = new GZIPInputStream (new ByteArrayInputStream (data)); - - ByteArrayOutputStream bout = new ByteArrayOutputStream (); - - IOUtils.streamTo (gin, - bout, - 4096); - - return bout.toByteArray (); - - } - -} diff --git a/src/com/quollwriter/ui/AbstractProjectViewer.java b/src/com/quollwriter/ui/AbstractProjectViewer.java deleted file mode 100644 index ecea49cc..00000000 --- a/src/com/quollwriter/ui/AbstractProjectViewer.java +++ /dev/null @@ -1,7553 +0,0 @@ -package com.quollwriter.ui; - -import java.awt.*; -import java.awt.dnd.*; -import java.awt.event.*; - -import java.io.*; - -import java.net.*; - -import java.security.*; - -import java.text.*; - -import java.util.Arrays; -import java.util.ArrayList; -import java.util.Date; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.Set; -import java.util.StringTokenizer; -import java.util.HashSet; -import java.util.LinkedHashSet; -import java.util.WeakHashMap; -import java.util.Collections; -import java.util.Stack; -import java.util.TimerTask; -import java.util.concurrent.*; - -import org.w3c.dom.Element; -import org.w3c.dom.Node; - -import javax.sound.sampled.*; - -import javax.swing.*; -import javax.swing.border.*; -import javax.swing.event.*; -import javax.swing.tree.*; -import javax.swing.text.*; - -import com.gentlyweb.properties.*; - -import com.gentlyweb.utils.*; - -import com.jgoodies.forms.builder.*; -import com.jgoodies.forms.factories.*; -import com.jgoodies.forms.layout.*; - -import com.quollwriter.*; - -import com.quollwriter.data.*; - -import com.quollwriter.db.*; -import com.quollwriter.ui.sidebars.*; -import com.quollwriter.ui.panels.*; -import com.quollwriter.events.*; -import com.quollwriter.synonyms.*; -import com.quollwriter.text.*; -import com.quollwriter.text.rules.*; - -import com.quollwriter.ui.actionHandlers.*; -import com.quollwriter.ui.components.*; -import com.quollwriter.ui.events.*; -import com.quollwriter.ui.renderers.*; -import com.quollwriter.ui.charts.*; - -import com.quollwriter.data.editors.*; -import com.quollwriter.editors.*; -import com.quollwriter.editors.ui.*; -import com.quollwriter.editors.ui.sidebars.*; - -import com.quollwriter.achievements.rules.*; - -import static com.quollwriter.LanguageStrings.*; -import static com.quollwriter.Environment.getUIString; - -public abstract class AbstractProjectViewer extends AbstractViewer implements PropertyChangedListener, - SpellCheckSupported, - HTMLPanelActionHandler -{ - - public static final String IDEA_BOARD_HEADER_CONTROL_ID = "ideaBoard"; - public static final String FIND_HEADER_CONTROL_ID = "find"; - public static final String FULL_SCREEN_HEADER_CONTROL_ID = "fullScreen"; - public static final String CLOSE_HEADER_CONTROL_ID = "close"; - - public static final String TAB_OBJECT_TYPE = "tab"; - - public static int INTERNAL_SPLIT_PANE_DIVIDER_WIDTH = 2; - - // public static final int CLOSE_WARMUPS_ACTION = 12; //"closeWarmups"; - public static final int CREATE_PROJECT_SNAPSHOT_ACTION = 0; - public static final int NEW_PROJECT_ACTION = 1; - public static final int EDIT_CHAPTER_ACTION = 4; // "editChapter"; - public static final int DELETE_CHAPTER_ACTION = 5; - public static final int RENAME_CHAPTER_ACTION = 7; // "renameChapter"; - public static final int ABOUT_ACTION = 9; // "about"; - public static final int REPORT_BUG_ACTION = 10; // "reportBug"; - public static final int OPEN_PROJECT_ACTION = 11; // "openProject"; - public static final int CLOSE_PROJECT_ACTION = 12; // "closeProject"; - public static final int DELETE_PROJECT_ACTION = 13; // "deleteProject"; - public static final int RENAME_PROJECT_ACTION = 14; // "renameProject"; - public static final int EDIT_PROJECT_PROPERTIES_ACTION = 15; // "editProjectProperties"; - public static final int WARMUP_EXERCISE_ACTION = 26; - public static final int CONTACT_SUPPORT_ACTION = 28; - - public static final String NAME_CHANGED = "nameChanged"; - - protected Project proj = null; - private DnDTabbedPane tabs = null; - private ProjectDictionaryProvider projDict = null; - private String projectLanguage = null; - private SynonymProvider synProv = null; - private JSplitPane splitPane = null; - private JSplitPane splitPane2 = null; - protected ObjectManager dBMan = null; - //private Header title = null; - private Map toolbars = new HashMap (); - private Box toolbarPanel = null; - private Accordion acc = null; - private boolean spellCheckingEnabled = false; - private Date sessionStart = new Date (); - //private Box notifications = null; - private boolean playSoundOnKeyStroke = false; - private Clip keyStrokeSound = null; - //private QPopup achievementsPopup = null; - private ChapterCounts startWordCounts = new ChapterCounts (null); - private Map noEditorReadabilityIndices = new WeakHashMap (); - private Map chapterCounts = new WeakHashMap (); - //private Box itemsBox = null; - private Box sideBar = null; - private Box sideBarWrapper = null; - private Map sideBars = new HashMap (); - private Stack activeSideBars = new Stack (); - private AbstractSideBar currentOtherSideBar = null; - private AbstractSideBar mainSideBar = null; - private Finder finder = null; - private WordCountsSideBar wordCounts = null; - private Map panels = new HashMap (); - private int lastDividerLocation = -1; - private Map sideBarWidths = new HashMap (); - private java.util.List sideBarListeners = new ArrayList (); - private java.util.List mainPanelListeners = new ArrayList (); - private java.util.List fullScreenListeners = new ArrayList (); - //private Map popups = new HashMap (); - - private Timer achievementsHideTimer = null; - - private JTree chapterTree = null; - - private FullScreenFrame fsf = null; - private FullScreenOverlay fullScreenOverlay = null; - - private String toolbarLocation = Constants.BOTTOM; - - private String layout = Constants.LAYOUT_PS_CH; - - private Map tempOptions = new HashMap (); - - //private Set projectEventListeners = new HashSet (); - //private boolean ignoreProjectEvents = false; - - //private Tips tips = null; - - private DictionaryManager dictMan = null; - - private WordCountTimer wordCountTimer = null; - - private int savedOtherSideBarWidth = 0; - private int savedSideBarWidth = 0; - - private JPanel cards = null; - private CardLayout cardsLayout = null; - - private ScheduledFuture autoSaveTask = null; - private ScheduledFuture chapterCountsUpdater = null; - private TargetsData targets = null; - private Map chapterWordCountTargetWarned = new HashMap (); - - public AbstractProjectViewer() - { - - final AbstractProjectViewer _this = this; - - this.wordCountTimer = new WordCountTimer (this, - -1, - -1); - - this.setDefaultCloseOperation (WindowConstants.DO_NOTHING_ON_CLOSE); - - // Create a split pane. - this.splitPane = UIUtils.createSplitPane (JSplitPane.HORIZONTAL_SPLIT); - - this.splitPane.setBorder (null); - - javax.swing.plaf.basic.BasicSplitPaneDivider div = ((javax.swing.plaf.basic.BasicSplitPaneUI) this.splitPane.getUI ()).getDivider (); - div.setBorder (new MatteBorder (0, 0, 0, 1, Environment.getBorderColor ())); - this.splitPane.setOpaque (false); - this.splitPane.setBackground (UIUtils.getComponentColor ()); - - this.splitPane2 = UIUtils.createSplitPane (JSplitPane.HORIZONTAL_SPLIT); - this.splitPane2.setBorder (null); - - div = ((javax.swing.plaf.basic.BasicSplitPaneUI) this.splitPane2.getUI ()).getDivider (); - div.setBorder (new MatteBorder (0, 0, 0, 1, Environment.getBorderColor ())); - this.splitPane2.setOpaque (false); - this.splitPane2.setBackground (UIUtils.getComponentColor ()); - - InputMap im = this.getInputMap (JComponent.WHEN_IN_FOCUSED_WINDOW); - - im.put (KeyStroke.getKeyStroke (KeyEvent.VK_F12, - InputEvent.CTRL_MASK | InputEvent.ALT_MASK), - "debug"); - im.put (KeyStroke.getKeyStroke (KeyEvent.VK_F1, - InputEvent.CTRL_MASK | InputEvent.ALT_MASK), - "debug-mode"); - - im.put (KeyStroke.getKeyStroke (KeyEvent.VK_F11, - 0), - "whatsnew"); - - ActionMap am = this.getActionMap (); - - this.initKeyMappings (im); - - this.initActionMappings (am); - - this.tabs = this.createTabbedPane (); - - this.tabs.addChangeListener (new ChangeListener () - { - - public void stateChanged (ChangeEvent ev) - { - - if (_this.tabs.getTabCount () == 0) - { - - _this.tabs.setVisible (false); - - } else { - - _this.tabs.setVisible (true); - - } - } - - }); - - this.tabs.setMinimumSize (new Dimension (300, 200)); - this.tabs.putClientProperty(com.jgoodies.looks.Options.NO_CONTENT_BORDER_KEY, Boolean.TRUE); - //this.tabs.putClientProperty(com.jgoodies.looks.Options.EMBEDDED_TABS_KEY, Boolean.TRUE); - this.tabs.setBorder (null); - - this.setTabsLocation (null); - - this.splitPane2.setLeftComponent (this.tabs); - - this.splitPane.setRightComponent (this.splitPane2); - - this.sideBar = new Box (BoxLayout.PAGE_AXIS); - this.sideBar.setOpaque (false); - this.sideBar.setMaximumSize (new Dimension (Short.MAX_VALUE, - Short.MAX_VALUE)); - - this.toolbarPanel = new Box (BoxLayout.X_AXIS); - - this.toolbarPanel.setOpaque (false); - - this.toolbarPanel.setAlignmentX (Component.LEFT_ALIGNMENT); - - this.toolbarPanel.setMaximumSize (new Dimension (Short.MAX_VALUE, - 100)); - - this.sideBarWrapper = new Box (BoxLayout.X_AXIS); - this.sideBarWrapper.setOpaque (false); - this.sideBarWrapper.setAlignmentX (Component.LEFT_ALIGNMENT); - - this.sideBar.add (this.sideBarWrapper); - this.sideBar.add (this.toolbarPanel); - - this.splitPane.setLeftComponent (this.sideBar); - this.splitPane.setAlignmentX (Component.LEFT_ALIGNMENT); - - this.cardsLayout = new CardLayout (0, 0); - - this.cards = new JPanel (this.cardsLayout); - this.cards.setBackground (UIUtils.getComponentColor ()); - this.cards.setAlignmentX (Component.LEFT_ALIGNMENT); - - this.cards.add (this.splitPane, "main"); - - this.addTabChangeListener (new ChangeAdapter () - { - - public void stateChanged (ChangeEvent ev) - { - - QuollPanel qp = _this.getCurrentlyVisibleTab (); - - if (qp != null) - { - - _this.fireMainPanelShownEvent (qp); - - } - - } - - }); - - this.setContent (this.cards); - - } - - public void addCard (String name, - JComponent c) - { - - this.cards.add (c, - name); - - } - - public void showMainCard () - { - - this.showCard ("main"); - - } - - public void showCard (String name) - { - - this.cardsLayout.show (this.cards, - name); - - this.validate (); - this.repaint (); - - } - - @Override - public void initActionMappings (ActionMap am) - { - - final AbstractProjectViewer _this = this; - - super.initActionMappings (am); - - am.put ("close-current-tab", - new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - QuollPanel qp = _this.getCurrentlyVisibleTab (); - - if (qp != null) - { - - _this.closePanel (qp); - - } - - } - - }); - - am.put ("show-main-sidebar", - new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.closeSideBar (); - - } - - }); - - am.put ("new-project", - this.getAction (AbstractProjectViewer.NEW_PROJECT_ACTION, - null)); - - am.put ("open-project", - this.getAction (AbstractProjectViewer.OPEN_PROJECT_ACTION, - null)); - - am.put (Constants.SHOW_FIND_ACTION, - new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.showFind (null); - - } - - }); - - am.put ("fullscreen", - new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.enterFullScreen (); - - } - - }); - - } - - @Override - public void initKeyMappings (InputMap im) - { - - super.initKeyMappings (im); - - im.put (KeyStroke.getKeyStroke (KeyEvent.VK_F1, - 0), - Constants.SHOW_FIND_ACTION); - - im.put (KeyStroke.getKeyStroke (KeyEvent.VK_F4, - 0), - "close-current-tab"); - - im.put (KeyStroke.getKeyStroke (KeyEvent.VK_F5, - 0), - "fullscreen"); - - im.put (KeyStroke.getKeyStroke (KeyEvent.VK_ESCAPE, - 0), - "show-main-sidebar"); - - im.put (KeyStroke.getKeyStroke (KeyEvent.VK_F, - Event.CTRL_MASK), - Constants.SHOW_FIND_ACTION); - - im.put (KeyStroke.getKeyStroke (KeyEvent.VK_N, - Event.CTRL_MASK), - "new-project"); - im.put (KeyStroke.getKeyStroke (KeyEvent.VK_O, - Event.CTRL_MASK), - "open-project"); - - } - - public WordCountTimer getWordCountTimer () - { - - return this.wordCountTimer; - - } - - protected void initSideBars () - throws GeneralException - { - - this.finder = new Finder (this); - - this.addSideBar (this.finder); - - this.wordCounts = new WordCountsSideBar (this); - - this.addSideBar (this.wordCounts); - - this.mainSideBar = this.getMainSideBar (); - - this.addSideBar (this.mainSideBar); - - } - - public JComponent getSideBarForFullScreen () - { - - if (this.currentOtherSideBar != null) - { - - this.sideBarWrapper.removeAll (); - this.sideBarWrapper.add (this.currentOtherSideBar); - - } else { - - if (this.mainSideBar != null) - { - - this.sideBarWrapper.removeAll (); - this.sideBarWrapper.add (this.mainSideBar); - - } - - } - - return this.sideBar; - - } - - private void fireMainPanelShownEvent (QuollPanel p) - { - - MainPanelEvent ev = new MainPanelEvent (this, - p); - - for (MainPanelListener l : this.mainPanelListeners) - { - - l.panelShown (ev); - - } - - } - - public void removeMainPanelListener (MainPanelListener l) - { - - this.mainPanelListeners.remove (l); - - } - - public void addMainPanelListener (MainPanelListener l) - { - - this.mainPanelListeners.add (l); - - } - - private void fireFullScreenEnteredEvent () - { - - FullScreenEvent ev = new FullScreenEvent (this); - - for (FullScreenListener l : this.fullScreenListeners) - { - - l.fullScreenEntered (ev); - - } - - } - - private void fireFullScreenExitedEvent () - { - - FullScreenEvent ev = new FullScreenEvent (this); - - for (FullScreenListener l : this.fullScreenListeners) - { - - l.fullScreenExited (ev); - - } - - } - - public void removeFullScreenListener (FullScreenListener l) - { - - this.fullScreenListeners.remove (l); - - } - - public void addFullScreenListener (FullScreenListener l) - { - - this.fullScreenListeners.add (l); - - } - - protected void fireSideBarShownEvent (AbstractSideBar sb) - { - - SideBarEvent ev = new SideBarEvent (this, - sb); - - for (SideBarListener l : this.sideBarListeners) - { - - l.sideBarShown (ev); - - } - - } - - protected void fireSideBarHiddenEvent (AbstractSideBar sb) - { - - SideBarEvent ev = new SideBarEvent (this, - sb); - - for (SideBarListener l : this.sideBarListeners) - { - - l.sideBarHidden (ev); - - } - - } - - public void removeSideBarListener (SideBarListener l) - { - - this.sideBarListeners.remove (l); - - } - - public void addSideBarListener (SideBarListener l) - { - - this.sideBarListeners.add (l); - - } - - private JComponent createLayoutFiller () - { - - Box l = new Box (BoxLayout.X_AXIS); - l.setMinimumSize (new Dimension (0, 0)); - l.setPreferredSize (new Dimension (0, 0)); - l.setVisible (false); - - return l; - - } - - public void closeSideBar () - { - - if (this.currentOtherSideBar != null) - { - - this.currentOtherSideBar.onHide (); - - this.fireSideBarHiddenEvent (this.currentOtherSideBar); - - } - - this.currentOtherSideBar = null; - - this.showMainSideBar (); - - } - - public AbstractSideBar getSideBar (String id) - { - - return this.sideBars.get (id); - - } - - public void removeSideBar (String id) - { - - this.removeSideBar (this.getSideBar (id)); - - } - - public void removeSideBar (AbstractSideBar sb) - { - - if (sb == null) - { - - return; - - } - - this.sideBars.remove (sb.getId ()); - - this.activeSideBars.remove (sb); - - if (this.currentOtherSideBar == sb) - { - - this.currentOtherSideBar = null; - - } - - try - { - - // Close the sidebar down gracefully. - sb.onHide (); - - this.fireSideBarHiddenEvent (sb); - - sb.onClose (); - - } catch (Exception e) { - - Environment.logError ("Unable to close sidebar: " + sb.getId (), - e); - - } - - this.removeSideBarListener (sb); - - this.removeMainPanelListener (sb); - - AbstractSideBar _sb = (this.activeSideBars.size () > 0 ? this.activeSideBars.peek () : null); - - if (_sb != null) - { - - this.showSideBar (_sb.getId ()); - - } else { - - if (this.fsf == null) - { - - this.setUILayout (this.layout); - - } - - } - - } - - public void addSideBar (AbstractSideBar sb) - throws GeneralException - { - - if (sb == null) - { - - throw new IllegalArgumentException ("No sidebar provided."); - - } - - String state = null; - - String id = sb.getId (); - - if (id != null) - { - - state = this.proj.getProperty ("sidebarState-" + id); - - } - - sb.init (state); - - //sb.setName (name); - - this.sideBars.put (id, - sb); - - this.addMainPanelListener (sb); - - } - - public boolean isDistractionFreeModeEnabled () - { - - if (this.fsf != null) - { - - return this.fsf.isDistractionFreeModeEnabled (); - - } - - return false; - - } - - public void exitFullScreen () - { - - try - { - - if (this.fsf != null) - { - - this.fsf.close (); - - this.tabs.setVisible (true); - - this.fullScreenOverlay.setVisible (false); - - } - - this.setUILayout (this.layout); - - } catch (Exception e) { - - Environment.logError ("Unable to exit full screen", - e); - - UIUtils.showErrorMessage (null, - getUIString (fullscreen,actions,exit,actionerror)); - - } finally { - - this.setVisible (true); - - } - - } - - public void closeFind () - { - - this.showMainSideBar (); - - } - - public void viewWordCounts () - { - - this.showSideBar ("wordcounts"); - - this.fireProjectEvent (ProjectEvent.WORD_COUNTS, - ProjectEvent.SHOW); - - this.fireProjectEvent (ProjectEvent.READABILITY, - ProjectEvent.SHOW); - - } - - public void showFind (String text) - { - - this.showSideBar ("find"); - - if (text == null) - { - - QuollPanel qp = this.getCurrentlyVisibleTab (); - - if (qp instanceof AbstractEditorPanel) - { - - text = ((AbstractEditorPanel) qp).getEditor ().getSelectedText (); - - } - - } - - this.finder.setFindText (text); - - this.finder.onShow (); - - } - - public boolean isMainSideBar (AbstractSideBar sb) - { - - return this.mainSideBar == sb; - - } - - public boolean isMainSideBarId (String n) - { - - return (n.equals (this.getMainSideBarId ())); - - } - - protected void setMainSideBar (AbstractSideBar sb) - { - - this.mainSideBar = sb; - - this.sideBars.put (this.getMainSideBarId (), - sb); - - this.showMainSideBar (); - - } - - public void showMainSideBar () - { - - this.showSideBar (this.getMainSideBarId ()); - - } - - public String getMainSideBarId () - { - - return this.mainSideBar.getId (); - - } - - public int getActiveSideBarCount () - { - - int c = this.activeSideBars.size (); - - if ((this.layout.equals (Constants.LEFT)) - || - (this.layout.equals (Constants.RIGHT)) - || - (this.layout.equals (Constants.LAYOUT_PS_CH)) - || - (this.layout.equals (Constants.LAYOUT_CH_PS)) - ) - { - - c++; - - } - - return c; - - } - - public JPopupMenu getShowOtherSideBarsPopupSelector () - { - - final AbstractProjectViewer _this = this; - - JPopupMenu m = new JPopupMenu (); - - if (this.currentOtherSideBar != null) - { - - if ((this.layout.equals (Constants.LEFT)) - || - (this.layout.equals (Constants.RIGHT)) - || - (this.layout.equals (Constants.LAYOUT_PS_CH)) - || - (this.layout.equals (Constants.LAYOUT_CH_PS)) - ) - { - - JMenuItem mi = UIUtils.createMenuItem (this.mainSideBar.getActiveTitle (), - this.mainSideBar.getActiveIconType (), - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.showMainSideBar (); - - } - - }); - - m.add (mi); - - } - - } - - // Means we are showing the main sidebar and the other sidebar. - // Exclude those from the list. - for (AbstractSideBar sb : this.activeSideBars) - { - - if ((this.currentOtherSideBar != null) - && - (this.currentOtherSideBar == sb) - ) - { - - continue; - - } - - final AbstractSideBar _sb = sb; - - JMenuItem mi = UIUtils.createMenuItem (sb.getActiveTitle (), - sb.getActiveIconType (), - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.showSideBar (_sb.getId ()); - - } - - }); - - m.add (mi); - - } - - return m; - - } - - public void showSideBar (String id) - { - - if ((this.currentOtherSideBar != null) - && - (this.currentOtherSideBar.getId ().equals (id)) - ) - { - - return; - - } - - AbstractSideBar b = this.sideBars.get (id); - - if (b == null) - { - - throw new IllegalArgumentException ("Unable to show sidebar: " + - id + - ", no sidebar found with that id."); - - } - - if (this.currentOtherSideBar != null) - { - - // Will be hiding this one. - this.currentOtherSideBar.onHide (); - - this.fireSideBarHiddenEvent (this.currentOtherSideBar); - - } - - if (id.equals (this.getMainSideBarId ())) - { - - // Need to check the layout. If we are only showing one sidebar then set the current other - // to null. - if (this.isUILayoutShowSingleSidebar ()) - { - - this.currentOtherSideBar = null; - - } - - } else { - - this.currentOtherSideBar = b; - - this.activeSideBars.remove (b); - - this.activeSideBars.push (b); - - } - - if (this.fsf != null) - { - - if (this.currentOtherSideBar != null) - { - - this.sideBarWrapper.removeAll (); - this.sideBarWrapper.add (this.currentOtherSideBar); - - } else { - - this.sideBarWrapper.removeAll (); - this.sideBarWrapper.add (this.mainSideBar); - - } - - this.fsf.showSideBar (); - - } else { - - this.setUILayout (this.layout); - - } - - try - { - - b.onShow (); - - } catch (Exception e) { - - Environment.logError ("Unable to call onShow for sidebar: " + - id + - ", instance: " + - b, - e); - - } - - this.fireSideBarShownEvent (b); - - } - - public void setSplitPaneColor (Color c) - { - - - ((javax.swing.plaf.basic.BasicSplitPaneUI) this.splitPane.getUI ()).getDivider ().setBackground (Environment.getBorderColor ()); - - this.validate (); - this.repaint (); - - } - - public void setSplitPaneColor () - { - - this.setSplitPaneColor (UIUtils.getComponentColor ()); - - } - - public void addTabChangeListener (ChangeListener cl) - { - - this.tabs.addChangeListener (cl); - - } - - private void updateToolbarForPanel (QuollPanel qp) - { - - if (qp != null) - { - - this.toolbarPanel.removeAll (); - - JToolBar tb = qp.getToolBar ((this.fsf != null)); - - if (tb != null) - { - - this.toolbarPanel.add (tb); - - if (tb.getComponentCount () == 0) - { - - this.setToolbarVisible (false); - - } else - { - - this.setToolbarVisible (true); - - } - - } - - this.toolbarPanel.setMaximumSize (new Dimension (Short.MAX_VALUE, - this.toolbarPanel.getPreferredSize ().height)); - - this.toolbarPanel.revalidate (); - this.toolbarPanel.repaint (); - - } else - { - - this.setToolbarVisible (false); - - } - - } - - private DnDTabbedPane createTabbedPane () - { - - final AbstractProjectViewer _this = this; - - final DnDTabbedPane p = new DnDTabbedPane (); - - p.setTabLayoutPolicy (JTabbedPane.SCROLL_TAB_LAYOUT); - - p.addChangeListener (new ChangeAdapter () - { - - public void stateChanged (ChangeEvent ev) - { - - _this.updateToolbarForPanel (_this.getCurrentlyVisibleTab ()); - - } - - }); - - return p; - - } - - public abstract String getViewerTitle (); - - public abstract void reloadTreeForObjectType (String objType); - - public abstract void reloadTreeForObjectType (NamedObject obj); - - public abstract void showObjectInTree (String treeObjType, - NamedObject obj); - - public abstract AbstractSideBar getMainSideBar (); - - public abstract String getChapterObjectName (); - - public abstract void fillFullScreenTitleToolbar (JToolBar toolbar); - - public abstract void doSaveState (); - - public abstract void handleOpenProject () - throws Exception; - - public abstract void handleNewProject () - throws Exception; - - public abstract boolean viewObject (DataObject d); - - public abstract boolean viewObject (DataObject d, - ActionListener doAfterView); - - public abstract boolean openPanel (String id); - - public abstract void deleteChapter (Chapter c); - - public abstract void deleteObject (NamedObject o) - throws GeneralException; - - public abstract void deleteObject (NamedObject o, - boolean deleteChildObjects) - throws GeneralException; - - public abstract void updateChapterIndexes (Book b) - throws GeneralException; - - public abstract void handleItemChangedEvent (ItemChangedEvent ev); - - public abstract Set findText (String t); - - public Action getAction (int name) - { - - return this.getAction (name, - null); - - } - - /** - * Get the correct text properties depending on whether the viewer is in full screen or not. - * - * @returns Normal project text properties if we are in normal mode or full screen text properties - * if we are in full screen mode. - */ - public TextProperties getTextProperties () - { - - return (this.fsf != null ? Environment.getFullScreenTextProperties () : Environment.getProjectTextProperties ()); - - } - - public void reinitAllChapterEditors () - { - - this.doForPanels (AbstractEditorPanel.class, - new DefaultQuollPanelAction () - { - - public void doAction (QuollPanel qp) - { - - ((AbstractEditorPanel) qp).initEditor (); - - } - - }); - - } - - public void scrollTo (final Chapter c, - final int pos) - { - - final AbstractProjectViewer _this = this; - - this.viewObject (c); - - SwingUtilities.invokeLater (new Runner () - { - - public void run () - { - - try - { - - _this.getEditorForChapter (c).scrollToPosition (pos); - _this.getEditorForChapter (c).scrollToPosition (pos); - - } catch (Exception e) - { - - Environment.logError ("Unable to scroll to position: " + - pos, - e); - - } - - } - - }); - - } - - public AbstractEditorPanel getEditorForChapter (Chapter c) - { - - return (AbstractEditorPanel) this.getQuollPanelForObject (c); - - } - - public Action getAction (int name, - final NamedObject other) - { - - final AbstractProjectViewer pv = this; - - if (name == AbstractProjectViewer.EDIT_CHAPTER_ACTION) - { - - return new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - pv.viewObject ((Chapter) other); - - } - - }; - - } - - if (name == AbstractProjectViewer.RENAME_CHAPTER_ACTION) - { - - return new RenameChapterActionHandler ((Chapter) other, - pv); - - } - - if (name == AbstractProjectViewer.WARMUP_EXERCISE_ACTION) - { - - return new ActionAdapter () - { - - public void actionPerformed (final ActionEvent ev) - { - - pv.showWarmupPromptSelect (); - - } - - }; - - } - - if (name == AbstractProjectViewer.DELETE_CHAPTER_ACTION) - { - - return new DeleteChapterActionHandler ((Chapter) other, - pv); - - } - - if (name == AbstractProjectViewer.CREATE_PROJECT_SNAPSHOT_ACTION) - { - - return new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - UIUtils.showCreateBackup (pv.getProject (), - null, - pv); - - } - - }; - - } - - if (name == AbstractProjectViewer.RENAME_PROJECT_ACTION) - { - - return new RenameProjectActionHandler (this); - - } - - if (name == AbstractProjectViewer.OPEN_PROJECT_ACTION) - { - - return new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - try - { - - Environment.showLanding (); - - } catch (Exception e) { - - Environment.logError ("Unable to show landing", - e); - - UIUtils.showErrorMessage (pv, - getUIString (project,actions,openproject)); - //"Unable to show the {projects} window, please contact Quoll Writer support for assistance."); - - } - - } - - }; - - } - - if (name == AbstractProjectViewer.NEW_PROJECT_ACTION) - { - - return new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - UIUtils.showAddNewProject (pv, - null, - null); - - } - - }; - - } - - if (name == AbstractProjectViewer.CLOSE_PROJECT_ACTION) - { - - return new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - pv.close (false, - null); - - } - - }; - - } - - if (name == AbstractProjectViewer.EDIT_PROJECT_PROPERTIES_ACTION) - { - - return new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - pv.showOptions (); - - } - - }; - - } - - if (name == AbstractProjectViewer.DELETE_PROJECT_ACTION) - { - - return new DeleteProjectActionHandler (this, - this.getProject (), - null); - - } - - if (name == AbstractProjectViewer.REPORT_BUG_ACTION) - { - - return new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - pv.showReportProblem (); - - } - - }; - - } - - if (name == AbstractProjectViewer.CONTACT_SUPPORT_ACTION) - { - - return new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - pv.showContactSupport (); - - } - - }; - - } - - if (name == AbstractProjectViewer.ABOUT_ACTION) - { - - return new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - pv.showAbout (); - - } - - }; - - } - - return super.getAction (name); - - } - - public void updateProjectDictionaryForNames (Set oldNames, - NamedObject object) - { - - if (!(object instanceof Asset)) - { - - return; - - } - - if (this.projDict != null) - { - - this.projDict.removeObjectNames (oldNames); - this.projDict.addNamedObject (object); - - } -/* - for (String nn : oldNames) - { - - if (nn == null) - { - - continue; - - } - - if (nn.trim ().length () == 0) - { - - continue; - - } - - try - { - - this.removeWordFromDictionary (nn); - //"project"); - //this.removeWordFromDictionary (nn + "'s"); - //"project"); - - } catch (Exception e) {} - - } - - for (String nn : object.getAllNames ()) - { - - // Add the name. - try - { - - this.addWordToDictionary (nn); - //"project"); - //this.addWordToDictionary (nn + "'s"); - //"project"); - - } catch (Exception e) {} - - } -*/ - } - - public void removeWordFromDictionary (String w) - { - - if (this.projDict != null) - { - - this.projDict.removeWord (w); - - } - - } - - public void addWordToDictionary (String w) - { - - if (this.projDict != null) - { - - this.projDict.addWord (w); - - } - - } - - public void setDictionaryProvider (DictionaryProvider2 dp) - { - - throw new UnsupportedOperationException ("Not supported."); - - } - - public void checkSpelling () - { - - throw new UnsupportedOperationException ("Not supported."); - - } - - public void doForSideBars (final Class type, - final QuollSideBarAction act, - final boolean doOnEventThread) - { - - Set ps = new LinkedHashSet (this.sideBars.values ()); - - for (AbstractSideBar sb : ps) - { - - if (type.isAssignableFrom (sb.getClass ())) - { - - final AbstractSideBar _sb = sb; - - if (doOnEventThread) - { - - UIUtils.doLater (new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - act.doAction (_sb); - - } - - }); - - } else { - - try - { - - act.doAction (sb); - - } catch (Exception e) { - - Environment.logError ("Unable to perform action: " + - act, - e); - - } - - } - - } - - } - - } - - public void doForSideBars (final Class type, - final QuollSideBarAction act) - { - - this.doForSideBars (type, - act, - true); - - } - - public void doForPanels (final Class type, - final QuollPanelAction act, - final boolean doOnEventThread) - { - - Set ps = new LinkedHashSet (this.panels.values ()); - - for (QuollPanel p : ps) - { - - if (type.isAssignableFrom (p.getClass ())) - { - - final QuollPanel _p = p; - - if (doOnEventThread) - { - - UIUtils.doLater (new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - act.doAction (_p); - - } - - }); - - } else { - - try - { - - act.doAction (p); - - } catch (Exception e) { - - Environment.logError ("Unable to perform action: " + - act, - e); - - } - - } - - } - - } - - } - - public void doForPanels (final Class type, - final QuollPanelAction act) - { - - this.doForPanels (type, - act, - true); - - } - - public boolean isHighlightWritingLine () - { - - return this.proj.getPropertyAsBoolean (Constants.EDITOR_HIGHLIGHT_WRITING_LINE_PROPERTY_NAME); - - } - - public void setHighlightWritingLine (final boolean s) - { - - this.doForPanels (AbstractEditorPanel.class, - new DefaultQuollPanelAction () - { - - public void doAction (QuollPanel p) - { - - ((AbstractEditorPanel) p).getEditor ().setHighlightWritingLine (s); - - } - - }); - - } - - /** - * Set the spell check language for the project. Note: this DOES NOT affect the project property: - * {@link Constants.SPELL_CHECK_LANGUAGE_PROPERTY_NAME}. Also this does not affect the spell check enabled - * flag. - * - * @param lang The language to use, set to null to switch off spell checking. - * @param updateEditors Set to true to tell all the editor panels about the change. - * @throws Exception If something goes wrong. - */ - public void setSpellCheckLanguage (String lang, - boolean updateEditors) - throws Exception - { - - if ((this.projectLanguage != null) - && - (this.projectLanguage.equals (lang)) - ) - { - - // Not changing. - return; - - } - - this.projectLanguage = lang; - - if (lang == null) - { - - // Basically turning off spellchecking. - this.projDict = null; - - this.doForPanels (SpellCheckSupported.class, - new DefaultQuollPanelAction () - { - - public void doAction (QuollPanel panel) - { - - AbstractEditorPanel s = (AbstractEditorPanel) panel; - - s.setDictionaryProvider (null); - - s.setSynonymProvider (null); - - } - - }); - - return; - - } - - java.util.List names = new ArrayList (); - - boolean isEnglish = Environment.isEnglish (lang); - - // Get the names from the assets. - Set objs = this.proj.getAllNamedChildObjects (Asset.class); - - for (NamedObject o : objs) - { - - Set onames = o.getAllNames (); - - for (String n : onames) - { - - // Get the name, add it. - names.add (n); - - if (isEnglish) - { - - names.add (n + "'s"); - - } - - } - - } - - this.projDict = new ProjectDictionaryProvider (names, - new UserDictionaryProvider (this.projectLanguage)); - - final AbstractProjectViewer _this = this; - - if (updateEditors) - { - - this.doForPanels (AbstractEditorPanel.class, - new DefaultQuollPanelAction () - { - - public void doAction (QuollPanel panel) - { - - AbstractEditorPanel s = (AbstractEditorPanel) panel; - - s.setDictionaryProvider (_this.projDict); - - try - { - - s.setSynonymProvider (_this.getSynonymProvider ()); - - } catch (Exception e) { - - Environment.logError ("Unable to set synonym provider", - e); - - } - - } - - }); - - } - - } - - public ReadabilityIndices getReadabilityIndices (String text) - { - - ReadabilityIndices ri = new ReadabilityIndices (); - - if (text != null) - { - - ri.add (text); - - } - - return ri; - - - } - - public String getWordTypes (String word) - throws GeneralException - { - - if (this.synProv != null) - { - - return this.synProv.getWordTypes (word); - - } - - return null; - - } - - public Synonyms getSynonyms (String word) - throws GeneralException - { - - if (this.synProv != null) - { - - return this.synProv.getSynonyms (word); - - } - - return null; - - } - - public boolean synonymLookupsSupported () - { - - return this.synProv != null; - - } - - public SynonymProvider getSynonymProvider () - throws Exception - { - - if (this.synProv != null) - { - - return this.synProv; - - } - - this.synProv = Environment.getSynonymProvider (this.getSpellCheckLanguage ()); - - return this.synProv; - - } - - public boolean isLanguageFunctionAvailable () - { - - if (!this.isLanguageEnglish ()) - { - - this.showNotificationPopup (getUIString (functionunavailable,title), - //"Function unavailable", - getUIString (functionunavailable,text), - //"Sorry, this function is only available when your spellchecker language is English.

    Click here to contact me to help add support for your language", - 20); - - return false; - - } - - return true; - - } - - public boolean isLanguageEnglish () - { - - return Environment.isEnglish (this.getSpellCheckLanguage ()); - - } - - public String getSpellCheckLanguage () - { - - String c = this.proj.getProperty (Constants.SPELL_CHECK_LANGUAGE_PROPERTY_NAME); - - // Get the property. - if (c == null) - { - - c = Environment.getProperty (Constants.SPELL_CHECK_LANGUAGE_PROPERTY_NAME); - - } - - if (Environment.isEnglish (c)) - { - - c = Constants.ENGLISH; - - } - - return c; - - } - - public ProjectDictionaryProvider getDictionaryProvider () - { - - return this.projDict; - - } - - public void setToolbarLocation (String loc) - { - - if (loc == null) - { - - loc = Constants.BOTTOM; - - } - - if (loc.equals (Constants.TOP)) - { - - this.toolbarPanel.setBorder (new CompoundBorder (new MatteBorder (0, 0, 1, 0, UIUtils.getBorderColor ()), - new EmptyBorder (0, - 5, - 0, - 5))); - - this.sideBar.add (this.toolbarPanel, - 0); - - } else - { - - this.toolbarPanel.setBorder (new CompoundBorder (new MatteBorder (1, 0, 0, 0, UIUtils.getBorderColor ()), - new EmptyBorder (0, - 5, - 0, - 5))); - - this.sideBar.add (this.toolbarPanel); - - } - - this.toolbarLocation = loc; - - } - - public void setTabsLocation (String loc) - { - - if (loc == null) - { - - loc = Constants.TOP; - - } - - int p = -1; - - Border b = null; - - if (loc.equals (Constants.TOP)) - { - - p = JTabbedPane.TOP; - - b = new EmptyBorder (7, 0, 0, 0); - - } - - if (loc.equals (Constants.BOTTOM)) - { - - p = JTabbedPane.BOTTOM; - - b = new EmptyBorder (0, 0, 7, 0); - - } - - if (loc.equals (Constants.LEFT)) - { - - p = JTabbedPane.LEFT; - - } - - if (loc.equals (Constants.RIGHT)) - { - - p = JTabbedPane.RIGHT; - - } - - this.tabs.setBorder (b); - - this.tabs.setTabPlacement (p); - - } - - @Override - public AbstractSideBar getActiveOtherSideBar () - { - - if (this.activeSideBars.size () > 0) - { - - return this.activeSideBars.peek (); - - } - - return null; - - } - - private boolean isUILayoutShowSingleSidebar () - { - - String layout = this.getUILayout (); - - if (layout.equals (Constants.LEFT)) - { - - layout = Constants.LAYOUT_PS_CH; - - } - - if (layout.equals (Constants.RIGHT)) - { - - layout = Constants.LAYOUT_CH_PS; - - } - - return (layout.equals (Constants.LAYOUT_PS_CH) - || - layout.equals (Constants.LAYOUT_CH_PS)); - - } - - /** - * The layout is done in terms of preferred sizes and resize weights. - * We then call resetToPreferredSizes on the split panes to resize. - * The resize weights ensure that the tabs get all the extra space (without it one of the sidebars - * could get the space). Weights of 0.98f and 0.02f are used to ensure that the sidebars aren't shrunk below - * their current size (can't work out why it does that...) - * - * @{link splitpane2} is nested within the right half of {@link splitpane}. - * - * A zero sized filler is used to when a "half" isn't used to ensure that the relevant splitpane - * doesn't freak out. See {@link createLayoutFiller()}. - */ - public void setUILayout (String layout) - { - - final AbstractProjectViewer _this = this; - final AbstractSideBar other = this.currentOtherSideBar; - - final Dimension min = this.sideBar.getMinimumSize (); - - int ww = this.splitPane.getSize ().width; - - if (ww == 0) - { - - ww = this.proj.getPropertyAsInt (Constants.WINDOW_WIDTH_PROPERTY_NAME); - - } - - int sbw = this.savedSideBarWidth; - - if (sbw == 0) - { - - sbw = this.sideBar.getSize ().width; - - } else { - - this.savedSideBarWidth = 0; - - } - - if (sbw == 0) - { - - sbw = this.proj.getPropertyAsInt (Constants.PROJECT_SIDE_BAR_WIDTH_PROPERTY_NAME); - - if (sbw <= 0) - { - - // Legacy, pre-v2.3 - int spd = this.proj.getPropertyAsInt (Constants.SPLIT_PANE_DIVIDER_LOCATION_PROPERTY_NAME); - - if (spd > 0) - { - - sbw = spd; - - this.proj.removeProperty (Constants.PROJECT_SIDE_BAR_WIDTH_PROPERTY_NAME); - - } else { - - sbw = this.proj.getPropertyAsInt (Constants.PROJECT_SIDE_BAR_WIDTH_PROPERTY_NAME); - - } - - } - - if (sbw == 0) - { - - sbw = min.width; - - } - - } - - if (min.width > sbw) - { - - sbw = min.width; - - } - - int h = this.splitPane.getSize ().height; - - if (h == 0) - { - - h = 200; - - } - - int w = ww - sbw - INTERNAL_SPLIT_PANE_DIVIDER_WIDTH; - int ow = 0; - - if (other != null) - { - - ow = this.savedOtherSideBarWidth; - - if (ow == 0) - { - - ow = other.getMinimumSize ().width - INTERNAL_SPLIT_PANE_DIVIDER_WIDTH; - - } else { - - this.savedOtherSideBarWidth = 0; - - } - - w -= ow; - - other.setPreferredSize (new Dimension (ow, - h)); - - } - - //this.tabs.setPreferredSize (new Dimension (w, 100)); - - //this.sideBar.setPreferredSize (new Dimension (sbw, 200)); - - final int fw = w; - final int fow = ow; - final int fsbw = sbw; - - // Legacy, pre-2.3 - if (layout.equals (Constants.LEFT)) - { - - layout = Constants.LAYOUT_PS_CH; - - } - - if (layout.equals (Constants.RIGHT)) - { - - layout = Constants.LAYOUT_CH_PS; - - } - - if (layout.equals (Constants.LAYOUT_PS_CH_OS)) - { - - this.splitPane.setLeftComponent (this.sideBar); - this.splitPane.setDividerSize (INTERNAL_SPLIT_PANE_DIVIDER_WIDTH); - this.splitPane.setResizeWeight (0f); - this.splitPane.setDividerLocation (this.sideBar.getPreferredSize ().width); - - this.splitPane2.setLeftComponent (this.tabs); - this.splitPane2.setRightComponent (this.createLayoutFiller ()); - this.splitPane2.setDividerSize (0); - - this.sideBarWrapper.removeAll (); - this.sideBarWrapper.add (this.mainSideBar); - - this.splitPane.setDividerLocation (fsbw);//this.sideBar.getPreferredSize ().width); - - // Is a non-main sidebar visible? - if (other != null) - { - - this.splitPane2.setResizeWeight (1f); - this.splitPane2.setRightComponent (other); - this.splitPane2.setDividerSize (INTERNAL_SPLIT_PANE_DIVIDER_WIDTH); - this.splitPane2.setDividerLocation (fw); - - UIUtils.doLater (new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - // For reasons best known to swing this has to be done separately otherwise when - // you exit full screen it will have the other sidebar as taking up all the space. - _this.splitPane.setDividerLocation (fsbw); - _this.splitPane2.setDividerLocation (fw); - - _this.validate (); - _this.repaint (); - - } - - }); - - } - - } - - if (layout.equals (Constants.LAYOUT_OS_CH_PS)) - { - - this.splitPane.setLeftComponent (this.tabs); - this.splitPane.setResizeWeight (1f); - this.splitPane.setDividerSize (INTERNAL_SPLIT_PANE_DIVIDER_WIDTH); - - this.splitPane2.setLeftComponent (this.createLayoutFiller ()); - this.splitPane2.setRightComponent (this.sideBar); - this.splitPane2.setDividerSize (0); - - this.sideBarWrapper.removeAll (); - this.sideBarWrapper.add (this.mainSideBar); - - this.splitPane.setDividerLocation (fw); - - // Is a non-main sidebar visible? - if (other != null) - { - - this.splitPane.setResizeWeight (0); - this.splitPane2.setResizeWeight (1f); - - this.splitPane.setLeftComponent (other); - this.splitPane.setResizeWeight (0); - - this.splitPane2.setLeftComponent (this.tabs); - this.splitPane2.setDividerSize (INTERNAL_SPLIT_PANE_DIVIDER_WIDTH); - this.splitPane.setDividerLocation (fow); - this.splitPane2.setDividerLocation (fw); - - UIUtils.doLater (new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - // For reasons best known to swing this has to be done separately otherwise when - // you exit full screen it will have the other sidebar as taking up all the space. - _this.splitPane.setDividerLocation (fow); - _this.splitPane2.setDividerLocation (fw); - - _this.validate (); - _this.repaint (); - - } - - }); - - } - - } - - if (layout.equals (Constants.LAYOUT_PS_OS_CH)) - { - - this.splitPane.setLeftComponent (this.sideBar); - this.splitPane.setDividerSize (INTERNAL_SPLIT_PANE_DIVIDER_WIDTH); - this.splitPane.setResizeWeight (0f); - - this.splitPane2.setLeftComponent (this.createLayoutFiller ()); - this.splitPane2.setRightComponent (this.tabs); - //this.splitPane2.setResizeWeight (0.02f); - this.splitPane2.setDividerSize (0); - - this.sideBarWrapper.removeAll (); - this.sideBarWrapper.add (this.mainSideBar); - - this.splitPane.setDividerLocation (fsbw); - - // Is a non-main sidebar visible? - if (other != null) - { - - //this.splitPane.setResizeWeight (0.5f); - - this.splitPane2.setLeftComponent (other); - this.splitPane2.setDividerSize (INTERNAL_SPLIT_PANE_DIVIDER_WIDTH); - this.splitPane2.setResizeWeight (0f); - - this.splitPane2.setDividerLocation (fow); - this.splitPane.setDividerLocation (fsbw); - - UIUtils.doLater (new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - // For reasons best known to swing this has to be done separately otherwise when - // you exit full screen it will have the other sidebar as taking up all the space. - _this.splitPane2.setDividerLocation (fow); - _this.splitPane.setDividerLocation (fsbw); - - _this.validate (); - _this.repaint (); - - } - - }); - - } - - } - - if (layout.equals (Constants.LAYOUT_CH_OS_PS)) - { - - this.splitPane.setLeftComponent (this.tabs); - this.splitPane.setDividerSize (INTERNAL_SPLIT_PANE_DIVIDER_WIDTH); - - this.splitPane2.setLeftComponent (this.createLayoutFiller ()); - this.splitPane2.setRightComponent (this.sideBar); - this.splitPane2.setDividerSize (0); - - this.sideBarWrapper.removeAll (); - this.sideBarWrapper.add (this.mainSideBar); - - this.splitPane.setDividerLocation (fw); - - // Is a non-main sidebar visible? - if (other != null) - { - - this.splitPane.setResizeWeight (1f); - - this.splitPane2.setLeftComponent (other); - this.splitPane2.setDividerSize (INTERNAL_SPLIT_PANE_DIVIDER_WIDTH); - - this.splitPane2.setDividerLocation (fow); - this.splitPane.setDividerLocation (fw); - - UIUtils.doLater (new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - // For reasons best known to swing this has to be done separately otherwise when - // you exit full screen it will have the other sidebar as taking up all the space. - _this.splitPane2.setDividerLocation (fow); - _this.splitPane.setDividerLocation (fw); - - _this.validate (); - _this.repaint (); - - } - - }); - - } - - } - - if (layout.equals (Constants.LAYOUT_PS_CH)) - { - - this.splitPane.setLeftComponent (this.sideBar); - this.splitPane.setDividerSize (INTERNAL_SPLIT_PANE_DIVIDER_WIDTH); - this.splitPane.setResizeWeight (0f); - - this.splitPane2.setLeftComponent (this.tabs); - this.splitPane2.setResizeWeight (1f); - this.splitPane2.setRightComponent (this.createLayoutFiller ()); - this.splitPane2.setDividerSize (0); - - if (other != null) - { - - if (other.getMinimumSize ().width > sbw) - { - - sbw = other.getMinimumSize ().width; - - } - - this.sideBarWrapper.removeAll (); - this.sideBarWrapper.add (other); - - } else { - - if (this.mainSideBar != null) - { - - if (this.mainSideBar.getMinimumSize ().width > sbw) - { - - sbw = this.mainSideBar.getMinimumSize ().width; - - } - - this.sideBarWrapper.removeAll (); - this.sideBarWrapper.add (this.mainSideBar); - - } - - } - - final int fsbw2 = sbw; - - this.splitPane.setDividerLocation (sbw); - - UIUtils.doLater (new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - // For reasons best known to swing this has to be done separately otherwise when - // you exit full screen it will have the other sidebar as taking up all the space. - _this.splitPane.setDividerLocation (fsbw2); - - _this.validate (); - _this.repaint (); - - } - - }); - - } - - if (layout.equals (Constants.LAYOUT_CH_PS)) - { - - w += ow; - - this.splitPane.setLeftComponent (this.tabs); - this.splitPane.setDividerSize (INTERNAL_SPLIT_PANE_DIVIDER_WIDTH); - this.splitPane.setResizeWeight (1f); - - this.splitPane2.setLeftComponent (this.sideBar); - this.splitPane2.setRightComponent (this.createLayoutFiller ()); - this.splitPane2.setDividerSize (0); - - if (other != null) - { - - if (other.getMinimumSize ().width > sbw) - { - - w = this.splitPane.getSize ().width - other.getMinimumSize ().width; - - } - - this.sideBarWrapper.removeAll (); - this.sideBarWrapper.add (other); - - } else { - - if (this.mainSideBar != null) - { - - if (this.mainSideBar.getMinimumSize ().width > sbw) - { - - w = this.splitPane.getSize ().width - this.mainSideBar.getMinimumSize ().width; - - } - - this.sideBarWrapper.removeAll (); - this.sideBarWrapper.add (this.mainSideBar); - - } - - } - - this.splitPane.setDividerLocation (w); - - final int fw2 = w; - - UIUtils.doLater (new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - // For reasons best known to swing this has to be done separately otherwise when - // you exit full screen it will have the other sidebar as taking up all the space. - _this.splitPane.setDividerLocation (fw2); - - _this.validate (); - _this.repaint (); - - } - - }); - - } - - this.layout = layout; - - } - - private String getUILayout () - { - - String sidebarLoc = UserProperties.get (Constants.SIDEBAR_LOCATION_PROPERTY_NAME); - - String uiLayout = Constants.LAYOUT_CH_PS; - - // Legacy, pre-v2.5 - if (sidebarLoc != null) - { - - if (sidebarLoc.equals (Constants.RIGHT)) - { - - uiLayout = Constants.LAYOUT_CH_PS; - - } - - UserProperties.remove (Constants.SIDEBAR_LOCATION_PROPERTY_NAME); - - } else { - - uiLayout = UserProperties.get (Constants.UI_LAYOUT_PROPERTY_NAME); - - } - - // Legacy, pre-2.5 - if (uiLayout.equals (Constants.LEFT)) - { - - uiLayout = Constants.LAYOUT_PS_CH; - - } - - if (uiLayout.equals (Constants.RIGHT)) - { - - uiLayout = Constants.LAYOUT_CH_PS; - - } - - return uiLayout; - - } - - protected void initWindow () - { - - if (this.proj == null) - { - - return; - - } - - this.setSpellCheckingEnabled (this.proj.getPropertyAsBoolean (Constants.SPELL_CHECKING_ENABLED_PROPERTY_NAME)); - - // Check the height and width and ensure they aren't too big. - // If they overrun the current screen size then reduce them down to 80% either way. - Dimension ss = Toolkit.getDefaultToolkit ().getScreenSize (); - - int wWidth = this.proj.getPropertyAsInt (Constants.WINDOW_WIDTH_PROPERTY_NAME); - - if (wWidth > ss.width) - { - - wWidth = (int) ((float) ss.width * 0.8f); - - } - - int wHeight = this.proj.getPropertyAsInt (Constants.WINDOW_HEIGHT_PROPERTY_NAME); - - if (wHeight > ss.height) - { - - wHeight = (int) ((float) ss.height * 0.8f); - - } - - this.splitPane.setPreferredSize (new Dimension (wWidth, - wHeight)); - - this.setSplitPaneColor (); - - this.setToolbarLocation (this.proj.getProperty (Constants.TOOLBAR_LOCATION_PROPERTY_NAME)); - - String sidebarLoc = UserProperties.get (Constants.SIDEBAR_LOCATION_PROPERTY_NAME); - - String uiLayout = this.getUILayout (); - - this.setUILayout (uiLayout); - - this.setTabsLocation (this.proj.getProperty (Constants.TABS_LOCATION_PROPERTY_NAME)); - - this.setViewerTitle (this.getViewerTitle ()); - - this.setIconImage (Environment.getWindowIcon ().getImage ()); - - //this.updateForDebugMode (); - - //this.pack (); - - // Allow the underlying Windowing manager determine where to put the window. - //this.setLocationByPlatform (true); - - //this.setVisible (true); - - //Environment.doNewsAndVersionCheck (this); - - if (this.isSpellCheckingEnabled ()) - { - - this.doForPanels (SpellCheckSupported.class, - new DefaultQuollPanelAction () - { - - public void doAction (QuollPanel p) - { - - SpellCheckSupported s = (SpellCheckSupported) p; - - s.checkSpelling (); - - } - - }); - - } - - } - - public void newProject (File saveDir, - Project p, - String filePassword) - throws Exception - { - - this.newProject (saveDir, - p, - filePassword, - null); - - } - - public void newProject (File saveDir, - Project p, - String filePassword, - ActionListener onOpen) - throws Exception - { - - - if (p == null) - { - - throw new GeneralException ("No project provided."); - - } - - if (p.getName () == null) - { - - throw new GeneralException ("No project name provided."); - - } - - this.setIgnoreProjectEvents (true); - - this.dBMan = Environment.createProject (saveDir, - p, - filePassword); - - this.proj = this.dBMan.getProject (); - this.proj.setFilePassword (filePassword); - - if ((this.proj.getBooks () == null) || - (this.proj.getBooks ().size () == 0) || - (this.proj.getBooks ().get (0).getChapters ().size () == 0)) - { - - Book b = null; - - if ((this.proj.getBooks () != null) - && - (this.proj.getBooks ().size () > 0) - ) - { - - b = this.proj.getBooks ().get (0); - - } else { - - b = new Book (this.proj, - this.proj.getName ()); - - this.proj.addBook (b); - - this.saveObject (b, - true); - - } - - } - - this.proj.addPropertyChangedListener (this); - - this.targets = new TargetsData (this.proj.getProperties ()); - - Environment.addToAchievementsManager (this); - - this.initSideBars (); - - this.initDictionaryProvider (); - - this.handleNewProject (); - - this.initChapterCounts (); - - this.setSpellCheckingEnabled (this.proj.getPropertyAsBoolean (Constants.SPELL_CHECKING_ENABLED_PROPERTY_NAME)); - - this.setSplitPaneColor (); - - this.startAutoBackups (); - - this.initWindow (); - - this.showMainSideBar (); - - //this.handleWhatsNew (); - - //this.handleShowTips (); - - this.setIgnoreProjectEvents (false); - - this.fireProjectEvent (this.proj.getObjectType (), - ProjectEvent.NEW); - - this.showViewer (); - - // Register ourselves with the environment. - try - { - - Environment.addOpenedProject (this); - - } catch (Exception e) - { - - Environment.logError ("Unable to add opened project (probably an error with the projects file): " + - this.proj, - e); - - } - - this.scheduleA4PageCountUpdate (); - - UIUtils.doLater (onOpen); - - } - - private void scheduleA4PageCountUpdate () - { - - final AbstractProjectViewer _this = this; - - // Generate the A4 page counts. - this.schedule (new Runnable () - { - - @Override - public void run () - { - - Book b = _this.proj.getBooks ().get (0); - - java.util.List chapters = b.getChapters (); - - for (Chapter c : chapters) - { - - String t = _this.getCurrentChapterText (c); - - ChapterCounts cc = _this.getChapterCounts (c); - - try - { - - cc.standardPageCount = UIUtils.getA4PageCountForChapter (c, - t); - - } catch (Exception e) { - - // Just ignore any errors, it's next to impossible to stop them. - - } - - } - - } - - }, - 1, - 0); - - } - - public void setToolbarVisible (boolean v) - { - - this.toolbarPanel.setVisible (v); - - } - - public void openProject (ProjectInfo p, - String filePassword) - throws Exception - { - - this.openProject (p, - filePassword, - null); - - } - - public void openProject (ProjectInfo p, - String filePassword, - ActionListener onOpen) - throws Exception - { - - this.setIgnoreProjectEvents (true); - - // Get the username and password. - String username = Environment.getProperty (Constants.DB_USERNAME_PROPERTY_NAME); - String password = Environment.getProperty (Constants.DB_PASSWORD_PROPERTY_NAME); - - if (p.isNoCredentials ()) - { - - username = null; - password = null; - filePassword = null; - - } - - if (!p.isEncrypted ()) - { - - filePassword = null; - - } - - this.dBMan = new ObjectManager (); - - this.dBMan.init (new File (p.getProjectDirectory ().getPath (), Constants.PROJECT_DB_FILE_NAME_PREFIX), - username, - password, - filePassword, - Environment.getSchemaVersion ()); - - Environment.incrStartupProgress (); - - // Get the project. - - try - { - - this.proj = this.dBMan.getProject (); - - } catch (Exception e) { - - // This means we can't open the project and something is wrong, close the dbman to prevent - // it locking the project open but unusable. - this.dBMan.closeConnectionPool (); - - throw e; - - } - - Environment.incrStartupProgress (); - - this.proj.setFilePassword (filePassword); - this.proj.setProjectDirectory (p.getProjectDirectory ()); - this.proj.setBackupDirectory (p.getBackupDirectory ()); - //this.proj.setFilePassword (filePassword); - this.proj.setEncrypted (p.isEncrypted ()); - this.proj.setNoCredentials (p.isNoCredentials ()); - - this.proj.addPropertyChangedListener (this); - - this.initChapterCounts (); - - this.targets = new TargetsData (this.proj.getProperties ()); - - Environment.incrStartupProgress (); - - Environment.addToAchievementsManager (this); - - this.initSideBars (); - - this.initDictionaryProvider (); - - this.handleOpenProject (); - - Environment.incrStartupProgress (); - - final java.util.List inits = new ArrayList (); - - this.restoreTabs (); - - Environment.incrStartupProgress (); - - this.initWindow (); - - this.setSplitPaneColor (); - - // Init all the panels. - for (QuollPanel qp : this.panels.values ()) - { - - Runner r = this.getInitPanelStateRunner (qp, - (qp == this.getCurrentlyVisibleTab ())); - //lastOpen.equals (qp.getPanelId ())); - - // The init for the panel should have set it as ready for use so switch that off. - qp.setReadyForUse (false); - - if (r != null) - { - - inits.add (r); - - } - - } - - UIUtils.doLater (new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - for (Runner r : inits) - { - - r.run (); - - } - - } - - }); - - Environment.incrStartupProgress (); - - this.startAutoBackups (); - - this.scheduleAutoSaveForAllEditors (); - - Environment.incrStartupProgress (); - - this.dBMan.createActionLogEntry (this.proj, - "Opened project", - null, - null); - - final AbstractProjectViewer _this = this; - - // Check the font used for the project and inform the user if we don't have it. - // We do it here so it's done once. - String f = this.proj.getProperty (Constants.EDITOR_FONT_PROPERTY_NAME); - - if (f != null) - { - - Font ft = new Font (f, - Font.PLAIN, - 12); - - if (!ft.getFamily ().equalsIgnoreCase (f)) - { - - UIUtils.showMessage (this, - String.format (getUIString (fontunavailable,text), - f)); - //"The font " + f + " selected for use in {chapters} is not available on this computer.

    To select a new font, switch to a chapter tab then click here to change the text properties."); - - } - - } - - //this.handleWhatsNew (); - - //this.handleShowTips (); - - this.setIgnoreProjectEvents (false); - - this.fireProjectEvent (this.proj.getObjectType (), - ProjectEvent.OPEN); - - this.showViewer (); - - // Register ourselves with the environment. - try - { - - Environment.addOpenedProject (this); - - } catch (Exception e) - { - - Environment.logError ("Unable to add opened project: " + - this.proj, - e); - - } - - this.scheduleA4PageCountUpdate (); - - UIUtils.doLater (onOpen); - - // Check to see if any chapters have overrun the target. - UIUtils.doLater (new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - try - { - - int wc = _this.getProjectTargets ().getMaxChapterCount (); - - Set chaps = _this.getChaptersOverWordTarget (); - - int s = chaps.size (); - - if ((wc > 0) - && - (s > 0) - ) - { - - for (Chapter c : chaps) - { - - _this.chapterWordCountTargetWarned.put (c, - new Date ()); - - } - - final JLabel l = UIUtils.createLabel (null, - null, - null); - - String t = LanguageStrings.single; - - if (s > 1) - { - - t = LanguageStrings.multiple; - - } - - String text = String.format (getUIString (LanguageStrings.targets, chaptersoverwcmaximum, - t), - Environment.formatNumber (chaps.size ()), - //"%s {chapter}%s over the word count maximum of %s words, click to view the {chapter}%s.", - Environment.formatNumber (wc)); - - l.setText (text); - - final Notification n = _this.addNotification (l, - Constants.WORDCOUNT_ICON_NAME, - 90); - - UIUtils.makeClickable (l, - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - Targets.showChaptersOverWordTarget (_this, - n); - - n.removeNotification (); - - } - - }); - - } - - chaps = _this.getChaptersOverReadabilityTarget (); - - s = chaps.size (); - - if (s > 0) - { - - String t = LanguageStrings.single; - - if (s > 1) - { - - t = LanguageStrings.multiple; - - } - - final JLabel l = UIUtils.createLabel (null, - null, - null); - - String text = String.format (getUIString (LanguageStrings.targets, chaptersoverreadabilitymaximum,t), - //"%s {chapter}%s over one of the readability targets, click to view the {chapter}%s.", - Environment.formatNumber (chaps.size ())); - //(s == 1 ? " is" : "s are"), - //(s == 1 ? "" : "s")); - - l.setText (text); - - final Notification n = _this.addNotification (l, - Constants.READABILITY_ICON_NAME, - 90); - - UIUtils.makeClickable (l, - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - Targets.showChaptersOverReadabilityTarget (_this, - n); - - n.removeNotification (); - - } - - }); - - } - - } catch (Exception e) { - - Environment.logError ("Unable to display chapters over target notification", - e); - - } - - } - - }); - - this.schedule (new Runnable () - { - - @Override - public void run () - { - - try - { - - int wc = _this.getProjectTargets ().getMaxChapterCount (); - - if ((wc > 0) - && - (_this.getProjectTargets ().isShowMessageWhenMaxChapterCountExceeded ()) - ) - { - - Book b = _this.proj.getBooks ().get (0); - - final Set over = new LinkedHashSet (); - - java.util.List chapters = b.getChapters (); - - Date d = new Date (); - - // 15 minutes ago. - long last = System.currentTimeMillis () - 15 * 60 * 1000; - - for (Chapter c : chapters) - { - - ChapterCounts cc = _this.getChapterCounts (c); - - final Chapter _c = c; - - if (cc.wordCount > wc) - { - - if (!_this.chapterWordCountTargetWarned.containsKey (c)) - { - - _this.chapterWordCountTargetWarned.put (c, - new Date ()); - - over.add (c); - - } - - } else { - - Date od = _this.chapterWordCountTargetWarned.get (c); - - // Only remove if it's been 15 minutes since we last warned the user. - // This provides a buffer so that they aren't constantly nagged about - // it going over, for example if they've deleted/edited a sentence, removed - // a word or two to go below the target then added some back in. - if ((od != null) - && - (od.getTime () < last) - ) - { - - _this.chapterWordCountTargetWarned.remove (c); - - } - - } - - } - - if (over.size () > 0) - { - - // Show a message. - UIUtils.doLater (new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - final int s = over.size (); - - final QPopup popup = UIUtils.createClosablePopup (getUIString (LanguageStrings.targets, LanguageStrings.popup,title), - //String.format ("{Chapter}%s over word count target", - //(s == 1 ? "" : "s")), - Environment.getIcon (Constants.WORDCOUNT_ICON_NAME, - Constants.ICON_POPUP), - null); -/* - String text = String.format ("%s {chapter}%s over the target word count, click to view them.", - Environment.formatNumber (s), - (s == 1 ? " is" : "s are")); -*/ - String text = null; - - if (s == 1) - { - - Chapter c = over.iterator ().next (); - - text = String.format (getUIString (LanguageStrings.targets, LanguageStrings.popup,singleoverlimit), - c.getName ()); - - //text = String.format ("{Chapter} %s is over the target word count, click to view it.", - // c.getName ()); - - } else { - - text = String.format (getUIString (LanguageStrings.targets, LanguageStrings.popup,multipleoverlimit), - Environment.formatNumber (s)); - - } - - Box content = new Box (BoxLayout.Y_AXIS); - - ActionListener showChapter = new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - Targets.showChaptersOverWordTarget (_this, - null); - - popup.removeFromParent (); - - } - - }; - - JLabel l = UIUtils.createLabel (text, - null, - showChapter); - - l.setBorder (UIUtils.createPadding (0, 0, 10, 0)); - - content.setBorder (UIUtils.createPadding (10, 10, 10, 10)); - - content.add (l); - - JButton cb = UIUtils.createButton (getUIString (buttons,close)); - - JButton sb = UIUtils.createButton (getUIString (buttons,showdetail), - //"Show detail", - showChapter); - - JButton[] buts = { sb, cb }; - - JComponent bs = UIUtils.createButtonBar2 (buts, - Component.CENTER_ALIGNMENT); - bs.setAlignmentX (Component.LEFT_ALIGNMENT); - - content.add (bs); - - cb.addActionListener (popup.getCloseAction ()); - popup.setRemoveOnClose (true); - - popup.setContent (content); - - popup.setDraggable (_this); - - popup.resize (); - - _this.showPopupAt (popup, - new Point (10, 10), - false); - - } - - }); - - } - - } - - } catch (Exception e) { - - Environment.logError ("Unable to determine chapters that are over target", - e); - - } - - } - - }, - 30 * 1000, - 5 * 1000); - - } - - public void saveProjectTargets () - { - - try - { - - this.saveObject (this.proj, - false); - - } catch (Exception e) { - - Environment.logError ("Unable to update project targets", - e); - - } - - } - - public TargetsData getProjectTargets () - { - - return this.targets; - - } - - private void startAutoBackups () - { - - final AbstractProjectViewer _this = this; - - this.schedule (new Runnable () - { - - public void run () - { - - try - { - - // Get references first so that they can't change further on. - Project proj = _this.proj; - ObjectManager dBMan = _this.dBMan; - - if ((proj == null) - || - (dBMan == null) - ) - { - - return; - - } - - if (proj.getPropertyAsBoolean (Constants.AUTO_SNAPSHOTS_ENABLED_PROPERTY_NAME)) - { - - // Get the last backup. - File last = dBMan.getLastBackupFile (proj); - - long lastDate = (last != null ? last.lastModified () : proj.getDateCreated ().getTime ()); - - if ((System.currentTimeMillis () - lastDate) > Utils.getTimeAsMillis (proj.getProperty (Constants.AUTO_SNAPSHOTS_TIME_PROPERTY_NAME))) - { - - Environment.createBackupForProject (proj, - false); - - UIUtils.doLater (new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - try - { - - _this.addNotification (String.format (getUIString (backups,autobackupnotification), - //"An automatic backup has been created. Click to view the backups.", - Constants.ACTION_PROTOCOL, - Constants.BACKUPS_HTML_PANEL_ACTION), - Constants.INFO_ICON_NAME, - 30); - - } catch (Exception e) { - - // Sigh... - - } - - } - - }); - - } - - } - - } catch (Exception e) { - - if (_this.proj == null) - { - - // Means we have shutdown. - return; - - } - - Environment.logError ("Unable to create backup for project: " + - _this.proj, - e); - - } - - } - - }, - // Start straight away. - 0, - // Run every 10 mins. - 10 * 60 * 1000); - - } - - /** - * Given a list of comma separated object ids, open the panels for the objects (if available). - * So an example ids might be: chapter-1,character-2,chapter-3. - * This will be parsed into 3 values and then the relevant objects searched for in the project. - * If there is an associated object then it will be opened for viewing. - * - * @param ids The object ids, comma separated. - */ - public void openPanelsFromObjectIdList (String ids) - { - - if ((ids == null) - || - (ids.trim ().equals ("")) - ) - { - - return; - - } - - java.util.List objIds = new ArrayList (); - - // Split on : - StringTokenizer t = new StringTokenizer (ids, - ","); - - while (t.hasMoreTokens ()) - { - - String tok = t.nextToken ().trim (); - - objIds.add (tok); - - } - - Collections.reverse (objIds); - - for (String panelId : objIds) - { - - ObjectReference r = null; - - try - { - - r = ObjectReference.parseObjectReference (panelId); - - } catch (Exception e) - { - - Environment.logError ("Unable to parse: " + - panelId, - e); - - continue; - - } - - // Pass it to the project. - final DataObject d = this.proj.getObjectForReference (r); - - if (d == null) - { - - if (!this.openPanelInt (panelId)) - { - - Environment.logError ("Unable to open panel for id: " + - panelId); - - continue; - - } - - } else - { - - if (!this.viewObject (d)) - { - - continue; - - } - - } - - } - - - } - - public String getOpenTabsProperty () - { - - ProjectVersion pv = this.proj.getProjectVersion (); - - String suffix = ""; - - // See if we have a project version. - if (pv != null) - { - - suffix = ":" + pv.getKey (); - - } - - // Setup the tabs. - String openTabs = this.proj.getProperty (Constants.OPEN_TABS_PROPERTY_NAME + suffix); - - return openTabs; - - } - - /** - * Responsible for setting up the panels that should be open when the project is opened. - * If you override this method ensure that you do: - * * Open the necessary panels. - * * Call this.initWindow to restore the window state. - * * Set the last opened tab (after opening it). - */ - protected void restoreTabs () - { - - ProjectVersion pv = this.proj.getProjectVersion (); - - String suffix = ""; - - // See if we have a project version. - if (pv != null) - { - - suffix = ":" + pv.getKey (); - - } - - // Setup the tabs. - String openTabs = this.getOpenTabsProperty (); - - this.openPanelsFromObjectIdList (openTabs); - - String lastOpen = this.proj.getProperty (Constants.LAST_OPEN_TAB_PROPERTY_NAME + suffix); - - if (lastOpen != null) - { - - final QuollPanel qp = this.getQuollPanel (lastOpen); - - if (qp != null) - { - - this.setPanelVisible (qp); - - } - - } - - } - - private void initDictionaryProvider () - { - - final String lang = this.getSpellCheckLanguage (); - - try - { - - if (!DictionaryProvider.isLanguageInstalled (lang)) - { - - final AbstractProjectViewer _this = this; - - // Turn off spell checking until the download is complete. - this.setSpellCheckLanguage (null, - true); - - // Download them. - this.downloadDictionaryFiles (this.getSpellCheckLanguage (), - new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - try - { - - _this.setSpellCheckLanguage (null, - true); - - _this.setSpellCheckLanguage (lang, - true); - - } catch (Exception e) { - - Environment.logError ("Unable to set spell check language to: " + - lang, - e); - - UIUtils.showErrorMessage (_this, - String.format (getUIString (spellchecker,unabletosetlanguage), - lang)); - //"Unable to set spell check language to " + - //lang + - //".

    Please contact Quoll Writer support for assistance."); - - } - - } - - }); - - } else { - - this.setSpellCheckLanguage (lang, - true); - - } - - } catch (Exception e) { - - Environment.logError ("Unable to check for spell check language", - e); - - } - - } - - public void downloadDictionaryFiles (String lang, - final ActionListener onComplete) - { - - UIUtils.downloadDictionaryFiles (lang, - this, - onComplete); - - } - - private void initPanelState (QuollPanel qp) - { - - Runner r = this.getInitPanelStateRunner (qp, - true); - - if (r != null) - { - - try - { - - r.run (); - - } catch (Exception e) { - - Environment.logError ("Unable to init panel: " + - qp.getPanelId (), - e); - - } - - } - - } - - private Runner getInitPanelStateRunner (final QuollPanel qp, - final boolean visible) - { - - final String panelId = qp.getPanelId (); - - final String state = this.proj.getProperty (panelId + "-state"); - - if (state != null) - { - - final AbstractProjectViewer _this = this; - - // Need to "do later" since it won't always set the state correctly for - // none visible tabs. - return new Runner () - { - - public void run () - { - - qp.setState (UIUtils.parseState (state), - visible); - - qp.setReadyForUse (true); - - } - - }; - - } - - return null; - - } - - public void handleHTMLPanelAction (String v) - { - - try - { - - if (v.equals (Constants.BACKUPS_HTML_PANEL_ACTION)) - { - - UIUtils.showManageBackups (Environment.getProjectInfo (this.proj), - this); - - return; - - } - - if (v.equals ("textproperties")) - { - - QuollPanel qp = this.getCurrentlyVisibleTab (); - - if (qp instanceof AbstractEditorPanel) - { - - ((AbstractEditorPanel) qp).showTextProperties (); - - } - - return; - - } - - if (v.equals ("find")) - { - - this.showFind (null); - - return; - - } - - if (v.equals ("spellcheckoff")) - { - - this.setSpellCheckingEnabled (false); - - return; - - } - - if (v.equals ("spellcheckon")) - { - - this.setSpellCheckingEnabled (true); - - return; - - } - - if (v.equals ("statistics")) - { - - this.viewStatistics (); - - return; - - } - - if (v.equals ("wordcounts")) - { - - this.viewWordCounts (); - - return; - - } - - if (v.equals ("wordcounthistory")) - { - - this.viewStatistics (); - - return; - - } - - if (v.equals ("projectoptions")) - { - - this.showOptions ("project"); - - return; - - } - - if (v.equals ("dictionarymanager")) - { - - this.showDictionaryManager (); - - return; - - } - - if (v.equals ("enabletypewritersound")) - { - - boolean old = Environment.isPlaySoundOnKeyStroke (); - - Environment.setPlaySoundOnKeyStroke (true); - - Environment.playKeyStrokeSound (); - - Environment.setPlaySoundOnKeyStroke (old); - - return; - - } - - if (v.equals ("fullscreen")) - { - - try - { - - this.enterFullScreen (); - - } catch (Exception e) { - - Environment.logError ("Unable to show in full screen mode", - e); - - } - - return; - - } - - if (v.equals ("projectsidebar")) - { - - this.showMainSideBar (); - - return; - - } - - super.handleHTMLPanelAction (v); - - } catch (Exception e) { - - Environment.logError ("Unable to perform action: " + - v, - e); - - } - - } - - public boolean viewAchievements () - { - - // Check our tabs to see if we are already viewing the word counts, if so then just switch to it instead. - AchievementsPanel ap = (AchievementsPanel) this.getQuollPanel (AchievementsPanel.PANEL_ID); - - if (ap != null) - { - - this.setPanelVisible (ap); - - this.fireProjectEvent (ProjectEvent.ACHIEVEMENTS, - ProjectEvent.SHOW); - - return true; - - } - - try - { - - ap = new AchievementsPanel (this); - - ap.init (); - - } catch (Exception e) - { - - Environment.logError ("Unable to view achievements: " + - this.proj, - e); - - UIUtils.showErrorMessage (this, - getUIString (achievementspanel,actionerror)); - //"Unable to view achievements"); - - return false; - - } - - this.addPanel (ap); - - // Open the tab :) - return this.viewAchievements (); - - } - - private boolean openPanelInt (String id) - { - - if (id.equals (OptionsPanel.PANEL_ID)) - { - - return this.showOptions (); - - } - - if (id.equals (StatisticsPanel.PANEL_ID)) - { - - return this.viewStatistics (); - - } - - if (id.equals (StatisticsPanel.OLD_WORD_COUNT_PANEL_ID)) - { - - return this.viewStatistics (); - - } - - if (id.equals (AchievementsPanel.PANEL_ID)) - { - - return this.viewAchievements (); - - } - - return this.openPanel (id); - - } - - public Project getProject () - { - - return this.proj; - - } - - protected JScrollPane createTreeScroll (JTree tree) - { - - return UIUtils.createTreeScroll (tree); - - } - - protected JTree createTree () - { - - return UIUtils.createTree (); - - } - - protected void closeAllTabs (boolean saveState) - { - - if (saveState) - { - - try - { - - this.saveState (); - - } catch (Exception e) { - - Environment.logError ("Unable to save state", - e); - - } - - } - - // Regardless of whether it should be saved call the close method - // for the panel to allow it to close itself nicely. - // Close after state so we can keep track of what is open. - - // Duplicate the values so we don't get a modification error for this.panels. - Set qpps = new LinkedHashSet (this.panels.values ()); - - for (QuollPanel qp : qpps) - { - - this.closePanel (qp); - - } - - } - - private boolean closeInternal (boolean saveUnsavedChanges, - ActionListener afterClose) - { - - if (saveUnsavedChanges) - { - - // Save all. - for (QuollPanel qp : this.panels.values ()) - { - - if (qp instanceof ProjectObjectQuollPanel) - { - - ProjectObjectQuollPanel pqp = (ProjectObjectQuollPanel) qp; - - if (pqp.hasUnsavedChanges ()) - { - - boolean showError = true; - - try - { - - showError = !pqp.saveUnsavedChanges (); - - } catch (Exception e) - { - - Environment.logError ("Unable to save unsaved changes for: " + - pqp.getForObject (), - e); - - } - - if (showError) - { - - UIUtils.showErrorMessage (this, - String.format (getUIString (closeproject,actionerror), - pqp.getTitle ())); - //"Unable to save: " + - //pqp.getTitle () + - //", aborting exit."); - - // Switch to the tab. - this.viewObject (pqp.getForObject ()); - - return false; - - } - - } - - } - - } - - } - - // Close all sidebars. - // TODO: Fix this up - for (AbstractSideBar sb : new ArrayList (this.activeSideBars)) - { - - this.removeSideBar (sb); - - } - - //this.notifications.setVisible (false); - - this.removeAllNotifications (); - - this.closeAllTabs (true); - - this.proj.setLastEdited (new Date ()); - - try - { - - this.saveProject (); - - } catch (Exception e) - { - - Environment.logError ("Unable to save project: " + - this.proj, - e); - - return false; - - } - - this.proj.removePropertyChangedListener (this); - - ChapterDataHandler ch = (ChapterDataHandler) this.dBMan.getHandler (Chapter.class); - - ch.saveWordCounts (this.proj, - this.sessionStart, - new Date ()); - - this.dBMan.createActionLogEntry (this.proj, - "Closed project", - null, - null); - - // Fire our last event. - this.fireProjectEvent (this.proj.getObjectType (), - ProjectEvent.CLOSE); - - Environment.removeFromAchievementsManager (this); - - // Close all the db connections. - this.dBMan.closeConnectionPool (); - - try - { - - Environment.projectClosed (this, - !(afterClose != null)); - - } catch (Exception e) - { - - Environment.logError ("Unable to close project", - e); - - Environment.showLanding (); - - return false; - - } - - super.close (false, - afterClose); - - return true; - - } - - @Override - public boolean close (boolean noConfirm, - final ActionListener afterClose) - { - - final StringBuilder b = new StringBuilder (); - - this.exitFullScreen (); - - boolean save = false; - - if (noConfirm) - { - - save = true; - - } - - if (!noConfirm) - { - - boolean hasChanges = false; - - for (QuollPanel qp : this.panels.values ()) - { - - if (qp instanceof ProjectObjectQuollPanel) - { - - ProjectObjectQuollPanel pqp = (ProjectObjectQuollPanel) qp; - - if (pqp.hasUnsavedChanges ()) - { - - hasChanges = true; - - if (pqp.getForObject () instanceof NamedObject) - { - - b.append ("
  • " + pqp.getTitle () + "
  • "); - - } - - } - - } - - } - - if (hasChanges) - { - - final AbstractProjectViewer _this = this; - - Map buttons = new LinkedHashMap (); - - buttons.put (getUIString (LanguageStrings.buttons,savechanges), - //"Yes, save the changes", - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.closeInternal (true, - afterClose); - - } - - }); - - buttons.put (getUIString (LanguageStrings.buttons,discardchanges), - //"No, discard the changes", - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.closeInternal (false, - afterClose); - - } - - }); - - buttons.put (getUIString (LanguageStrings.buttons,cancel), - null); - - UIUtils.createQuestionPopup (this, - getUIString (closeproject,confirmpopup,title), - //"Save changes before exiting?", - Constants.SAVE_ICON_NAME, - String.format (getUIString (closeproject,confirmpopup,text), - //"The following items have unsaved changes (click on an item to go to the relevant tab):
      %s
    Do you wish to save the changes before exiting?", - b.toString ()), - buttons, - null, - null); - - return false; - - } - - } - - return this.closeInternal (true, - afterClose); - - } - - public FullScreenFrame getFullScreenFrame () - { - - return this.fsf; - - } - - public boolean isCurrentSideBarTextProperties () - { - - if (this.currentOtherSideBar != null) - { - - return this.currentOtherSideBar.getId ().equals (TextPropertiesSideBar.ID); - - } - - return false; - - } - - public void showTextProperties () - throws GeneralException - { - - if (!this.sideBars.containsKey (TextPropertiesSideBar.ID)) - { - - this.addSideBar (new TextPropertiesSideBar (this, - this, - Environment.getProjectTextProperties ())); - - } - - this.showSideBar (TextPropertiesSideBar.ID); - - } - - public QuollPanel getCurrentlyVisibleTab () - { - - if (this.isInFullScreen ()) - { - - // Return the panel being displayed. - return this.fsf.getPanel ().getChild (); - - } - - Component sel = this.tabs.getSelectedComponent (); - - if (sel instanceof QuollPanel) - { - - return (QuollPanel) sel; - - } - - return null; - - } - - /** - * Return the name of the property that is used to save the open tabs, this is needed because is the project - * has a project version object then the name of the property will change. - * - * @return The open tabs property name in the form {@link Constants.OPENS_TAB_PROPERTY_NAME} + [":" + project version key]. - */ - public String getOpenTabsPropertyName () - { - - // See if we have a project version. - ProjectVersion pv = this.proj.getProjectVersion (); - - String suffix = ""; - - if (pv != null) - { - - suffix = ":" + pv.getKey (); - - } - - return Constants.OPEN_TABS_PROPERTY_NAME + suffix; - - } - - private void saveState () - throws GeneralException - { - - if (this.proj == null) - { - - return; - - } - - // Get the state from the sidebars. - for (AbstractSideBar sb : this.sideBars.values ()) - { - - String id = sb.getId (); - - if (id == null) - { - - continue; - - } - - try - { - - this.proj.setProperty ("sidebarState-" + id, - sb.getSaveState ()); - - } catch (Exception e) { - - Environment.logError ("Unable to save state for sidebar: " + - id, - e); - - } - - } - - // Set the open tab ids. - - QuollPanel vqp = this.getCurrentlyVisibleTab (); - - String panelId = null; - - if (vqp != null) - { - - panelId = vqp.getPanelId (); - - } - - // See if we have a project version. - ProjectVersion pv = this.proj.getProjectVersion (); - - String suffix = ""; - - if (pv != null) - { - - suffix = ":" + pv.getKey (); - - } - - // Save it. - try - { - - this.proj.setProperty (Constants.LAST_OPEN_TAB_PROPERTY_NAME + suffix, - panelId); - - } catch (Exception e) - { - - throw new GeneralException ("Unable to save open tab id for project: " + - this.proj, - e); - - } - - StringBuilder openTabs = new StringBuilder (); - - for (int i = 0; i < this.tabs.getTabCount (); i++) - { - - Component p = this.tabs.getComponentAt (i); - - if (p instanceof QuollPanel) - { - - // TODO: Change to add a flag in the QuollPanel of whether it should be persisted. - if (p instanceof HelpTextPanel) - { - - continue; - - } - - QuollPanel qp = (QuollPanel) p; - - panelId = qp.getPanelId (); - - if (openTabs.length () > 0) - { - - openTabs.append (","); - - } - - openTabs.append (panelId); - - } - - } - - try - { - - this.proj.setProperty (this.getOpenTabsPropertyName (), - openTabs.toString ()); - - } catch (Exception e) - { - - throw new GeneralException ("Unable to save open tab ids for project: " + - this.proj, - e); - - } - - // We've drastically changed the size of things due to closing tabs and potentially the - // notifications so validate to ensure the sizes have changed. - this.validate (); - - // Save the size of the window (more specifically the size of the split pane. - try - { - - this.proj.setProperty (Constants.WINDOW_HEIGHT_PROPERTY_NAME, - this.splitPane.getSize ().height); - - this.proj.setProperty (Constants.WINDOW_WIDTH_PROPERTY_NAME, - this.splitPane.getSize ().width); - - this.proj.setProperty (Constants.PROJECT_SIDE_BAR_WIDTH_PROPERTY_NAME, - this.sideBar.getSize ().width); - this.proj.setProperty (Constants.SPELL_CHECKING_ENABLED_PROPERTY_NAME, - this.spellCheckingEnabled); - - } catch (Exception e) - { - - throw new GeneralException ("Unable to save open tab ids for project: " + - this.proj, - e); - - } - - this.doSaveState (); - - this.saveProject (); - - } - - public java.util.List getObjectsForReferences (String objRefs) - { - - java.util.List objs = new ArrayList (); - - StringTokenizer t = new StringTokenizer (objRefs, - ","); - - while (t.hasMoreTokens ()) - { - - String tok = t.nextToken ().trim (); - - ObjectReference r = null; - - try - { - - r = ObjectReference.parseObjectReference (tok); - - } catch (Exception e) - { - - Environment.logError ("Unable to parse: " + - tok, - e); - - continue; - - } - - // Pass it to the project. - DataObject d = this.proj.getObjectForReference (r); - - if (d == null) - { - - continue; - - } - - objs.add (d); - - } - - return objs; - - } - - public Component getVisiblePanel () - { - - return this.tabs.getSelectedComponent (); - - } - - public void enterFullScreen () - { - - try - { - - this.showInFullScreen (this.getCurrentlyVisibleTab ()); - - } catch (Exception e) { - - Environment.logError ("Unable to show in full screen", - e); - - UIUtils.showErrorMessage (this, - getUIString (fullscreen,actionerror)); - //"Unable to enter full screen mode"); - - } - - } - - public void fullScreenClosed (QuollPanel vis) - { - - this.fsf = null; - - this.fullScreenOverlay.setVisible (false); - - DnDTabbedPane p = this.createTabbedPane (); - - // Have to rebuild the tabbed pane because otherwise it behaves weirdly. - for (int i = this.tabs.getTabCount () - 1; i > -1; i--) - { - - Component title = this.tabs.getTabComponentAt (i); - Component body = this.tabs.getComponentAt (i); - - this.tabs.remove (i); - - this.tabs.add (body, - i); - this.tabs.setTabComponentAt (i, - title); - - } - - try - { - - this.tabs.setSelectedComponent (vis); - - } catch (Exception e) { - - // May not exist, don't care. - - } - - this.tabs.setVisible (true); - - if (vis instanceof AbstractEditorPanel) - { - - AbstractEditorPanel edPanel = (AbstractEditorPanel) vis; - - QTextEditor ed = edPanel.getEditor (); - - edPanel.scrollCaretIntoView (); - - ed.grabFocus (); - - } - - this.setVisible (true); - this.setUILayout (this.layout); - this.validate (); - this.repaint (); - - this.fireFullScreenExitedEvent (); - - } - - public void restoreFromFullScreen (FullScreenQuollPanel qp) - { - - for (int i = 0; i < this.tabs.getTabCount (); i++) - { - - Component comp = this.tabs.getComponentAt (i); - - if (comp == qp) - { - - this.tabs.setComponentAt (i, - qp.getChild ()); - - qp.getChild ().setVisible (true); - - this.tabs.revalidate (); - this.tabs.repaint (); - this.validate (); - this.repaint (); - - return; - - } - - } - - this.tabs.setVisible (true); - - } - - public boolean isInFullScreen () - { - - return this.fsf != null; - - } - - public void showInFullScreen (QuollPanel qep) - throws GeneralException - { - - if (this.fsf == null) - { - - // Need to get the divider location. - this.lastDividerLocation = this.splitPane.getDividerLocation (); - - } - - if (this.fullScreenOverlay == null) - { - - this.fullScreenOverlay = new FullScreenOverlay (this); - - this.setGlassPane (this.fullScreenOverlay); - - } - - this.fullScreenOverlay.setVisible (true); - - if (this.fsf != null) - { - - if (this.fsf.getPanel ().getChild () == qep) - { - - // Nothing to do, it's already showing, maybe bring to front. - this.fsf.toFront (); - - return; - - } - - } - - if (qep == null) - { - - qep = new BlankQuollPanel (this, - "fullscreen-blank"); - - qep.init (); - - } - - if (this.currentOtherSideBar != null) - { - - this.savedOtherSideBarWidth = this.currentOtherSideBar.getSize ().width; - - } - - if (this.mainSideBar != null) - { - - this.savedSideBarWidth = this.mainSideBar.getSize ().width; - - } - - FullScreenQuollPanel fs = new FullScreenQuollPanel (qep); - - int tabInd = this.getTabIndexForPanelId (qep.getPanelId ()); - - if (tabInd > -1) - { - - // Need to set the component, otherwise it will be removed. - this.tabs.setComponentAt (tabInd, - fs); - - } - - if (this.fsf != null) - { - - this.fsf.switchTo (fs); - - } else - { - - this.fsf = new FullScreenFrame (fs, - this); - - this.fsf.init (); - - // Need to set the tabs hidden otherwise the parent qw window will flash in front - // or show up in front of the fsf. - this.tabs.setVisible (false); - - } - - //this.fsf.toFront (); - - this.tabs.revalidate (); - this.tabs.repaint (); - this.validate (); - this.repaint (); - - this.setVisible (false); - - this.fireFullScreenEnteredEvent (); - - final AbstractProjectViewer _this = this; - - UIUtils.doLater (new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - if (_this.fsf != null) - { - - _this.fsf.toFront (); - - } - - } - - }); - - } - - public void showInFullScreen (DataObject n) - throws GeneralException - { - - // Are we already in fs mode? - if (this.fsf != null) - { - - if (this.fsf.getCurrentForObject () == n) - { - - // Nothing to do, it's already showing, maybe bring to front. - this.fsf.toFront (); - - return; - - } else - { - - this.viewObject (n); - - } - - } - - if (this.fullScreenOverlay == null) - { - - this.fullScreenOverlay = new FullScreenOverlay (this); - - this.setGlassPane (this.fullScreenOverlay); - - } - - this.fullScreenOverlay.setVisible (true); - - this.lastDividerLocation = this.splitPane.getDividerLocation (); - - AbstractEditorPanel qep = this.getEditorForChapter ((Chapter) n); - - if (qep != null) - { - - FullScreenQuollPanel fs = new FullScreenQuollPanel (qep); - - // Need to set the component, otherwise it will be removed. - this.tabs.setComponentAt (this.getTabIndexForPanelId (qep.getPanelId ()), - fs); - - if (this.fsf != null) - { - - this.fsf.switchTo (fs); - - } else - { - - this.fsf = new FullScreenFrame (fs, - this); - - this.fsf.init (); - - } - - //this.fsf.toFront (); - - this.tabs.revalidate (); - this.tabs.repaint (); - this.validate (); - this.repaint (); - - } - - this.setVisible (false); - - this.fireFullScreenEnteredEvent (); - - } - - public ProjectObjectQuollPanel getQuollPanelForObject (DataObject n) - { - - for (QuollPanel qp : this.panels.values ()) - { - - ProjectObjectQuollPanel pqp = null; - - if (qp instanceof FullScreenQuollPanel) - { - - FullScreenQuollPanel fqp = (FullScreenQuollPanel) qp; - - if (fqp.getChild () instanceof ProjectObjectQuollPanel) - { - - pqp = (ProjectObjectQuollPanel) fqp.getChild (); - - } - - } - - // This is getting silly... - // TODO: Fix this up. - if (qp instanceof ProjectObjectQuollPanel) - { - - pqp = (ProjectObjectQuollPanel) qp; - - } - - if ((pqp != null) - && - (pqp.getForObject () == n) - ) - { - - return pqp; - - } - - } - - return null; - - } - - public java.util.List getAllQuollPanelsForObject (DataObject n) - { - - java.util.List ret = new ArrayList (); - - for (QuollPanel qp : this.panels.values ()) - { - - if (qp instanceof ProjectObjectQuollPanel) - { - - ProjectObjectQuollPanel pqp = (ProjectObjectQuollPanel) qp; - - if (pqp.getForObject () == n) - { - - ret.add (pqp); - - } - - } - - } - - return ret; - - } - - public QuollPanel getQuollPanel (String panelId) - { - - return this.panels.get (panelId); - - } - - protected void setPanelVisible (QuollPanel qp) - { - - this.updateToolbarForPanel (qp); - - if (!this.inFullScreen ()) - { - - this.tabs.setSelectedComponent (qp); - this.tabs.revalidate (); - this.tabs.repaint (); - - } else { - - try - { - - this.showInFullScreen (qp); - - } catch (Exception e) { - - Environment.logError ("Unable to show panel: " + qp + - " in full screen", - e); - - UIUtils.showErrorMessage (this, - getUIString (fullscreen,showpanelactionerror)); - //"Unable to show in full screen"); - - } - - } - - this.fireMainPanelShownEvent (qp); - - } - - protected int getTabIndexForObject (NamedObject n) - { - - return this.getTabIndexForPanelId (n.getObjectReference ().asString ()); - - } - - protected int getTabIndexForPanelId (String panelId) - { - - for (int i = 0; i < this.tabs.getTabCount (); i++) - { - - Component comp = this.tabs.getComponentAt (i); - - if (comp instanceof QuollPanel) - { - - QuollPanel qp = (QuollPanel) comp; - - if (qp.getPanelId ().equals (panelId)) - { - - return i; - - } - - } - - } - - return -1; - - } - - public void setTabHeaderTitle (QuollPanel qp, - String title) - { - - int ind = this.getTabIndexForPanelId (qp.getPanelId ()); - - if (ind < 0) - { - - // No current tab for this panel. - return; - - } - - TabHeader th = (TabHeader) this.tabs.getTabComponentAt (ind); - - if (th != null) - { - - th.setTitle (title); - - } - - } - - public TabHeader addPanel (final QuollPanel qp) - { - - final AbstractProjectViewer _this = this; - - final TabHeader th = new TabHeader (this.tabs, - Environment.getIcon (Constants.CANCEL_ICON_NAME, - Constants.ICON_TAB_HEADER), - Environment.getTransparentImage (), - qp.getTitle ()); - - th.setIcon (qp.getIcon (Constants.ICON_TAB_HEADER)); - - final String panelId = qp.getPanelId (); - - this.panels.put (panelId, - qp); - - th.addActionListener (new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - if (ev.getID () == TabHeader.TAB_CLOSING) - { - - if (!_this.closePanel (qp)) - { - - VetoableActionEvent vev = (VetoableActionEvent) ev; - - vev.cancel (); - - } - - } - - } - - }); - - if (qp instanceof ProjectObjectQuollPanel) - { - - qp.addActionListener (new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - if (ev.getID () == ProjectObjectQuollPanel.UNSAVED_CHANGES_ACTION_EVENT) - { - - if (ev.getActionCommand ().equals (ProjectObjectQuollPanel.HAS_CHANGES_COMMAND)) - { - - th.setComponentChanged (true); - - } - - if (ev.getActionCommand ().equals (ProjectObjectQuollPanel.NO_CHANGES_COMMAND)) - { - - th.setComponentChanged (false); - - } - - } - - if (ev.getID () == ProjectObjectQuollPanel.SAVED) - { - - th.setComponentChanged (false); - - } - - } - - }); - - } - - this.tabs.add (qp, - 0); - this.tabs.setTabComponentAt (0, - th); - - this.initPanelState (qp); - - return th; - - } - - public boolean closePanel (NamedObject n) - { - - QuollPanel qp = this.getQuollPanel (n.getObjectReference ().asString ()); - - if (qp == null) - { - - return false; - - } - - return this.closePanel (qp); - - } - - public boolean closePanel (QuollPanel qp) - { - - // Get the state. - Map m = new LinkedHashMap (); - - qp.getState (m); - - String panelId = qp.getPanelId (); - - if (m.size () > 0) - { - - try - { - - this.proj.setProperty (panelId + "-state", - UIUtils.createState (m)); - - } catch (Exception e) - { - - Environment.logError ("Unable to save state for panel: " + - panelId, - e); - - } - - } - - final AbstractProjectViewer _this = this; - - if (qp instanceof ProjectObjectQuollPanel) - { - - final ProjectObjectQuollPanel p = (ProjectObjectQuollPanel) qp; - - final ActionListener remove = new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - NamedObject n = p.getForObject (); - - if (p != null) - { - - if ((_this.fsf != null) - && - (p == _this.fsf.getPanel ().getChild ()) - ) - { - - // In full screen, restore first. - _this.restoreFromFullScreen (_this.fsf.getPanel ()); - - // Add a blank instead. - _this.fsf.showBlankPanel (); - - } - - _this.removePanel (p); - - // Remove all the property changed listeners. - java.util.List l = p.getObjectPropertyChangedListeners (); - - if (l != null) - { - - for (PropertyChangedListener c : l) - { - - n.removePropertyChangedListener (c); - - } - - } - - } - - } - - }; - - // Object already deleted, don't ask the question. - if ((p.getForObject ().getKey () != null) - && - (!this.proj.hasObject (p.getForObject ())) - ) - { - - remove.actionPerformed (new ActionEvent (this, - 0, - "deleted")); - - return true; - - } - - if (p.hasUnsavedChanges ()) - { - - UIUtils.createQuestionPopup (this, - getUIString (closepanel,confirmpopup,title), - //"Save before closing?", - Constants.SAVE_ICON_NAME, - String.format (getUIString (closepanel,confirmpopup,text), - p.getTitle ()), - //"The %s has unsaved changes. Save before closing?", - //Environment.getObjectTypeName (p.getForObject ())), - getUIString (closepanel,confirmpopup,buttons,save), - //"Yes, save the changes", - getUIString (closepanel,confirmpopup,buttons,discard), - //"No, discard the changes", - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - try - { - - if (!p.saveUnsavedChanges ()) - { - - return; - - } - - } catch (Exception e) - { - - // What the hell to do here??? - Environment.logError ("Unable to save: " + - p.getForObject (), - e); - - UIUtils.showErrorMessage (_this, - getUIString (closepanel,actionerror)); - //"Unable to save " + - //Environment.getObjectTypeName (p.getForObject ())); - - return; - - } - - remove.actionPerformed (ev); - - } - - }, - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - remove.actionPerformed (ev); - - } - - }, - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - if (!p.hasUnsavedChanges ()) - { - - remove.actionPerformed (ev); - - } - - } - - }, - null); - - return false; - - } - - remove.actionPerformed (new ActionEvent (this, - 0, - "deleted")); - - return true; - - } - - return this.removePanel (qp); - - } - - protected void informTreeOfNodeChange (NamedObject n, - JTree tree) - { - - DefaultTreeModel model = (DefaultTreeModel) tree.getModel (); - - DefaultMutableTreeNode node = (DefaultMutableTreeNode) UIUtils.getTreePathForUserObject ((DefaultMutableTreeNode) model.getRoot (), - n).getLastPathComponent (); - - model.nodeChanged (node); - - tree.validate (); - tree.repaint (); - - } - - @Override - public void addPopup (Component c, - boolean hideOnClick, - boolean hideViaVisibility) - { - - if (this.fsf != null) - { - - this.fsf.addPopup (c, - hideOnClick, - hideViaVisibility); - - return; - - } - - super.addPopup (c, - hideOnClick, - hideViaVisibility); - - } - - @Override - public void removePopup (Component c) - { - - if (this.fsf != null) - { - - this.fsf.removePopup (c); - - return; - - } - - super.removePopup (c); - - } - - @Override - public void showAchievement (AchievementRule ar) - { - - if (this.fsf != null) - { - - this.fsf.showAchievement (ar); - - return; - - } - - super.showAchievement (ar); - - } - - @Override - public QPopup getPopupByName (String name) - { - - if (this.fsf != null) - { - - return this.fsf.getPopupByName (name); - - } - - return super.getPopupByName (name); - - } - - @Override - public void showPopupAt (Component popup, - Component showAt, - boolean hideOnParentClick) - { - - if (this.fsf != null) - { - - this.fsf.showPopupAt (popup, - showAt, - hideOnParentClick); - - return; - - } - - super.showPopupAt (popup, - showAt, - hideOnParentClick); - - } - - @Override - public void showPopupAt (Component c, - Point p, - boolean hideOnParentClick) - { - - if (this.fsf != null) - { - - this.fsf.showPopupAt (c, - p, - hideOnParentClick); - - return; - - } - - super.showPopupAt (c, - p, - hideOnParentClick); - - } - - public boolean removePanel (NamedObject n) - { - - return this.removePanel (n.getObjectReference ().asString ()); - - } - - public void removeAllSideBarsForObject (NamedObject n) - { - - Set sbs = new HashSet<> (); - - sbs.addAll (this.sideBars.values ()); - - for (AbstractSideBar s : sbs) - { - - if (n == s.getForObject ()) - { - - this.removeSideBar (s); - - } - - } - - } - - public void removeAllPanelsForObject (NamedObject n) - { - - for (ProjectObjectQuollPanel p : this.getAllQuollPanelsForObject (n)) - { - - this.removePanel (p); - - } - - } - - private boolean removePanel (String panelId) - { - - QuollPanel p = this.getQuollPanel (panelId); - - if (p == null) - { - - return false; - - } - - return this.removePanel (p); - - } - - public boolean removePanel (final QuollPanel p) - { - - p.close (); - - String panelId = p.getPanelId (); - - int tInd = this.getTabIndexForPanelId (panelId); - - if (tInd > -1) - { - - this.tabs.removeTabAt (tInd); - - } - - this.panels.remove (panelId); - - return true; - - } - - public ObjectManager getObjectManager () - { - - return this.dBMan; - - } - - public DataHandler getDataHandler (Class clazz) - throws GeneralException - { - - if (this.dBMan == null) - { - - return null; - - } - - return this.dBMan.getHandler (clazz); - - } - - public void refreshViewPanel (NamedObject n) - { - - ProjectObjectQuollPanel p = this.getQuollPanelForObject (n); - - if (p != null) - { - - p.refresh (); - - } - - } - - public void refreshObjectPanels (final Set objs) - { - - final AbstractProjectViewer _this = this; - - if ((objs != null) && - (objs.size () > 0)) - { - - UIUtils.doLater (new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - // For each one determine if it is visible. - for (NamedObject n : objs) - { - - ProjectObjectQuollPanel qp = _this.getQuollPanelForObject (n); - - if (qp != null) - { - - qp.refresh (); - - } - - } - - } - - }); - - } - - } - - public void deleteLinks (NamedObject o, - boolean doInTransaction) - throws GeneralException - { - - java.util.Set otherObjects = o.getOtherObjectsInLinks (); - - this.dBMan.deleteLinks (o, - null); - - this.refreshObjectPanels (otherObjects); - - } - - public void saveLinks (NamedObject o, - Set newLinks) - throws GeneralException - { - - // Do it here to get all the links that may be removed. - java.util.Set otherObjects = o.getOtherObjectsInLinks (); - - this.dBMan.updateLinks (o, - newLinks); - - // Do it here to get all the links that may be added. - otherObjects.addAll (o.getOtherObjectsInLinks ()); - - this.refreshObjectPanels (otherObjects); - - } - - public void saveObject (NamedObject o, - boolean doInTransaction) - throws GeneralException - { - - if (o == null) - { - - return; - - } - - java.util.Set otherObjects = o.getOtherObjectsInLinks (); - - if (this.dBMan == null) - { - - throw new IllegalStateException ("No object manager available."); - - } - - this.dBMan.saveObject (o, - null); - - this.refreshObjectPanels (otherObjects); - - } - - public void saveObjects (java.util.List objs, - boolean doInTransaction) - throws GeneralException - { - - this.dBMan.saveObjects (objs, - null); - - } - - public void saveProject () - throws GeneralException - { - - this.dBMan.saveObject (this.proj, - null); - - } - - public void setLinks (NamedObject o) - { - - try - { - - this.dBMan.getLinks (o); - - } catch (Exception e) - { - - Environment.logError ("Unable to set links for: " + - o, - e); - - } - - } - - public void propertyChanged (PropertyChangedEvent ev) - { - - DataObject d = (DataObject) ev.getSource (); - - if (d instanceof Project) - { - - Project p = (Project) d; - - try - { - - this.saveObject (p, - true); - - } catch (Exception e) - { - - Environment.logError ("Unable to save project: " + - p, - e); - - } - - } - - } - - public boolean isSpellCheckingEnabled () - { - - return this.spellCheckingEnabled; - - } - - public void setSpellCheckingEnabled (final boolean v) - { - - this.spellCheckingEnabled = v; - - this.doForPanels (SpellCheckSupported.class, - new DefaultQuollPanelAction () - { - - public void doAction (QuollPanel qp) - { - - SpellCheckSupported s = (SpellCheckSupported) qp; - - s.setSpellCheckingEnabled (v); - - } - - }); - - this.fireProjectEvent (ProjectEvent.SPELL_CHECK, - (v ? ProjectEvent.ON : ProjectEvent.OFF)); - - } - - public void createActionLogEntry (NamedObject n, - String m) - { - - this.dBMan.createActionLogEntry (n, - m, - null, - null); - - } - - public boolean inFullScreen () - { - - return this.fsf != null; - - } - - public ReadabilityIndices getReadabilityIndices (Chapter c) - { - - AbstractEditorPanel qep = this.getEditorForChapter (c); - - ReadabilityIndices ri = null; - - if (qep != null) - { - - ri = qep.getReadabilityIndices (); - - if (ri != null) - { - - this.noEditorReadabilityIndices.remove (c); - - return ri; - - } - - } - - ri = this.noEditorReadabilityIndices.get (c); - - if (ri == null) - { - - // Cache the value. - ri = this.getReadabilityIndices (c.getChapterText ()); - - this.noEditorReadabilityIndices.put (c, - ri); - - } - - return ri; - - } - - public ChapterCounts getChapterCounts (Chapter c) - { - - return this.chapterCounts.get (c); - - } - - public ReadabilityIndices getAllReadabilityIndices () - { - - if (this.proj == null) - { - - return null; - - } - - Book b = this.proj.getBooks ().get (0); - - java.util.List chapters = b.getChapters (); - - ReadabilityIndices ri = new ReadabilityIndices (); - - for (Chapter c : chapters) - { - - ri.add (this.getReadabilityIndices (c)); - - } - - return ri; - - } - - private void initChapterCounts () - { - - if (this.proj == null) - { - - return; - - } - - if (this.proj.getBooks ().size () == 0) - { - - return; - - } - - Book b = this.proj.getBooks ().get (0); - - java.util.List chapters = b.getChapters (); - - for (Chapter c : chapters) - { - - this.updateChapterCounts (c); - - } - - this.startWordCounts = this.getAllChapterCounts (); - - } - - public String getCurrentChapterText (Chapter c) - { - - AbstractEditorPanel qep = this.getEditorForChapter (c); - - String t = null; - - if (qep != null) - { - - t = qep.getEditor ().getText (); - - } else { - - t = (c.getText () != null ? c.getText ().getText () : null); - - } - - return t; - - } - - public void updateChapterCounts (final Chapter c) - { - - final AbstractProjectViewer _this = this; - - final String t = this.getCurrentChapterText (c); - - final ChapterCounts cc = new ChapterCounts (t); - - ChapterCounts _cc = this.getChapterCounts (c); - - if (_cc != null) - { - - cc.standardPageCount = _cc.standardPageCount; - - } - - this.chapterCounts.put (c, - cc); - - if (!Environment.isStartupComplete ()) - { - - return; - - } - - // Don't try and calculate the a4 page count before the window is ready otherwise - // strange errors result. The initChapterCounts and scheduleA4PageCountUpdate will handle the initial counts. - this.unschedule (this.chapterCountsUpdater); - - Runnable r = new Runnable () - { - - @Override - public void run () - { - - try - { - - cc.standardPageCount = UIUtils.getA4PageCountForChapter (c, - t); - - } catch (Exception e) { - - Environment.logError ("Unable to get a4 page count for chapter: " + - c, - e); - - } - - } - - }; - - this.chapterCountsUpdater = _this.schedule (r, - // Start in 2 seconds - 2 * Constants.SEC_IN_MILLIS, - // Do it once. - 0); - - } - - public int getChapterA4PageCount (Chapter c) - { - - return UIUtils.getA4PageCountForChapter (c, - this.getCurrentChapterText (c)); - - } - - public ChapterCounts getAllChapterCounts () - { - - ChapterCounts all = new ChapterCounts (); - - for (ChapterCounts cc : this.chapterCounts.values ()) - { - - all.add (cc); - - } - - return all; - - } - - public Set getAllChapterCountsAsSet () - { - - return new LinkedHashSet (this.chapterCounts.values ()); - - } - - private Book getBookCurrentlyEdited () - { - - Chapter c = this.getChapterCurrentlyEdited (); - - if (c != null) - { - - return c.getBook (); - - } - - return this.proj.getBook (0); - - } - - public Chapter getChapterCurrentlyEdited () - { - - Component sel = this.getCurrentlyVisibleTab (); - - if (sel instanceof AbstractEditorPanel) - { - - // Get the id. - AbstractEditorPanel qep = (AbstractEditorPanel) sel; - - // Get the chapter. - return qep.getChapter (); - - } - - return null; - - } - - public boolean showOptions () - { - - return this.showOptions (null); - - } - - public boolean showOptions (final String section) - { - - OptionsPanel p = (OptionsPanel) this.getQuollPanel (OptionsPanel.PANEL_ID); - - if (p == null) - { - - try - { - - p = new OptionsPanel (this, - Options.Section.project, - Options.Section.look, - Options.Section.naming, - Options.Section.editing, - Options.Section.assets, - Options.Section.start, - Options.Section.editors, - Options.Section.itemsAndRules, - Options.Section.warmups, - Options.Section.achievements, - Options.Section.problems, - Options.Section.betas); - - p.init (); - - } catch (Exception e) - { - - Environment.logError ("Unable to view the options", - e); - - UIUtils.showErrorMessage (this, - getUIString (options,actionerror)); - //"Unable to view the options"); - - return false; - - } - - this.addPanel (p); - - } - - this.setPanelVisible (p); - - final OptionsPanel pp = p; - - if (section != null) - { - - UIUtils.doActionWhenPanelIsReady (p, - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - pp.showSection (section); - - } - - }, - null, - null); - - } - - return true; - - } - - @Override - public boolean showChart (String chartType) - throws GeneralException - { - - if (this.viewStatistics ()) - { - - StatisticsPanel sp = (StatisticsPanel) this.getQuollPanel (StatisticsPanel.PANEL_ID); - - sp.showChart (chartType); - - return true; - - } - - return false; - - } - - /** - * This is a top-level action so it can handle showing the user a message, it returns a boolean to indicate - * whether the word count history is viewed. - */ - public boolean viewStatistics () - { - - // Check our tabs to see if we are already viewing the word counts, if so then just switch to it instead. - StatisticsPanel wcp = (StatisticsPanel) this.getQuollPanel (StatisticsPanel.PANEL_ID); - - if (wcp != null) - { - - this.setPanelVisible (wcp); - - this.fireProjectEvent (ProjectEvent.STATISTICS, - ProjectEvent.SHOW); - - return true; - - } - - try - { - - wcp = new StatisticsPanel (this, - new PerChapterWordCountsChart (this), - new AllWordCountsChart (this), - new ReadabilityIndicesChart (this), - new SessionWordCountChart (this), - new SessionTimeChart (this)); - - wcp.init (); - - wcp.showChart (PerChapterWordCountsChart.CHART_TYPE); - - } catch (Exception e) - { - - Environment.logError ("Unable to view word counts: " + - this.proj, - e); - - UIUtils.showErrorMessage (this, - getUIString (statistics,actionerror)); - //"Unable to view statistics panel."); - - return false; - - } - - this.addPanel (wcp); - - // Open the tab :) - return this.viewStatistics (); - - } - - /** - * Determine the number of words written for this project during this session. - * - * @return The current word count - the start word count. - */ - public int getSessionWordCount () - { - - return this.getAllChapterCounts ().wordCount - this.startWordCounts.wordCount; - - } - - public ChapterCounts getStartWordCounts () - { - - return this.startWordCounts; - - } - - public Set snapshotChapters (Set chapters, - ProjectVersion pv) - throws Exception - { - - ChapterDataHandler ch = (ChapterDataHandler) this.dBMan.getHandler (Chapter.class); - - return ch.snapshot (chapters, - pv); - - } - - @Override - public void sendMessageToEditor (final EditorEditor ed) - throws GeneralException - { - - this.viewEditors (); - - final AbstractProjectViewer _this = this; - - UIUtils.doLater (new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - EditorsSideBar sb = (EditorsSideBar) _this.sideBars.get (EditorsSideBar.ID); - - if (sb == null) - { - - Environment.logError ("Cant get editors sidebar?"); - - return; - - } - - try - { - - sb.showChatBox (ed); - - } catch (Exception e) { - - Environment.logError ("Unable to show editor: " + - ed, - e); - - UIUtils.showErrorMessage (_this, - getUIString (editors,vieweditorerror)); - //"Unable to show Editor"); - - } - - } - - }); - - } - - @Override - public void viewEditor (final EditorEditor ed) - throws GeneralException - { - - this.viewEditors (); - - final AbstractProjectViewer _this = this; - - UIUtils.doLater (new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - EditorsSideBar sb = (EditorsSideBar) _this.sideBars.get (EditorsSideBar.ID); - - if (sb == null) - { - - Environment.logError ("Cant get editors sidebar?"); - - return; - - } - - try - { - - sb.showEditor (ed); - - } catch (Exception e) { - - Environment.logError ("Unable to show editor: " + - ed, - e); - - UIUtils.showErrorMessage (_this, - getUIString (editors,vieweditorerror)); - //"Unable to show Editor"); - - } - - } - - }); - - } - - @Override - public boolean viewEditors () - throws GeneralException - { - - // See if the user has an account or has already registered, if so show the sidebar - // otherwise show the register. - if (!EditorsEnvironment.hasRegistered ()) - { - - try - { - - EditorsUIUtils.showRegister (this); - - } catch (Exception e) { - - Environment.logError ("Unable to show editor register", - e); - - UIUtils.showErrorMessage (this, - getUIString (editors,showregistererror)); - //"Unable to show the editors register panel, please contact Quoll Writer support for assistance."); - - return false; - - } - - return true; - - } - - AbstractSideBar sb = this.sideBars.get (EditorsSideBar.ID); - - if (sb == null) - { - - sb = new EditorsSideBar (this); - - this.addSideBar (sb); - - } - - this.showSideBar (EditorsSideBar.ID); - - return true; - - } - - /** - * Set a chapter as edit complete. - * - * Note: this is NOT the right place for this method however there isn't currently a better - * place. It is here because the editor panel may need to use the function and the chapter - * tree might, however the editor panel may not actually exist and putting it in the chapter - * tree means that the chapter tree needs knowledge of panels which isn't correct either (but is worse). - * - * @param chapter The chapter to mark as edit complete. - * @param editComplete Whether the chapter is edit complete or not. - */ - public void setChapterEditComplete (Chapter chapter, - boolean editComplete) - { - - try - { - - chapter.setEditComplete (editComplete); - - AbstractEditorPanel p = (AbstractEditorPanel) this.getEditorForChapter (chapter); - - int pos = 0; - - if (p != null) - { - - pos = Utils.stripEnd (p.getEditor ().getText ()).length (); - - } else { - - String t = (chapter.getText () != null ? chapter.getText ().getText () : ""); - - pos = Utils.stripEnd (t).length (); - - } - - chapter.setEditPosition (pos); - - this.saveObject (chapter, - false); - - this.reloadTreeForObjectType (Chapter.OBJECT_TYPE); - - } catch (Exception e) { - - Environment.logError ("Unable to set chapter edit complete: " + - chapter, - e); - - java.util.List prefix = Arrays.asList (project,editorpanel,actions); - - UIUtils.showErrorMessage (this, - getUIString (prefix,seteditcomplete,actionerror)); - - } - - } - - public void setChapterEditPosition (Chapter chapter, - int textPos) - throws Exception - { - - AbstractEditorPanel p = (AbstractEditorPanel) this.getEditorForChapter (chapter); - - int l = 0; - - if (p != null) - { - - l = Utils.stripEnd (p.getEditor ().getText ()).length (); - - textPos = Math.min (textPos, l); - - // See if we are on the last line (it may be that the user is in the icon - // column). - Rectangle pp = p.getEditor ().modelToView (textPos); - - if (UserProperties.getAsBoolean (Constants.SET_CHAPTER_AS_EDIT_COMPLETE_WHEN_EDIT_POSITION_IS_AT_END_OF_CHAPTER_PROPERTY_NAME)) - { - - if (textPos <= l) - { - - Rectangle ep = p.getEditor ().modelToView (l); - - chapter.setEditComplete ((ep.y == pp.y)); - - } - - } - - } else { - - String t = (chapter.getText () != null ? chapter.getText ().getText () : ""); - - l = Utils.stripEnd (t).length (); - - } - - textPos = Math.min (textPos, l); - - chapter.setEditPosition (textPos); - - this.saveObject (chapter, - false); - - this.reloadTreeForObjectType (Chapter.OBJECT_TYPE); - - } - - public void removeChapterEditPosition (Chapter chapter) - { - - try - { - - chapter.setEditComplete (false); - chapter.setEditPosition (-1); - - this.saveObject (chapter, - false); - - this.reloadTreeForObjectType (Chapter.OBJECT_TYPE); - - } catch (Exception e) { - - Environment.logError ("Unable to remove edit position for chapter: " + - chapter, - e); - - java.util.List prefix = Arrays.asList (project,editorpanel,actions); - - UIUtils.showErrorMessage (this, - getUIString (prefix,removeeditposition,actionerror)); - - } - - } - - @Override - public boolean isEditorsVisible () - { - - return this.isEditorsSideBarVisible (); - - } - - public boolean isEditorsSideBarVisible () - { - - EditorsSideBar sb = (EditorsSideBar) this.sideBars.get (EditorsSideBar.ID); - - if (sb != null) - { - - return sb.isShowing (); - - } - - return false; - - } - - public ProjectVersion getProjectVersion (String name) - throws GeneralException - { - - java.util.List pvs = (java.util.List) this.dBMan.getObjects (ProjectVersion.class, - null, - null, - false); - - for (ProjectVersion pv : pvs) - { - - if (pv.getName ().equalsIgnoreCase (name)) - { - - return pv; - - } - - } - - return null; - - } - - public Set getNotesForVersion (ProjectVersion pv) - throws GeneralException - { - - NoteDataHandler ndh = (NoteDataHandler) this.dBMan.getHandler (Note.class); - - return ndh.getNotesForVersion (pv, - null); - - } - - public Set getDealtWithNotes (ProjectVersion pv, - boolean isDealtWith) - throws GeneralException - { - - NoteDataHandler ndh = (NoteDataHandler) this.dBMan.getHandler (Note.class); - - return ndh.getDealtWith (pv, - isDealtWith, - null); - - } - - @Override - public void showHelpText (String title, - String text, - String iconType, - String helpTextId) - { - - this.addHelpTextTab (title, - text, - iconType, - helpTextId); - - } - - public void addHelpTextTab (String title, - String text, - String iconType, - String panelId) - { - - HelpTextPanel p = new HelpTextPanel (this, - title, - text, - iconType, - panelId); - - p.init (); - - this.addPanel (p); - - this.setPanelVisible (p); - - } - - @Override - public JComponent getTitleHeaderControl (String id) - { - - if (id == null) - { - - return null; - - } - - java.util.List prefix = Arrays.asList (project,title,toolbar,buttons); - - final AbstractProjectViewer _this = this; - - JComponent c = null; - - if (id.equals (FIND_HEADER_CONTROL_ID)) - { - - return UIUtils.createButton (Constants.FIND_ICON_NAME, - Constants.ICON_TITLE_ACTION, - getUIString (prefix,find,tooltip), - //"Click to open the find", - new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.showFind (null); - - } - - }); - - } - - if (id.equals (CLOSE_HEADER_CONTROL_ID)) - { - - return UIUtils.createButton (Constants.CLOSE_ICON_NAME, - Constants.ICON_TITLE_ACTION, - getUIString (prefix,close,tooltip), - //"Click to close", - new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.close (false, - null); - - } - - }); - - } - - if (id.equals (FULL_SCREEN_HEADER_CONTROL_ID)) - { - - return UIUtils.createButton (Constants.FULLSCREEN_ICON_NAME, - Constants.ICON_TITLE_ACTION, - getUIString (prefix,fullscreen,tooltip), - //"Click to work in full screen mode", - new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.enterFullScreen (); - - } - - }); - - } - - return super.getTitleHeaderControl (id); - - } - - @Override - public Set getTitleHeaderControlIds () - { - - Set ids = new LinkedHashSet (); - - ids.add (CONTACTS_HEADER_CONTROL_ID); - ids.add (FIND_HEADER_CONTROL_ID); - ids.add (FULL_SCREEN_HEADER_CONTROL_ID); - ids.add (SETTINGS_HEADER_CONTROL_ID); - - return ids; - - } - - public void scheduleAutoSaveForAllEditors () - { - - this.unschedule (this.autoSaveTask); - - this.autoSaveTask = null; - - if (this.proj.getPropertyAsBoolean (Constants.CHAPTER_AUTO_SAVE_ENABLED_PROPERTY_NAME)) - { - - Properties props = Environment.getDefaultProperties (Project.OBJECT_TYPE); - - final long autoSaveInt = Utils.getTimeAsMillis (props.getProperty (Constants.CHAPTER_AUTO_SAVE_INTERVAL_PROPERTY_NAME)); - - if (autoSaveInt > 0) - { - - final AbstractProjectViewer _this = this; - - // Create our auto save - Runnable r = new Runnable () - { - - @Override - public void run () - { - - try - { - - _this.doForPanels (AbstractEditableEditorPanel.class, - new QuollPanelAction () - { - - @Override - public void doAction (AbstractEditableEditorPanel p) - { - - if (!p.hasUnsavedChanges ()) - { - - return; - - } - - try - { - - p.saveChapter (); - - } catch (Exception e) - { - - Environment.logError ("Unable to auto save chapter: " + - p.getChapter (), - e); - - } - - } - - }); - - } catch (Exception e) { - - Environment.logError ("Unable update panels", - e); - - } - - } - - }; - - this.autoSaveTask = this.schedule (r, - autoSaveInt, - autoSaveInt); - - } - - } - - } - - /** - * Display the targets for the project. - * - */ - public void viewTargets () - throws GeneralException - { - - TargetsSideBar t = new TargetsSideBar (this); - - this.addSideBar (t); - - this.showSideBar (TargetsSideBar.ID); - - } - - public boolean hasUnsavedChapters () - { - - for (QuollPanel qp : this.panels.values ()) - { - - if (qp instanceof AbstractEditorPanel) - { - - AbstractEditorPanel ep = (AbstractEditorPanel) qp; - - if (ep.hasUnsavedChanges ()) - { - - return true; - - } - - } - - } - - return false; - - } - - public Set getChaptersOverReadabilityTarget () - { - - Set chaps = new LinkedHashSet (); - - if (this.getProject () == null) - { - - // Closing down. - return chaps; - - } - - TargetsData projTargets = this.getProjectTargets (); - - int tFK = projTargets.getReadabilityFK (); - int tGF = projTargets.getReadabilityGF (); - - if ((tFK > 0) - || - (tGF > 0) - ) - { - - for (Book book : this.getProject ().getBooks ()) - { - - for (Chapter c : book.getChapters ()) - { - - ReadabilityIndices ri = this.getReadabilityIndices (c); - - ChapterCounts cc = this.getChapterCounts (c); - - if (cc.wordCount < Constants.MIN_READABILITY_WORD_COUNT) - { - - continue; - - } - - float fk = ri.getFleschKincaidGradeLevel (); - float gf = ri.getGunningFogIndex (); - - if ((tFK > 0) - && - (ri.getFleschKincaidGradeLevel () > tFK) - ) - { - - chaps.add (c); - - continue; - - } - - if ((tGF > 0) - && - (ri.getGunningFogIndex () > tGF) - ) - { - - chaps.add (c); - - continue; - - } - - } - - } - - } - - return chaps; - - } - - public Set getChaptersOverWordTarget () - { - - Set chaps = new LinkedHashSet (); - - if (this.getProject () == null) - { - - // Closing down. - return chaps; - - } - - TargetsData projTargets = this.getProjectTargets (); - - int tcc = projTargets.getMaxChapterCount (); - - if (tcc > 0) - { - - for (Book book : this.getProject ().getBooks ()) - { - - for (Chapter c : book.getChapters ()) - { - - ChapterCounts count = this.getChapterCounts (c); - - if (count.wordCount > tcc) - { - - chaps.add (c); - - } - - } - - } - - } - - return chaps; - - } - - public Map> getProblemsForAllChapters () - { - - return this.getProblemsForAllChapters (null); - - } - - public Map> getProblemsForAllChapters (Rule limitToRule) - { - - Map> probs = new LinkedHashMap (); - - if (this.getProject () == null) - { - - // Closing down. - return probs; - - } - - for (Book book : this.getProject ().getBooks ()) - { - - for (Chapter c : book.getChapters ()) - { - - Set issues = null; - - if (limitToRule != null) - { - - issues = this.getProblems (c, - limitToRule); - - } else { - - issues = this.getProblems (c); - - } - - if (issues.size () > 0) - { - - probs.put (c, issues); - - } - - } - - } - - return probs; - - } - - public Set getProblems (Chapter c, - Rule r) - { - - Set ret = new LinkedHashSet (); - - String ct = this.getCurrentChapterText (c); - - if (ct != null) - { - - TextBlockIterator ti = new TextBlockIterator (ct); - - TextBlock b = null; - - while ((b = ti.next ()) != null) - { - - java.util.List issues = RuleFactory.getIssues (b, - r, - this.proj.getProperties ()); - - for (Issue i : issues) - { - - ret.add (i); - - i.setChapter (c); - - } - - } - - } - - return ret; - - } - - public Set getProblems (Chapter c) - { - - Set ret = new LinkedHashSet (); - - String ct = this.getCurrentChapterText (c); - - if (ct != null) - { - - TextBlockIterator ti = new TextBlockIterator (ct); - - TextBlock b = null; - - while ((b = ti.next ()) != null) - { - - if (b instanceof Paragraph) - { - - ret.addAll (RuleFactory.getParagraphIssues ((Paragraph) b, - this.proj.getProperties ())); - - } - - if (b instanceof Sentence) - { - - ret.addAll (RuleFactory.getSentenceIssues ((Sentence) b, - this.proj.getProperties ())); - - } - - } - - } - - return ret; - - } - - public Set getSpellingErrors (Chapter c) - { - - Set ret = new LinkedHashSet (); - - String ct = this.getCurrentChapterText (c); - - if (ct != null) - { - - DictionaryProvider2 dp = this.getDictionaryProvider (); - - if (dp != null) - { - - SpellChecker sc = dp.getSpellChecker (); - - if (sc != null) - { - - TextIterator ti = new TextIterator (ct); - - for (Word w : ti.getWords ()) - { - - if (!sc.isCorrect (w)) - { - - ret.add (w); - - } - - } - - } - - } - - } - - return ret; - - } - - public File getProjectFile (String fileName) - { - - if (fileName == null) - { - - return null; - - } - - return this.proj.getFile (fileName); - - } - - public File getProjectFilesDirectory () - { - - return this.proj.getFilesDirectory (); - - } - - public void saveToProjectFilesDirectory (File file, - String fileName) - throws IOException - { - - this.proj.saveToFilesDirectory (file, - fileName); - - } - - public Map> getTextSnippets (String s) - { - - Map> data = new LinkedHashMap<> (); - - // String name = n.getName ().toLowerCase (); - - java.util.List names = new ArrayList<> (); - names.add (s); - - // Get all the books and chapters. - java.util.List books = this.getProject ().getBooks (); - - for (int i = 0; i < books.size (); i++) - { - - Book b = books.get (i); - - java.util.List chapters = b.getChapters (); - - for (int j = 0; j < chapters.size (); j++) - { - - Chapter c = chapters.get (j); - - AbstractEditorPanel qep = this.getEditorForChapter (c); - - String t = null; - - if (qep != null) - { - - t = qep.getEditor ().getText (); - - } else { - - if (c.getText () != null) - { - - // Get the text. - t = c.getText ().getText (); - - } - - } - - if (t == null) - { - - continue; - - } - - java.util.List snippets = TextUtilities.getTextSnippetsForNames (names, - t); - - if ((snippets != null) && - (snippets.size () > 0)) - { - - data.put (c, - snippets); - - } - - } - - } - - return data; - - } - -} diff --git a/src/com/quollwriter/ui/AbstractViewer.java b/src/com/quollwriter/ui/AbstractViewer.java deleted file mode 100644 index 4e376a46..00000000 --- a/src/com/quollwriter/ui/AbstractViewer.java +++ /dev/null @@ -1,3445 +0,0 @@ -package com.quollwriter.ui; - -import java.awt.*; -import java.awt.dnd.*; -import java.awt.event.*; - -import java.io.*; - -import java.net.*; - -import java.security.*; - -import java.text.*; - -import java.util.ArrayList; -import java.util.Date; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.Set; -import java.util.StringTokenizer; -import java.util.HashSet; -import java.util.LinkedHashSet; -import java.util.WeakHashMap; -import java.util.Collections; -import java.util.Stack; -import java.util.SortedSet; -import java.util.TimerTask; -import java.util.Arrays; -import java.util.concurrent.*; - -import org.w3c.dom.Element; -import org.w3c.dom.Node; - -import javax.sound.sampled.*; - -import javax.swing.*; -import javax.swing.border.*; -import javax.swing.event.*; -import javax.swing.tree.*; -import javax.swing.text.*; - -import com.gentlyweb.properties.*; - -import com.gentlyweb.utils.*; - -import com.jgoodies.forms.builder.*; -import com.jgoodies.forms.factories.*; -import com.jgoodies.forms.layout.*; - -import com.quollwriter.*; - -import com.quollwriter.data.*; - -import com.quollwriter.db.*; -import com.quollwriter.ui.sidebars.*; -import com.quollwriter.ui.forms.*; -import com.quollwriter.ui.panels.*; -import com.quollwriter.events.*; -import com.quollwriter.synonyms.*; - -import com.quollwriter.ui.actionHandlers.*; -import com.quollwriter.ui.components.QPopup; -import com.quollwriter.ui.components.Header; -import com.quollwriter.ui.components.PopupAdapter; -import com.quollwriter.ui.components.PopupEvent; -import com.quollwriter.ui.events.*; -import com.quollwriter.ui.renderers.*; - -import com.quollwriter.data.editors.*; -import com.quollwriter.editors.*; -import com.quollwriter.editors.ui.*; -import com.quollwriter.editors.ui.sidebars.*; - -import com.quollwriter.achievements.rules.*; -import com.quollwriter.achievements.ui.*; - -import static com.quollwriter.LanguageStrings.*; -import static com.quollwriter.Environment.getUIString; - -public abstract class AbstractViewer extends JFrame implements PopupsSupported, - SideBarsSupported, - HTMLPanelActionHandler -{ - - public static final int NEW_PROJECT_ACTION = 1; - public static final int ABOUT_ACTION = 9; // "about"; - public static final int REPORT_BUG_ACTION = 10; // "reportBug"; - public static final int CLOSE_PROJECT_ACTION = 12; // "closeProject"; - public static final int DELETE_PROJECT_ACTION = 13; // "deleteProject"; - public static final int WARMUP_EXERCISE_ACTION = 26; - public static final int CONTACT_SUPPORT_ACTION = 28; - public static final int SHOW_TARGETS_ACTION = 29; - public static final int SHOW_STATISTICS_ACTION = 27; - - public static final String REPORT_BUG_HEADER_CONTROL_ID = "reportBug"; - public static final String CONTACTS_HEADER_CONTROL_ID = "contacts"; - public static final String SETTINGS_HEADER_CONTROL_ID = "settings"; - public static final String DO_WARMUP_HEADER_CONTROL_ID = "doWarmup"; - public static final String REPORT_BETA_BUG_HEADER_CONTROL_ID = "reportBetaBug"; - - private Header title = null; - private DropTarget titleDT = null; - private Box content = null; - private Box notifications = null; - private QPopup achievementsPopup = null; - private Map popups = new HashMap (); - - private ScheduledThreadPoolExecutor generalTimer = null; - - private Timer achievementsHideTimer = null; - - private Tips tips = null; - - private Map tempOptions = new HashMap (); - - private Set projectEventListeners = new HashSet (); - private boolean ignoreProjectEvents = false; - - public AbstractViewer() - { - - final AbstractViewer _this = this; - - this.generalTimer = new ScheduledThreadPoolExecutor (2, - new ThreadFactory () - { - - @Override - public Thread newThread (Runnable r) - { - - Thread t = new Thread (r); - - t.setDaemon (true); - t.setPriority (Thread.MIN_PRIORITY); - t.setName ("Viewer-general-" + t.getId ()); - - return t; - - } - - }); - - this.addWindowListener (new WindowAdapter () - { - - public void windowClosing (WindowEvent ev) - { - - _this.close (false, - null); - - } - - }); - - this.getContentPane ().setBackground (UIUtils.getComponentColor ()); - - this.setDefaultCloseOperation (WindowConstants.DO_NOTHING_ON_CLOSE); - - Box b = new Box (BoxLayout.Y_AXIS); - - this.title = new Header (); - this.title.setAlignmentX (Component.LEFT_ALIGNMENT); - - // new - Header h = this.title; - h.setFont (h.getFont ().deriveFont ((float) UIUtils.getScaledFontSize (22)).deriveFont (Font.PLAIN)); - h.setPaintProvider (null); - h.setTitleColor (UIUtils.getTitleColor ()); - h.setIcon (null); - h.setPadding (new Insets (3, 3, 3, 7)); - - Box tb = new Box (BoxLayout.X_AXIS); - tb.setAlignmentX (Component.LEFT_ALIGNMENT); - tb.add (this.title); - - tb.setBorder (new CompoundBorder (new MatteBorder (0, - 0, - 1, - 0, - Environment.getBorderColor ()), - new EmptyBorder (0, - 5, - 0, - 0) - )); - - b.add (tb); - - // Create the "notifications" area. - this.notifications = new Box (BoxLayout.Y_AXIS); - - this.notifications.setBorder (new MatteBorder (0, 0, 1, 0, UIUtils.getBorderColor ())); - - this.notifications.setVisible (false); - b.add (this.notifications); - - this.content = new Box (BoxLayout.Y_AXIS); - - b.add (this.content); - - try - { - - this.tips = new Tips (this); - - } catch (Exception e) { - - Environment.logError ("Unable to init tips", - e); - - } - - this.getContentPane ().add (b); - - } - - public void init () - throws Exception - { - - final AbstractViewer _this = this; - - InputMap im = this.getInputMap (JComponent.WHEN_IN_FOCUSED_WINDOW); - - im.put (KeyStroke.getKeyStroke (KeyEvent.VK_F12, - InputEvent.CTRL_MASK | InputEvent.ALT_MASK), - "debug"); - im.put (KeyStroke.getKeyStroke (KeyEvent.VK_F1, - InputEvent.CTRL_MASK | InputEvent.ALT_MASK), - "debug-mode"); - - im.put (KeyStroke.getKeyStroke (KeyEvent.VK_F11, - 0), - "whatsnew"); - - ActionMap am = this.getActionMap (); - - this.initKeyMappings (im); - - this.initActionMappings (am); - - final JToolBar titleC = UIUtils.createButtonBar (new ArrayList ()); - - Set tids = this.getTitleHeaderControlIds (); - - if (tids == null) - { - - tids = new LinkedHashSet (); - - } - - if (Environment.getQuollWriterVersion ().isBeta ()) - { - - Set ntids = new LinkedHashSet (); - - ntids.add (REPORT_BETA_BUG_HEADER_CONTROL_ID); - - ntids.addAll (tids); - - tids = ntids; - - } - - final Set ftids = tids; - - for (String s : tids) - { - - JComponent c = this.getTitleHeaderControl (s); - - if (c != null) - { - - c.setName (s); - - titleC.add (c); - - } - - } - - this.title.setControls (titleC); - - this.setIconImage (Environment.getWindowIcon ().getImage ()); - - this.updateForDebugMode (); - - Environment.registerViewer (this); - - } - - public void setTitleHeaderControlsVisible (boolean v) - { - - this.title.getControls ().setVisible (v); - - this.validate (); - this.repaint (); - - } - - public void showViewer () - { - - this.pack (); - - // Allow the underlying Windowing manager determine where to put the window. - this.setLocationByPlatform (true); - - this.setVisible (true); - - Environment.doNewsAndVersionCheck (this); - - this.handleWhatsNew (); - - this.handleShowTips (); - - } - - public JComponent getTitleHeaderControl (String id) - { - - if (id == null) - { - - return null; - - } - - java.util.List prefix = Arrays.asList (project, LanguageStrings.title,toolbar,buttons); - - final AbstractViewer _this = this; - - JComponent c = null; - - if (id.equals (DO_WARMUP_HEADER_CONTROL_ID)) - { - - c = UIUtils.createButton (Constants.WARMUPS_ICON_NAME, - Constants.ICON_TITLE_ACTION, - getUIString (prefix,warmup,tooltip), - //"Click to do a new {Warmup} exercise", - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - _this.showWarmupPromptSelect (); - - } - - }); - - } - - if (id.equals (REPORT_BUG_HEADER_CONTROL_ID)) - { - - c = UIUtils.createButton (Constants.BUG_ICON_NAME, - Constants.ICON_TITLE_ACTION, - getUIString (prefix,bug,tooltip), - //"Click to report a bug/problem", - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - _this.showReportProblem (); - - } - - }); - - } - - if (id.equals (REPORT_BETA_BUG_HEADER_CONTROL_ID)) - { - - c = UIUtils.createButton (Constants.BUG_ICON_NAME, - Constants.ICON_TITLE_ACTION, - getUIString (prefix,betabug,tooltip), - // "Click to report a bug/problem with the beta", - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - _this.showReportProblem (); - - } - - }); - - } - - if (id.equals (CONTACTS_HEADER_CONTROL_ID)) - { - - if (EditorsEnvironment.isEditorsServiceAvailable ()) - { - - String type = LanguageStrings.showcontacts; - - if (!EditorsEnvironment.hasRegistered ()) - { - - type = LanguageStrings.editorsserviceregister; - - } - - //String toolTip = (EditorsEnvironment.hasRegistered () ? "Click to show my {contacts}" : "Click to register for the Editors Service."); - - c = UIUtils.createButton (Constants.EDITORS_ICON_NAME, - Constants.ICON_TITLE_ACTION, - getUIString (prefix,type,tooltip), - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - if ((_this.isEditorsVisible ()) - && - (!EditorsEnvironment.isUserLoggedIn ()) - ) - { - - EditorsEnvironment.goOnline (null, - null, - null, - null); - - return; - - } - - try - { - - _this.viewEditors (); - - } catch (Exception e) { - - Environment.logError ("Unable to view editors", - e); - - UIUtils.showErrorMessage (_this, - getUIString (project,actions,vieweditors,actionerror)); - //"Unable to show the {editors}."); - - } - - } - - }); - - } - - } - - if (id.equals (SETTINGS_HEADER_CONTROL_ID)) - { - - c = UIUtils.createButton (Constants.SETTINGS_ICON_NAME, - Constants.ICON_TITLE_ACTION, - getUIString (prefix,projectmenu,tooltip), - //"Click to view the {Project} menu", - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - final JPopupMenu titlePopup = new JPopupMenu (); - - try - { - - _this.fillSettingsPopup (titlePopup); - - } catch (Exception e) - { - - Environment.logError ("Unable to fill popup", - e); - - } - - titlePopup.addSeparator (); - - JMenuItem mi = null; - - java.util.List prefix = Arrays.asList (project,settingsmenu,items); - - titlePopup.add (_this.createMenuItem (getUIString (prefix,options), - //"Options", - Constants.OPTIONS_ICON_NAME, - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - _this.showOptions (null); - - } - - })); - - titlePopup.add (_this.createMenuItem (getUIString (prefix,achievements), - //"Achievements", - Constants.ACHIEVEMENT_ICON_NAME, - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - _this.viewAchievements (); - - } - - })); - - titlePopup.addSeparator (); - - titlePopup.add (_this.createMenuItem (getUIString (prefix,whatsnew), - //"What's New in this version", - Constants.WHATS_NEW_ICON_NAME, - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - _this.showWhatsNew (true); - - } - - })); - - // Help - JMenu m = new JMenu (getUIString (prefix,help)); - //"Help"); - m.setIcon (Environment.getIcon (Constants.HELP_ICON_NAME, - Constants.ICON_MENU)); - - titlePopup.add (m); - - // Report Bug/Problem - m.add (_this.createMenuItem (getUIString (prefix,reportbug), - Constants.BUG_ICON_NAME, - AbstractProjectViewer.REPORT_BUG_ACTION)); - - // Contact Support - m.add (_this.createMenuItem (getUIString (prefix,contactsupport), - Constants.EMAIL_ICON_NAME, - AbstractProjectViewer.CONTACT_SUPPORT_ACTION)); - - // View the User Guide - m.add (_this.createMenuItem (getUIString (prefix,viewuserguide), - //"View the User Guide", - Constants.HELP_ICON_NAME, - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - UIUtils.openURL (_this, - "help:index"); - - } - - })); - - m.add (_this.createMenuItem (getUIString (prefix,keyboardshortcuts), - //"Keyboard Shortcuts", - null, - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - UIUtils.openURL (_this, - "help:main-window/keyboard-shortcuts"); - - } - - })); - - // About Quoll Writer - titlePopup.add (_this.createMenuItem (getUIString (prefix,about), - //"About Quoll Writer", - Constants.ABOUT_ICON_NAME, - AbstractProjectViewer.ABOUT_ACTION)); - - if (Environment.isDebugModeEnabled ()) - { - - // Debug Console - titlePopup.add (_this.createMenuItem ("Debug Console", - Constants.CONSOLE_ICON_NAME, - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - new DebugConsole (_this); - - } - - })); - - } - - JComponent s = (JComponent) ev.getSource (); - - titlePopup.show (s, - s.getWidth () / 2, - s.getHeight ()); - - - } - - }); - - } - - return c; - - } - - public abstract boolean showOptions (String section); - - public abstract Set getTitleHeaderControlIds (); - - public abstract JPopupMenu getShowOtherSideBarsPopupSelector (); - - public abstract int getActiveSideBarCount (); - - public abstract AbstractSideBar getActiveOtherSideBar (); - - public abstract void addSideBarListener (SideBarListener l); - - public abstract void removeSideBarListener (SideBarListener l); - - public abstract void closeSideBar (); - - public abstract boolean viewAchievements (); - - public abstract boolean isEditorsVisible (); - - public abstract void viewTargets () - throws GeneralException; - - public abstract void viewEditor (EditorEditor ed) - throws GeneralException; - - public abstract boolean viewEditors () - throws GeneralException; - - public abstract void sendMessageToEditor (EditorEditor ed) - throws GeneralException; - - public abstract boolean showChart (String chartType) - throws GeneralException; - - public abstract boolean viewStatistics () - throws GeneralException; - - public void setContent (JComponent content) - { - - content.setAlignmentX (Component.LEFT_ALIGNMENT); - - this.content.add (content); - - } - - public void showContactSupport () - { - - final AbstractViewer _this = this; - - java.util.List prefix = Arrays.asList (project,actions,contactsupport); - - String popupName = "contactsupport"; - QPopup popup = this.getNamedPopup (popupName); - - if (popup == null) - { - - popup = UIUtils.createClosablePopup (getUIString (prefix, LanguageStrings.popup, LanguageStrings.title), - //"Contact Support", - Environment.getIcon (Constants.EMAIL_ICON_NAME, - Constants.ICON_POPUP), - null); - - final QPopup qp = popup; - - popup.setPopupName (popupName); - - this.addNamedPopup (popupName, - popup); - - Box content = new Box (BoxLayout.Y_AXIS); - - JTextPane help = UIUtils.createHelpTextPane (getUIString (prefix, LanguageStrings.popup,text), - //"Use the form below to contact Quoll Writer support. If you wish to receive a response then please provide an email address.", - this); - - help.setBorder (null); - - content.add (help); - content.add (Box.createVerticalStrut (10)); - - String errText = getUIString (prefix, LanguageStrings.popup,errorlabel); - - final JLabel error = UIUtils.createErrorLabel (errText); - //"Please enter a message."); - error.setVisible (false); - error.setBorder (UIUtils.createPadding (0, 0, 5, 5)); - - content.add (error); - - final MultiLineTextFormItem desc = new MultiLineTextFormItem (getUIString (prefix, LanguageStrings.popup,message,text), - //"Message", - getUIString (prefix, LanguageStrings.popup,message,tooltip), - //"Enter your message here.", - 10, - 10000, - false, - null); - - final TextFormItem email = new TextFormItem (getUIString (prefix, LanguageStrings.popup, LanguageStrings.email,text), - null); - - Set items = new LinkedHashSet (); - - items.add (desc); - items.add (email); - - ActionListener sendAction = new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - error.setVisible (false); - - String emErr = Utils.checkEmail (email.getText ()); - - if (emErr != null) - { - - error.setText (emErr); - - error.setVisible (true); - - qp.resize (); - - return; - - } - - if (desc.getText ().trim ().equals ("")) - { - - error.setText (errText); - error.setVisible (true); - - qp.resize (); - - return; - - } - - qp.resize (); - - // Send the message. - Map details = new HashMap (); - details.put ("details", - "Email: " + email.getText () + "\nDetails: " + desc.getText ()); - details.put ("email", - email.getText ()); - - try - { - - Environment.sendMessageToSupport ("contact", - details, - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - desc.setText (""); - - UIUtils.showMessage ((PopupsSupported) _this, - getUIString (prefix,confirmpopup, LanguageStrings.title), - //"Message sent", - getUIString (prefix,confirmpopup,text)); - //"Your request has been logged with Quoll Writer support. If you provided an email address then you should get a response within 1-2 days. If not feel then free to send the message again."); - - _this.fireProjectEvent (ProjectEvent.CONTACT, - ProjectEvent.SUBMIT); - - } - - }); - - } catch (Exception e) - { - - Environment.logError ("Unable to send message to support", - e); - - UIUtils.showErrorMessage (_this, - getUIString (prefix,actionerror)); - //"Unable to send message."); - - } - - qp.removeFromParent (); - - } - - }; - - UIUtils.addDoActionOnReturnPressed (desc.getTextArea (), - sendAction); - UIUtils.addDoActionOnReturnPressed (email.getTextField (), - sendAction); - - JButton send = UIUtils.createButton (getUIString (prefix, LanguageStrings.popup, LanguageStrings.buttons, LanguageStrings.send), - //"Send", - sendAction); - JButton cancel = UIUtils.createButton (getUIString (prefix, LanguageStrings.popup, LanguageStrings.buttons, LanguageStrings.cancel), - //Constants.CANCEL_BUTTON_LABEL_ID, - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - qp.removeFromParent (); - - } - - }); - - Set buttons = new LinkedHashSet (); - buttons.add (send); - buttons.add (cancel); - - Form f = new Form (Form.Layout.stacked, - items, - buttons); - - content.add (f); - - content.setSize (new Dimension (UIUtils.getPopupWidth () - 20, - content.getPreferredSize ().height)); - content.setBorder (UIUtils.createPadding (10, 10, 10, 10)); - - popup.setContent (content); - - popup.setDraggable (this); - - popup.resize (); - this.showPopupAt (popup, - UIUtils.getCenterShowPosition (this, - popup), - false); - - UIUtils.doLater (new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - desc.grabFocus (); - - } - - }); - - } else { - - popup.setVisible (true); - - - } - } - - public void showReportProblem () - { - - final AbstractViewer _this = this; - - java.util.List prefix = Arrays.asList (project,actions,reportproblem); - - String popupName = "bugreport"; - QPopup popup = this.getNamedPopup (popupName); - - if (popup == null) - { - - popup = UIUtils.createClosablePopup (getUIString (prefix, LanguageStrings.popup, LanguageStrings.title), - //"Report a Bug/Problem", - Environment.getIcon (Constants.BUG_ICON_NAME, - Constants.ICON_POPUP), - null); - - Box content = new Box (BoxLayout.Y_AXIS); - - JTextPane help = UIUtils.createHelpTextPane (getUIString (prefix, LanguageStrings.popup,text), - //"Complete the form below to report a bug/problem. The email address is optional, only provide it if you would like a response.

    The operating system you are using and the Java version will also be sent (it helps with debugging). No personal information will be sent.

    Please consider checking the box to send a screenshot, it helps a lot.", - this); - - help.setBorder (null); - - content.add (help); - content.add (Box.createVerticalStrut (10)); - - String errLabel = getUIString (prefix, LanguageStrings.popup,errorlabel); - - final JLabel error = UIUtils.createErrorLabel (errLabel); - //"Please enter a description."); - error.setVisible (false); - error.setBorder (UIUtils.createPadding (0, 5, 5, 5)); - - content.add (error); - - final MultiLineTextFormItem desc = new MultiLineTextFormItem (getUIString (prefix, LanguageStrings.popup,description,text), - //"Description", - getUIString (prefix, LanguageStrings.popup,description,tooltip), - //"Enter the bug/problem description here. The more information you can provide the better.", - 10, - 10000, - false, - null); - - final TextFormItem email = new TextFormItem (getUIString (prefix, LanguageStrings.popup, LanguageStrings.email,text), - //"Email", - null); - - Set items = new LinkedHashSet (); - - items.add (desc); - items.add (email); - - final JCheckBox sendLogFiles = UIUtils.createCheckBox (getUIString (prefix, LanguageStrings.popup,sendlogfiles,text)); - //"Send the log files"); - - items.add (new AnyFormItem (null, - sendLogFiles)); - - final JCheckBox sendScreenshot = UIUtils.createCheckBox (getUIString (prefix, LanguageStrings.popup,sendscreenshot,text)); - //"Send a screenshot of current window"); - - sendScreenshot.setToolTipText (getUIString (prefix, LanguageStrings.popup,sendscreenshot,tooltip)); - //"Takes a screenshot of the current window and sends it to support. If you have information you would prefer not to share then please change the tab before sending. Uncheck to not send a screenshot, but please remember a picture is worth 1,000 (and more) words."); - - items.add (new AnyFormItem (null, - sendScreenshot)); - - sendScreenshot.setSelected (false); - sendScreenshot.setOpaque (false); - sendScreenshot.setAlignmentX (java.awt.Component.LEFT_ALIGNMENT); - - if (Environment.getQuollWriterVersion ().isBeta ()) - { - - sendLogFiles.setEnabled (false); - sendLogFiles.setToolTipText ("Log files are always sent for beta versions, it really helps with debugging."); - - } - - sendLogFiles.setSelected (true); - sendLogFiles.setOpaque (false); - sendLogFiles.setAlignmentX (java.awt.Component.LEFT_ALIGNMENT); - - final QPopup qp = popup; - - ActionListener sendAction = new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - error.setVisible (false); - - String emErr = Utils.checkEmail (email.getText ()); - - if (emErr != null) - { - - error.setText (emErr); - - error.setVisible (true); - - qp.resize (); - - return; - - } - - if (desc.getText ().trim ().equals ("")) - { - - error.setText (errLabel); - //"Please enter a description of the problem/bug."); - error.setVisible (true); - - qp.resize (); - - return; - - } - - qp.resize (); - - qp.removeFromParent (); - - StringBuilder dets = new StringBuilder ("Email: " + email.getText () + "\nDetails: " + desc.getText ()); - - // TODO: Fix this, have a toString on project viewer instead. - if (_this instanceof AbstractProjectViewer) - { - - Project proj = ((AbstractProjectViewer) _this).getProject (); - - dets.append ("\nCurrent project id: " + proj.getId ()); - - } - - // Send the message. - Map details = new HashMap (); - details.put ("details", - dets.toString ()); - - details.put ("email", - email.getText ()); - - try - { - - // Get the log files? - if (sendLogFiles.isSelected ()) - { - - details.put ("errorLog", - IOUtils.getFile (Environment.getErrorLogFile ())); - details.put ("editorsMessageLog", - IOUtils.getFile (EditorsEnvironment.getEditorsMessageLogFile ())); - - } - - if (sendScreenshot.isSelected ()) - { - - details.put ("screenshot", - Base64.encodeBytes (UIUtils.getImageBytes (UIUtils.getImageOfComponent (_this, - _this.getSize ().width, - _this.getSize ().height)))); - - } - - Environment.sendMessageToSupport ("bug", - details, - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - desc.setText (""); - - UIUtils.showMessage ((PopupsSupported) _this, - getUIString (prefix,confirmpopup, LanguageStrings.title), - //"Problem/Bug reported", - getUIString (prefix,confirmpopup,text)); - //"Thank you, the problem has been logged with Quoll Writer support. If you provided an email address then you should get a response within 1-2 days. If not feel then free to send the message again."); - - _this.fireProjectEvent (ProjectEvent.BUG_REPORT, - ProjectEvent.SUBMIT); - - } - - }); - - } catch (Exception e) - { - - Environment.logError ("Unable to send message to support", - e); - - UIUtils.showErrorMessage (_this, - getUIString (prefix,actionerror)); - //"Unable to send message."); - - } - - } - - }; - - UIUtils.addDoActionOnReturnPressed (desc.getTextArea (), - sendAction); - UIUtils.addDoActionOnReturnPressed (email.getTextField (), - sendAction); - - JButton send = UIUtils.createButton (getUIString (prefix, LanguageStrings.popup, LanguageStrings.buttons, LanguageStrings.send), - //"Send", - sendAction); - JButton cancel = UIUtils.createButton (getUIString (prefix, LanguageStrings.popup, LanguageStrings.buttons, LanguageStrings.cancel), - //Constants.CANCEL_BUTTON_LABEL_ID, - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - qp.removeFromParent (); - - } - - }); - - Set buttons = new LinkedHashSet (); - buttons.add (send); - buttons.add (cancel); - - Form f = new Form (Form.Layout.stacked, - items, - buttons); - - content.add (f); - - content.setSize (new Dimension (UIUtils.getPopupWidth () - 20, - content.getPreferredSize ().height)); - content.setBorder (UIUtils.createPadding (10, 10, 10, 10)); - - popup.setContent (content); - - popup.setDraggable (this); - - popup.setPopupName (popupName); - - this.addNamedPopup (popupName, - popup); - - popup.resize (); - this.showPopupAt (popup, - UIUtils.getCenterShowPosition (this, - popup), - false); - - UIUtils.doLater (new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - desc.grabFocus (); - - } - - }); - - } else { - - popup.setVisible (true); - - } - - } - - public void initActionMappings (ActionMap am) - { - - final AbstractViewer _this = this; - - am.put ("show-options", - new AbstractAction () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - _this.showOptions (null); - - } - - }); - - am.put ("do-warmup", - new AbstractAction () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.getAction (AbstractViewer.WARMUP_EXERCISE_ACTION).actionPerformed (ev); - - } - - }); - - am.put ("debug", - new AbstractAction () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - new DebugConsole (_this); - - } - - }); - - am.put ("debug-mode", - new AbstractAction () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - Environment.setDebugModeEnabled (!Environment.isDebugModeEnabled ()); - - _this.updateForDebugMode (); - - // Add a notification. - _this.addNotification ((Environment.isDebugModeEnabled () ? getUIString (debugmode, LanguageStrings.enabled) : getUIString (debugmode,disabled)), - Constants.BUG_ICON_NAME, - 10); - - } - - }); - - am.put ("whatsnew", - new AbstractAction () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - UserProperties.set (Constants.WHATS_NEW_VERSION_VIEWED_PROPERTY_NAME, - "0"); - - _this.showWhatsNew (true); - - } - - }); - - am.put ("contact", - new AbstractAction () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - _this.showContactSupport (); - - } - - }); - - am.put ("editobjectnames", - new AbstractAction () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - _this.showObjectTypeNameChanger (); - - } - - }); - - am.put ("vieweditors", - new AbstractAction () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - try - { - - _this.viewEditors (); - - } catch (Exception e) { - - Environment.logError ("Unable to show editors", - e); - - UIUtils.showErrorMessage (_this, - getUIString (editors,vieweditorserror)); - - } - - } - - }); - - } - - private void updateForDebugMode () - { - - String iconName = this.getViewerIcon (); - - if (Environment.isDebugModeEnabled ()) - { - - iconName = Constants.BUG_ICON_NAME; - - } - - this.title.setIcon (Environment.getIcon (iconName, - Constants.ICON_TITLE)); - - } - - public void initKeyMappings (InputMap im) - { - - im.put (KeyStroke.getKeyStroke (KeyEvent.VK_F3, - 0), - "show-options"); - - im.put (KeyStroke.getKeyStroke (KeyEvent.VK_F7, - 0), - "vieweditors"); - im.put (KeyStroke.getKeyStroke (KeyEvent.VK_F10, - 0), - "do-warmup"); - - } - - protected JMenuItem createMenuItem (String label, - String icon, - int action) - { - - return UIUtils.createMenuItem (label, - icon, - this.getAction (action)); - - } - - protected JMenuItem createMenuItem (String label, - String icon, - ActionListener action) - { - - return UIUtils.createMenuItem (label, - icon, - action); - - } - - public Map getTempOptions () - { - - return this.tempOptions; - - } - - public boolean hasTempOption (String name) - { - - return this.getTempOption (name) != null; - - } - - public boolean isTempOption (String name) - { - - Object o = this.getTempOption (name); - - if (o == null) - { - - return false; - - } - - if (o instanceof Boolean) - { - - return ((Boolean) o).booleanValue (); - - } - - return false; - - } - - public Object getTempOption (String name) - { - - return this.tempOptions.get (name); - - } - - public void setTempOption (String name, - Object value) - { - - this.tempOptions.put (name, - value); - - } - - public abstract void showHelpText (String title, - String text, - String iconType, - String helpTextId); - - //public abstract String getViewerTitle (); - - public abstract String getViewerIcon (); - - public abstract void fillSettingsPopup (JPopupMenu popup); - - public abstract void doSaveState (); - - public ActionMap getActionMap () - { - - return this.content.getActionMap (); - - } - - public InputMap getInputMap (int m) - { - - return this.content.getInputMap (m); - - } - - public Notification addNotification (JComponent comp, - String iconType, - int duration) - { - - return this.addNotification (comp, - iconType, - duration, - null); - - } - - /** - * Adds a notification to the notification area, the action listener can be used - * to remove the notification, it can be safely called with a null event. - * - * @param comp The component to add to the notification. - * @param iconType The type of notification, supported values are "information" and "notify". - * @param duration The time, in seconds, that the notification should be shown for, if less than 1 then - * the notification won't be auto removed. - * @return An action listener that can be called to remove the notification. - */ - public Notification addNotification (JComponent comp, - String iconType, - int duration, - java.util.List buttons) - { - - final AbstractViewer _this = this; - - Notification n = new Notification (comp, - iconType, - duration, - buttons, - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - Notification n = (Notification) ev.getSource (); - - _this.removeNotification (n); - - } - - }); - - this.addNotification (n); - - return n; - - } - - public void removeAllNotifications () - { - - for (int i = 0; i < this.notifications.getComponentCount (); i++) - { - - Notification n = (Notification) this.notifications.getComponent (i); - - this.removeNotification (n); - - } - - } - - public void removeNotification (Notification n) - { - - // Remove the box. - this.notifications.remove (n); - - if (this.notifications.getComponentCount () == 0) - { - - this.notifications.setVisible (false); - - } else { - - int c = this.notifications.getComponentCount (); - - JComponent jc = (JComponent) this.notifications.getComponent (c - 1); - - Border b = jc.getBorder (); - - // Eek, not good but ok for now. - // TODO: Fix this nasty. - if (b instanceof CompoundBorder) - { - - CompoundBorder cb = (CompoundBorder) b; - - jc.setBorder (cb.getInsideBorder ()); - - } - - } - - this.notifications.getParent ().validate (); - this.notifications.getParent ().repaint (); - - } - - public void addNotification (Notification n) - { - - if (this.notifications.getComponentCount () > 0) - { - - n.setBorder (new CompoundBorder (UIUtils.createBottomLineWithPadding (0, 0, 1, 0), - n.getBorder ())); - - } - - this.notifications.add (n, - 0); - - this.notifications.setVisible (true); - - n.init (); - - this.notifications.setMaximumSize (new Dimension (Short.MAX_VALUE, - this.notifications.getPreferredSize ().height)); - - } - - public Notification addNotification (String text, - String type, - int duration) - { - - return this.addNotification (text, - type, - duration, - null); - - } - - public Notification addNotification (String text, - String type, - int duration, - HyperlinkListener clickListener) - { - - JTextPane p = UIUtils.createHelpTextPane (text, - this); - - p.setMaximumSize (new Dimension (Short.MAX_VALUE, - Short.MAX_VALUE)); - p.setBorder (null); - - if (clickListener != null) - { - - p.addHyperlinkListener (clickListener); - - } - - return this.addNotification (p, - type, - duration); - - } - - public Action getAction (int name) - { - - final AbstractViewer _this = this; - - if (name == AbstractViewer.SHOW_STATISTICS_ACTION) - { - - return new AbstractAction () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - try - { - - _this.viewStatistics (); - - } catch (Exception e) { - - Environment.logError ("Unable to view the statistics", - e); - - UIUtils.showErrorMessage (_this, - getUIString (statistics,actionerror)); - //"Unable to view the statistics"); - - } - - } - - }; - - } - - if (name == AbstractViewer.WARMUP_EXERCISE_ACTION) - { - - return new AbstractAction () - { - - @Override - public void actionPerformed (final ActionEvent ev) - { - - _this.showWarmupPromptSelect (); - - } - - }; - - } - - if (name == AbstractViewer.REPORT_BUG_ACTION) - { - - return new AbstractAction () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - _this.showReportProblem (); - - } - - }; - - } - - if (name == AbstractViewer.CONTACT_SUPPORT_ACTION) - { - - return new AbstractAction () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - _this.showContactSupport (); - - } - - }; - - } - - if (name == AbstractViewer.ABOUT_ACTION) - { - - return new AbstractAction () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - _this.showAbout (); - - } - - }; - - } - - if (name == AbstractViewer.SHOW_TARGETS_ACTION) - { - - return new AbstractAction () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - try - { - - _this.viewTargets (); - - } catch (Exception e) { - - Environment.logError ("Unable to view targets", - e); - - UIUtils.showErrorMessage (_this, - getUIString (targets,actionerror)); - //"Unable to view targets."); - - } - - } - - }; - - } - - return null; - - } - - public void showWarmupPromptSelect () - { - - final QPopup qp = UIUtils.createClosablePopup (getUIString (dowarmup,popup, LanguageStrings.title), - //"Do a {Warmup} Exercise", - Environment.getIcon (Warmup.OBJECT_TYPE, - Constants.ICON_POPUP), - null); - - WarmupPromptSelect w = new WarmupPromptSelect (this); - - w.init (); - - w.setSize (new Dimension (UIUtils.getPopupWidth () - 20, - qp.getPreferredSize ().height)); - - w.setBorder (UIUtils.createPadding (10, 10, 10, 10)); - - qp.setContent (w); - - qp.setDraggable (this); - - qp.resize (); - - this.addNamedPopup ("warmup", - qp); - - this.showPopupAt (qp, - UIUtils.getCenterShowPosition (this, - qp), - false); - - UIUtils.doLater (new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - qp.resize (); - - } - - }); - - } - - public void setViewerTitle (String t) - { - - //t = Environment.replaceObjectNames (t); - - this.title.setTitle (t); - - UIUtils.setFrameTitle (this, - t); - - } - - private void handleWhatsNew () - { - - boolean showWhatsNew = false; - - String whatsNewVersion = UserProperties.get (Constants.WHATS_NEW_VERSION_VIEWED_PROPERTY_NAME); - //Environment.getProperty (Constants.WHATS_NEW_VERSION_VIEWED_PROPERTY_NAME); - - if (whatsNewVersion != null) - { - - Version lastViewed = new Version (whatsNewVersion); - - if (lastViewed.isNewer (Environment.getQuollWriterVersion ())) - { - - showWhatsNew = true; - - } - - } - - if (showWhatsNew) - { - - this.showWhatsNew (false); - - } - - } - - public void addNamedPopup (String name, - QPopup popup) - { - - QPopup qp = this.popups.get (name); - - if (qp != null) - { - - qp.removeFromParent (); - - } - - this.popups.put (name, - popup); - - } - - public void removeNamedPopup (String name) - { - - QPopup qp = this.popups.remove (name); - - if (qp != null) - { - - qp.removeFromParent (); - - } - - } - - public QPopup getNamedPopup (String name) - { - - return this.popups.get (name); - - } - - public void showAbout () - { - - final AbstractViewer _this = this; - - java.util.List prefix = Arrays.asList (about,popup); - - String popupName = "about"; - - QPopup popup = this.getNamedPopup (popupName); - - if (popup == null) - { - - final QPopup qp = UIUtils.createClosablePopup (getUIString (prefix, LanguageStrings.title), - Environment.getIcon (Constants.ABOUT_ICON_NAME, - Constants.ICON_POPUP), - null); - - qp.addPopupListener (new PopupAdapter () - { - - @Override - public void popupHidden (PopupEvent ev) - { - - _this.removeNamedPopup ("about"); - - } - - }); - - Box content = new Box (BoxLayout.Y_AXIS); - - FormLayout pfl = new FormLayout ("5px, right:p, 6px, fill:p:grow", - "p, 6px, p, 6px, p, 6px, p, 6px, p, 6px, p, 6px, p, 6px, p, 6px, p, 6px, p"); /*, 6px, p");*/ - - PanelBuilder pbuilder = new PanelBuilder (pfl); - - CellConstraints cc = new CellConstraints (); - - int y = 1; - - pbuilder.addLabel (getUIString (prefix,qwversion), - //"Version", - cc.xy (2, - y)); - - pbuilder.addLabel (Environment.getQuollWriterVersion ().getVersion (), - cc.xy (4, - y)); - - y += 2; - - pbuilder.addLabel (getUIString (prefix,copyright), - //"Copyright", - cc.xy (2, - y)); - - Date d = new Date (); - - SimpleDateFormat sdf = new SimpleDateFormat ("yyyy"); - - String year = sdf.format (d); - - pbuilder.addLabel (String.format (Environment.getProperty (Constants.COPYRIGHT_PROPERTY_NAME), - year), - cc.xy (4, - y)); - - y += 2; - - pbuilder.addLabel (getUIString (prefix,website), - //"Website", - cc.xy (2, - y)); - - pbuilder.add (UIUtils.createWebsiteLabel (Environment.getQuollWriterWebsite (), - null, - false), - cc.xy (4, - y)); - - y += 2; - - pbuilder.addLabel (getUIString (prefix,sourcecode), - //"Source Code", - cc.xy (2, - y)); - - pbuilder.add (UIUtils.createWebsiteLabel (Environment.getProperty (Constants.SOURCE_CODE_WEBSITE_PROPERTY_NAME), - //"https://github.com/garybentley/quollwriter", - null, - false), - cc.xy (4, - y)); - - y += 2; - - String relNotesUrl = Environment.getProperty (Constants.QUOLL_WRITER_RELEASE_NOTES_URL_PROPERTY_NAME); - - relNotesUrl = StringUtils.replaceString (relNotesUrl, - "[[VERSION]]", - Environment.getQuollWriterVersion ().getVersion ().replace ('.', - '_')); - - pbuilder.add (UIUtils.createWebsiteLabel (relNotesUrl, - getUIString (prefix,releasenotes), - //"Release Notes", - false), - cc.xy (4, - y)); - - y += 2; - - pbuilder.add (UIUtils.createWebsiteLabel (Environment.getProperty (Constants.PATREON_WEBSITE_PROPERTY_NAME), - //"https://www.patreon.com/quollwriter?ty=h", - "Patreon", - false), - cc.xy (4, - y)); - - y += 2; - - pbuilder.add (UIUtils.createWebsiteLabel (Environment.getProperty (Constants.GOFUNDME_WEBSITE_PROPERTY_NAME), - //"https://www.gofundme.com/quollwriter", - getUIString (prefix,makeadonation), - //"Make a donation", - false), - cc.xy (4, - y)); - - y += 2; - - pbuilder.add (UIUtils.createWebsiteLabel (Environment.getProperty (Constants.QUOLL_WRITER_ACKNOWLEDGMENTS_URL_PROPERTY_NAME), - getUIString (prefix,acknowledgments), - //"Acknowledgments", - false), - cc.xy (4, - y)); - - y += 2; - - JButton closeBut = UIUtils.createButton (getUIString (buttons,close)); - //closeBut.setText ("Close"); - - closeBut.addActionListener (new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - qp.removeFromParent (); - - } - - }); - - JButton[] buts = { closeBut }; - - JPanel bp = UIUtils.createButtonBar2 (buts, - Component.LEFT_ALIGNMENT); - bp.setOpaque (false); - - JPanel p = pbuilder.getPanel (); - p.setOpaque (false); - p.setAlignmentX (JComponent.LEFT_ALIGNMENT); - - content.add (p); - - content.add (Box.createVerticalStrut (10)); - content.add (bp); - - content.setSize (new Dimension (UIUtils.getPopupWidth () - 20, - content.getPreferredSize ().height)); - content.setBorder (UIUtils.createPadding (10, 10, 10, 10)); - - qp.setContent (content); - - qp.setDraggable (this); - - qp.resize (); - - popup = qp; - - this.addNamedPopup (popupName, - popup); - - this.showPopupAt (popup, - UIUtils.getCenterShowPosition (this, - popup), - false); - - } else { - - popup.setVisible (true); - - } - - this.fireProjectEvent (ProjectEvent.ABOUT, - ProjectEvent.SHOW); - - } - - public void showWhatsNew (boolean onlyShowCurrentVersion) - { - - String popupName = "whatsnew"; - - QPopup popup = this.getNamedPopup (popupName); - - if (popup == null) - { - - try - { - - popup = UIUtils.createWizardPopup (String.format (getUIString (whatsnew, LanguageStrings.popup, LanguageStrings.title), - Environment.getQuollWriterVersion ()), - //"What's new in version " + Environment.getQuollWriterVersion (), - Constants.WHATS_NEW_ICON_NAME, - null, - new WhatsNew (this, - onlyShowCurrentVersion)); - - popup.setPopupName (popupName); - - } catch (Exception e) { - - // Not good but not the end of the world but shouldn't stop things from going on. - Environment.logError ("Unable to init whats new", - e); - - UIUtils.showErrorMessage (this, - getUIString (whatsnew,actionerror)); - //"Unable to show What's New, please contact Quoll Writer support for assistance."); - - return; - - } - - this.addNamedPopup (popupName, - popup); - - popup.setDraggable (this); - - popup.resize (); - this.showPopupAt (popup, - UIUtils.getCenterShowPosition (this, - popup), - false); - - } else { - - popup.setVisible (true); - - } - - this.fireProjectEvent (ProjectEvent.WHATS_NEW, - ProjectEvent.SHOW); - - } - - private void handleShowTips () - { - - if (Environment.isFirstUse ()) - { - - return; - - } - - if ((this.tips != null) - && - (UserProperties.getAsBoolean (Constants.SHOW_TIPS_PROPERTY_NAME)) - ) - { - - final AbstractViewer _this = this; - - try - { - - String tipText = this.tips.getNextTip (); - - final JTextPane htmlP = UIUtils.createHelpTextPane (tipText, - this); - - htmlP.setBorder (null); - htmlP.setSize (new Dimension (500, - 500)); - - JButton nextBut = UIUtils.createButton ("next", - Constants.ICON_MENU, - getUIString (tipspanel,next,tooltip), - //"Click to view the next tip", - null); - - java.util.List buts = new ArrayList (); - buts.add (nextBut); - - JButton offBut = UIUtils.createButton (Constants.STOP_ICON_NAME, - Constants.ICON_MENU, - getUIString (tipspanel,stop,tooltip), - //"Click to stop showing tips when Quoll Writer starts", - null); - - buts.add (offBut); - - // Show a tip. - final Notification n = this.addNotification (htmlP, - Constants.HELP_ICON_NAME, - 90, - buts); - - nextBut.addActionListener (new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - String t = _this.tips.getNextTip (); - - if (t != null) - { - - htmlP.setText (t); - - htmlP.validate (); - - n.setMinimumSize (n.getPreferredSize ()); - - _this.repaint (); - - n.restartTimer (); - - _this.fireProjectEvent (ProjectEvent.TIPS, - ProjectEvent.SHOW); - - } - - } - - }); - - offBut.addActionListener (new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - JButton but = (JButton) ev.getSource (); - - Point p = SwingUtilities.convertPoint (but, - 0, - 0, - _this); - - java.util.List prefix = Arrays.asList (tipspanel,stop,popup); - - UIUtils.createQuestionPopup (_this, - getUIString (prefix, LanguageStrings.title), - //"Stop showing tips?", - Constants.STOP_ICON_NAME, - getUIString (prefix,text), - //"Stop showing tips when Quoll Writer starts?

    They can enabled at any time in the Options panel.", - getUIString (prefix,buttons,confirm), - //"Yes, stop showing them", - getUIString (prefix,buttons,cancel), - //"No, keep them", - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.fireProjectEvent (ProjectEvent.TIPS, - ProjectEvent.OFF); - - UserProperties.set (Constants.SHOW_TIPS_PROPERTY_NAME, - false); - - n.removeNotification (); - - } - - }, - null, - null, - p); - - } - - }); - - } catch (Exception e) { - - Environment.logError ("Unable to show tips", - e); - - } - - } - - } - - public void handleHTMLPanelAction (String v) - { - - StringTokenizer t = new StringTokenizer (v, - ",;"); - - if (t.countTokens () > 1) - { - - while (t.hasMoreTokens ()) - { - - this.handleHTMLPanelAction (t.nextToken ().trim ()); - - } - - return; - - } - - try - { - - if (v.equals ("showundealtwitheditormessages")) - { - - this.viewEditors (); - - return; - - } - - if (v.startsWith ("options")) - { - - String section = null; - - int dot = v.indexOf ('.'); - - if (dot > 1) - { - - section = v.substring (dot + 1); - - } - - this.showOptions (section); - - return; - - } - - if (v.equals ("whatsnew")) - { - - this.showWhatsNew (true); - - return; - - } - - if (v.equals ("achievements")) - { - - this.viewAchievements (); - - return; - - } - - if (v.equals ("warmup")) - { - - this.showWarmupPromptSelect (); - - return; - - } - - if (v.equals ("showinviteeditor")) - { - - EditorsUIUtils.showInviteEditor (this); - - return; - - } - - if (v.equals ("editobjectnames")) - { - - this.showObjectTypeNameChanger (); - - return; - - } - - if (v.equals ("contact")) - { - - this.showContactSupport (); - - return; - - } - - if (v.equals ("reportbug")) - { - - this.showReportProblem (); - - return; - - } - - if (v.equals ("dictionarymanager")) - { - - this.showDictionaryManager (); - - return; - - } - - if (v.equals ("editors")) - { - - this.viewEditors (); - - return; - - } - - if (v.equals ("targets")) - { - - this.viewTargets (); - - return; - - } - - if (v.equals ("statistics")) - { - - this.viewStatistics (); - - return; - - } - - if (v.equals ("charts")) - { - - this.viewStatistics (); - - return; - - } - - } catch (Exception e) { - - Environment.logError ("Unable to perform action: " + - v, - e); - - } - - } - - public void showObjectTypeNameChanger () - { - - String popupName = "editobjectnames"; - QPopup popup = this.getNamedPopup (popupName); - - if (popup == null) - { - - popup = UIUtils.createClosablePopup (getUIString (objectnames,changer, LanguageStrings.popup, LanguageStrings.title), - //"Edit Object Names", - Environment.getIcon (Constants.CONFIG_ICON_NAME, - Constants.ICON_POPUP), - null); - - popup.setPopupName (popupName); - - ObjectTypeNameChanger c = new ObjectTypeNameChanger (this); - - c.init (); - - popup.setContent (c); - - c.setSize (new Dimension (UIUtils.getPopupWidth () - 20, - c.getPreferredSize ().height)); - c.setBorder (UIUtils.createPadding (10, 10, 10, 10)); - - popup.setContent (c); - - popup.setDraggable (this); - - popup.resize (); - - this.addNamedPopup (popupName, - popup); - - this.showPopupAt (popup, - UIUtils.getCenterShowPosition (this, - popup), - false); - - } else { - - popup.setVisible (true); - - } - - } - - private boolean closeInternal (ActionListener afterClose) - { - - this.notifications.setVisible (false); - - this.dispose (); - - this.generalTimer.shutdown (); - - Environment.unregisterViewer (this, - afterClose); - - return true; - - } - - public boolean close (boolean noConfirm, - final ActionListener afterClose) - { - - return this.closeInternal (afterClose); - - } - - public void bringPopupToFront (Component c) - { - - this.getLayeredPane ().setPosition (c, - 0); - - } - - public void addPopup (Component c) - { - - this.addPopup (c, - false, - false); - - } - - public void addPopup (Component c, - boolean hideOnClick, - boolean hideViaVisibility) - { - - this.getLayeredPane ().add (c, - JLayeredPane.POPUP_LAYER); - - this.getLayeredPane ().moveToFront (c); - - } - - @Override - public void removePopup (Component c) - { - - this.getLayeredPane ().remove (c); - - this.getLayeredPane ().validate (); - - this.getLayeredPane ().repaint (); - - } - - public void showAchievement (AchievementRule ar) - { - - try - { - - Box b = null; - - if (this.achievementsPopup == null) - { - - b = new Box (BoxLayout.Y_AXIS); - b.setBackground (UIUtils.getComponentColor ()); - b.setOpaque (true); - - this.achievementsPopup = UIUtils.createPopup (getUIString (achievementreached, LanguageStrings.title), - //"You've got an Achievement", - Constants.ACHIEVEMENT_ICON_NAME, - b, - true, - null); - - this.achievementsPopup.getHeader ().setPreferredSize (new Dimension (250, - this.achievementsPopup.getHeader ().getPreferredSize ().height)); - - final AbstractViewer _this = this; - final Box content = b; - - this.achievementsPopup.getHeader ().addMouseListener (new MouseAdapter () - { - - public void mouseReleased (MouseEvent ev) - { - - _this.achievementsPopup.setVisible (false); - - content.removeAll (); - - } - - }); - - this.achievementsPopup.addMouseListener (new ComponentShowHide (new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - _this.achievementsHideTimer.stop (); - - } - - }, - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - _this.achievementsHideTimer.start (); - - } - - })); - - } else { - - b = (Box) this.achievementsPopup.getContent (); - - } - - JComponent arBox = new AchievementBox (ar, - false, - true); - - if (b.getComponentCount () > 0) - { - - arBox.setBorder (new CompoundBorder (new MatteBorder (0, 0, 1, 0, Environment.getBorderColor ()), - arBox.getBorder ())); - - } - - b.add (arBox, - 0); - - if (this.achievementsPopup.getParent () != null) - { - - this.achievementsPopup.getParent ().remove (this.achievementsPopup); - - } - - this.showPopupAt (this.achievementsPopup, - new Point (10, 10), - true); - - this.achievementsPopup.setVisible (true); - - final AbstractViewer _this = this; - final Box content = b; - - if (this.achievementsHideTimer == null) - { - - this.achievementsHideTimer = new Timer (10000, - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - _this.achievementsPopup.setVisible (false); - - content.removeAll (); - - } - - }); - - this.achievementsHideTimer.setRepeats (false); - - } - - this.achievementsHideTimer.stop (); - - this.achievementsHideTimer.start (); - - } catch (Exception e) { - - Environment.logError ("Unable to display achievement: " + - ar, - e); - - } - - } - - public void showNotificationPopup (String title, - String message, - int showFor) - { - - JComponent c = null; - JTextPane m = null; - - if (message != null) - { - - m = UIUtils.createHelpTextPane (message, - this); - - m.setSize (new Dimension (350 - 20, - m.getPreferredSize ().height)); - - Box b = new Box (BoxLayout.Y_AXIS); - b.setBackground (UIUtils.getComponentColor ()); - b.setOpaque (true); - b.add (m); - b.setBorder (UIUtils.createPadding (10, 10, 10, 10)); - b.setPreferredSize (new Dimension (350, - b.getPreferredSize ().height)); - - c = b; - - } - - final QPopup popup = UIUtils.createPopup (title, - Constants.INFO_ICON_NAME, - null, - true, - null); - - popup.setContent (c); - - if (m != null) - { - - m.addHyperlinkListener (new HyperlinkListener () - { - - @Override - public void hyperlinkUpdate (HyperlinkEvent ev) - { - - if (ev.getEventType () == HyperlinkEvent.EventType.ACTIVATED) - { - - popup.removeFromParent (); - - } - - } - - }); - - } - - this.showPopupAt (popup, - new Point (10, 10), - true); - - if (showFor > 0) - { - - final Timer t = new Timer (showFor * 1000, - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - popup.removeFromParent (); - - } - - }); - - popup.addMouseListener (new ComponentShowHide (new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - t.stop (); - - } - - }, - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - t.start (); - - } - - })); - - t.setRepeats (false); - - t.start (); - - } - - } - - public QPopup getPopupByName (String name) - { - - if (name == null) - { - - return null; - - } - - Component[] children = this.getLayeredPane ().getComponentsInLayer (JLayeredPane.POPUP_LAYER); - - if (children == null) - { - - return null; - - } - - for (int i = 0; i < children.length; i++) - { - - Component c = children[i]; - - if (name.equals (c.getName ())) - { - - if (c instanceof QPopup) - { - - return (QPopup) c; - - } - - } - - } - - return null; - - } - - public void showPopupAt (JComponent c, - Rectangle r, - String where, - boolean hideOnParentClick) - { - - Dimension s = c.getPreferredSize (); - - int x = r.x; - int y = r.y - c.getInsets ().top;// - c.getInsets ().bottom; - - if (where == null) - { - - where = "below"; - - } - - if (where.equals ("below")) - { - - y = y + r.height; - - } - - if (where.equals ("above")) - { - - y = y - s.height - c.getInsets ().bottom; - - } - - if (y < 0) - { - - y = r.y; // + r.height; - - } - - if ((x + s.width) > (this.getWidth ())) - { - - x = this.getWidth () - 20 - s.width; - - } - - if (x < 0) - { - - x = 5; - - } - - this.showPopupAt (c, - new Point (x, - y), - hideOnParentClick); - - } - - @Override - public void showPopupAt (Component popup, - Component showAt, - boolean hideOnParentClick) - { - - Point po = SwingUtilities.convertPoint (showAt, - 0, - 0, - this.getContentPane ()); - - this.showPopupAt (popup, - po, - hideOnParentClick); - - - } - - @Override - public void showPopupAt (Component c, - Point p, - boolean hideOnParentClick) - { - - Insets ins = this.getInsets (); - - if ((c.getParent () == null) - && - (c.getParent () != this.getLayeredPane ()) - ) - { - - this.addPopup (c, - hideOnParentClick, - false); - - } - - Dimension cp = c.getPreferredSize (); - - if ((p.y + cp.height) > (this.getBounds ().height - ins.top - ins.bottom)) - { - - p = new Point (p.x, - p.y); - - // See if the child is changing height. - if (c.getBounds ().height != cp.height) - { - - p.y = p.y - (cp.height - c.getBounds ().height); - - } else { - - p.y = p.y - cp.height; - - } - - } - - if (p.y < 0) - { - - p = new Point (p.x, - p.y); - - p.y = 10; - - } - - if ((p.x + cp.width) > (this.getBounds ().width - ins.left - ins.right)) - { - - p = new Point (p.x, - p.y); - - p.x = p.x - cp.width; - - } - - if (p.x < 0) - { - - p = new Point (p.x, - p.y); - - p.x = 10; - - } - - c.setBounds (p.x, - p.y, - c.getPreferredSize ().width, - c.getPreferredSize ().height); - - c.setVisible (true); - this.validate (); - this.repaint (); - - } - - public void showPopup (Component c, - boolean hideOnParentClick) - { - - Point p = this.getMousePosition (); - - if (p != null) - { - - SwingUtilities.convertPointToScreen (p, - this); - - } else - { - - p = new Point (300, - 300); - - } - - this.showPopupAt (c, - p, - hideOnParentClick); - - } - - public Point convertPoint (Component c, - Point p) - { - - Component o = this.getContentPane (); - - return SwingUtilities.convertPoint (c, - p, - o); - - } - - public void setViewerControls (JComponent c) - { - - this.title.setControls (c); - - } - - public void removeProjectEventListener (ProjectEventListener l) - { - - this.projectEventListeners.remove (l); - - } - - public void addProjectEventListener (ProjectEventListener l) - { - - this.projectEventListeners.add (l); - - } - - public void fireProjectEventLater (final String type, - final String action) - { - - final AbstractViewer _this = this; - - UIUtils.doLater (new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.fireProjectEvent (type, - action); - - } - - }); - - } - - public void fireProjectEvent (String type, - String action, - Object contextObject) - { - - this.fireProjectEvent (new ProjectEvent (this, - type, - action, - contextObject)); - - } - - public void fireProjectEvent (String type, - String action) - { - - this.fireProjectEvent (new ProjectEvent (this, - type, - action)); - - } - - public void setIgnoreProjectEvents (boolean v) - { - - this.ignoreProjectEvents = v; - - } - - public void fireProjectEvent (ProjectEvent ev) - { - - if (this.ignoreProjectEvents) - { - - return; - - } - - for (ProjectEventListener l : this.projectEventListeners) - { - - l.eventOccurred (ev); - - } - - } - - public void showDictionaryManager () - { - - String popupName = "dictman"; - QPopup popup = this.getNamedPopup (popupName); - - if (popup == null) - { - - DictionaryManager dictMan = null; - - try - { - - dictMan = new DictionaryManager (this); - - } catch (Exception e) { - - Environment.logError ("Unable to create dictionary maanger.", - e); - - UIUtils.showErrorMessage (this, - getUIString (dictionary,manage,actionerror)); - //"Unable to show personal dictionary."); - - return; - - } - - dictMan.init (); - - popup = UIUtils.createClosablePopup (getUIString (dictionary,manage, LanguageStrings.title), - //"Manage your personal Dictionary", - Environment.getIcon (Constants.DICTIONARY_ICON_NAME, - Constants.ICON_POPUP), - null); - - popup.setRemoveOnClose (false); - - popup.setPopupName (popupName); - - this.addNamedPopup (popupName, - popup); - - dictMan.setSize (new Dimension (UIUtils.getPopupWidth () - 20, - dictMan.getPreferredSize ().height)); - dictMan.setBorder (UIUtils.createPadding (10, 10, 10, 10)); - - popup.setContent (dictMan); - - popup.setDraggable (this); - - popup.resize (); - this.showPopupAt (popup, - UIUtils.getCenterShowPosition (this, - popup), - false); - - } else { - - popup.setVisible (true); - - } - - this.fireProjectEvent (ProjectEvent.PERSONAL_DICTIONARY, - ProjectEvent.SHOW); - - } - - public void showEditNoteTypes () - { - - String popupName = "editnotetypes"; - QPopup popup = this.getNamedPopup (popupName); - - if (popup == null) - { - - popup = UIUtils.createClosablePopup (getUIString (notetypes,actions,manage, LanguageStrings.title), - //"Manage the {Note} Types", - Environment.getIcon (Constants.EDIT_ICON_NAME, - Constants.ICON_POPUP), - null); - - popup.setRemoveOnClose (false); - - popup.setPopupName (popupName); - - this.addNamedPopup (popupName, - popup); - - EditNoteTypes content = new EditNoteTypes (this); - content.init (); - - content.setSize (new Dimension (UIUtils.getPopupWidth () - 20, - content.getPreferredSize ().height)); - content.setBorder (UIUtils.createPadding (10, 10, 10, 10)); - - popup.setContent (content); - - popup.setDraggable (this); - - popup.resize (); - this.showPopupAt (popup, - UIUtils.getCenterShowPosition (this, - popup), - false); - - } else { - - popup.setVisible (true); - - } - - this.fireProjectEvent (ProjectEvent.NOTE_TYPES, - ProjectEvent.SHOW); - - } - - public void showEditTags () - { - - String popupName = "edittags"; - QPopup popup = this.getNamedPopup (popupName); - - if (popup == null) - { - - popup = UIUtils.createClosablePopup (getUIString (tags,actions,manage, LanguageStrings.title), - //)"Manage the Tags", - Environment.getIcon (Constants.EDIT_ICON_NAME, - Constants.ICON_POPUP), - null); - - popup.setRemoveOnClose (false); - - popup.setPopupName (popupName); - - this.addNamedPopup (popupName, - popup); - - TagsEditor content = new TagsEditor (this); - - content.init (); - - content.setSize (new Dimension (UIUtils.getPopupWidth () - 20, - content.getPreferredSize ().height)); - content.setBorder (UIUtils.createPadding (10, 10, 10, 10)); - - popup.setContent (content); - - popup.setDraggable (this); - - popup.resize (); - this.showPopupAt (popup, - UIUtils.getCenterShowPosition (this, - popup), - false); - - } else { - - popup.setVisible (true); - - } - - this.fireProjectEvent (ProjectEvent.TAGS, - ProjectEvent.EDIT); - - } - - /** - * Un-schedule the scheduledfuture (gained from a call to Environment.schedule). - * - * @param r The scheduledfuture to remove from the executor service. - * @returns Whether it was successfully removed. - */ - public void unschedule (ScheduledFuture f) - { - - if (f == null) - { - - return; - - } - - // Let the task run to completion. - f.cancel (false); - - this.generalTimer.purge (); - - } - - /** - * Schedule the runnable to run after delay and repeat (use -1 or 0 for no repeat). - * - * @param r The runnable to run. - * @param delay The delay, in millis. - * @param repeat The repeat time, in millis. - */ - public ScheduledFuture schedule (final Runnable r, - final long delay, - final long repeat) - { - - if (this.generalTimer == null) - { - - Environment.logError ("Unable to schedule timer is no longer valid."); - - return null; - - } - - if (r == null) - { - - Environment.logError ("Unable to schedule timer, runnable is null."); - - return null; - - } - - if (repeat < 1) - { - - return this.generalTimer.schedule (r, - delay, - TimeUnit.MILLISECONDS); - - } else { - - return this.generalTimer.scheduleAtFixedRate (r, - delay, - repeat, - TimeUnit.MILLISECONDS); - - } - - } - -} diff --git a/src/com/quollwriter/ui/AccordionItem.java b/src/com/quollwriter/ui/AccordionItem.java deleted file mode 100644 index ad3f0c2f..00000000 --- a/src/com/quollwriter/ui/AccordionItem.java +++ /dev/null @@ -1,324 +0,0 @@ -package com.quollwriter.ui; - -import java.awt.Component; -import java.awt.Insets; -import java.awt.Cursor; -import java.awt.Color; -import java.awt.Font; -import java.awt.event.*; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.HashMap; - -import javax.swing.*; - -import com.quollwriter.*; -import com.quollwriter.events.*; -import com.quollwriter.ui.components.GradientPainter; -import com.quollwriter.ui.components.Header; - -public abstract class AccordionItem extends Box -{ - - protected Header header = null; - //private List headerMenuItems = new ArrayList (); - private String title = null; - //private JComponent content = null; - private boolean inited = false; - - public AccordionItem (String title) - { - - this (title, - (String) null); - - } - - public AccordionItem (String title, - ImageIcon icon) - { - - super (BoxLayout.Y_AXIS); - - this.initHeader (title, - icon); - - } - - public AccordionItem (String title, - String iconType) - { - - super (BoxLayout.Y_AXIS); - - ImageIcon ii = null; - - if (iconType != null) - { - - ii = Environment.getIcon (iconType, - Constants.ICON_SIDEBAR); - - } - - this.initHeader (title, - ii); - - } - - public abstract JComponent getContent (); - - public void initFromSaveState (String ss) - { - - this.init (); - - Map state = (Map) JSONDecoder.decode (ss); - - Boolean vis = (Boolean) state.get ("contentVisible"); - - this.setContentVisible ((vis != null ? vis : false)); - - } - - public Map getSaveStateAsMap () - { - - Map ss = new HashMap (); - - ss.put ("contentVisible", - this.isContentVisible ()); - - return ss; - - } - - public String getSaveState () - { - - try - { - - return JSONEncoder.encode (this.getSaveStateAsMap ()); - - } catch (Exception e) { - - Environment.logError ("Unable to encode save state: " + - this.getSaveStateAsMap (), - e); - - return ""; - - } - - } - - private void initHeader (String title, - ImageIcon icon) - { - - this.title = Environment.replaceObjectNames (title); - - final Header h = new Header (this.title, - icon, - null); - - h.setFont (h.getFont ().deriveFont ((float) UIUtils.getScaledFontSize (14)).deriveFont (Font.PLAIN)); - - h.setPaintProvider (null); - h.setTitleColor (UIUtils.getTitleColor ()); - h.setPadding (new Insets (5, 5, 0, 0)); - h.setPaintProvider (new GradientPainter (UIUtils.getComponentColor (), - UIUtils.getComponentColor ())); - - // end new - h.setAlignmentX (Component.LEFT_ALIGNMENT); - h.setAlignmentY (Component.TOP_ALIGNMENT); - - this.header = h; - - } - - public String getId () - { - - return null; - - } - - public boolean isContentVisible () - { - - return this.getContent ().isVisible (); - - } - - public void setIconType (String i) - { - - if (i != null) - { - - ImageIcon ii = Environment.getIcon (i, - Constants.ICON_SIDEBAR); - - this.header.setIcon (ii); - - } - - } - - public String getTitle () - { - - return this.title; - - } - - public void setTitle (String s) - { - - this.title = Environment.replaceObjectNames (s); - - this.header.setTitle (s); - - } - - public Header getHeader () - { - - return this.header; - - } - - public void setHeader (Header h) - { - - this.header = h; - - } - - public void setContentVisible (boolean v) - { - - JComponent c = this.getContent (); - - if (c != null) - { - - c.setVisible (v); - - } - - this.validate (); - this.repaint (); - - } - - public void fillHeaderPopupMenu (JPopupMenu m, - MouseEvent ev) - { - - } - - public void setSaveState (String s) - { - - Map m = (Map) JSONDecoder.decode (s); - - this.setContentVisible ((Boolean) m.get ("contentVisible")); - - } - - public void init () - { - - if (this.inited) - { - - return; - - } - - final AccordionItem _this = this; - - this.header.setCursor (Cursor.getPredefinedCursor (Cursor.HAND_CURSOR)); - this.header.setToolTipText (Environment.getUIString (LanguageStrings.project, - LanguageStrings.sidebar, - LanguageStrings.section, - LanguageStrings.title, - LanguageStrings.tooltip)); - //"Click to open/close the items below."); - - this.header.addMouseListener (new MouseEventHandler () - { - - @Override - public void fillPopup (JPopupMenu m, - MouseEvent ev) - { - - _this.fillHeaderPopupMenu (m, - ev); - - } - - @Override - public void handlePress (MouseEvent ev) - { - - JComponent c = _this.getContent (); - - if (c != null) - { - - c.setVisible (!c.isVisible ()); - - _this.revalidate (); - _this.repaint (); - - } - - } - - }); - - JComponent c = this.getContent (); - - if (c != null) - { - - c.setAlignmentX (Component.LEFT_ALIGNMENT); - - } - - this.add (this.header); - - if (c != null) - { - - this.add (c); - - } - - this.inited = true; - - } - - public void setHeaderControls (JComponent c) - { - - this.header.setControls (c); - - } - - public JComponent getHeaderControls () - { - - return (JComponent) this.header.getControls (); - - } - -} \ No newline at end of file diff --git a/src/com/quollwriter/ui/AssetFindResultsBox.java b/src/com/quollwriter/ui/AssetFindResultsBox.java deleted file mode 100644 index fc9d2ebc..00000000 --- a/src/com/quollwriter/ui/AssetFindResultsBox.java +++ /dev/null @@ -1,58 +0,0 @@ -package com.quollwriter.ui; - -import java.util.Set; - -import javax.swing.*; -import javax.swing.tree.*; - -import com.quollwriter.data.*; - -public class AssetFindResultsBox extends FindResultsBox -{ - - private Set objs = null; - private UserConfigurableObjectType objType = null; - - public AssetFindResultsBox (UserConfigurableObjectType type, - AbstractProjectViewer viewer, - Set objs) - { - - super (type.getObjectTypeNamePlural (), - type.getIcon16x16 (), - viewer); - - this.objs = objs; - - this.count = objs.size (); - - - } - - @Override - public String getId () - { - - return "findasset" + this.objType.getKey (); - - } - - @Override - public void initTree () - { - - // Let subclasses override for their own behaviour. - DefaultMutableTreeNode tn = new DefaultMutableTreeNode (this.viewer.getProject ()); - - UIUtils.createTree (this.objs, - tn); - - ((DefaultTreeModel) this.tree.getModel ()).setRoot (tn); - - this.count = objs.size (); - - this.updateItemCount (this.count); - - } - -} diff --git a/src/com/quollwriter/ui/BackupsManager.java b/src/com/quollwriter/ui/BackupsManager.java deleted file mode 100644 index 3015feef..00000000 --- a/src/com/quollwriter/ui/BackupsManager.java +++ /dev/null @@ -1,636 +0,0 @@ -package com.quollwriter.ui; - -import java.awt.*; -import java.awt.event.*; - -import java.io.File; - -import java.net.*; - -import java.text.*; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.StringTokenizer; -import java.util.Vector; -import java.util.Date; -import java.util.Arrays; -import java.util.Set; -import java.util.LinkedHashSet; - -import javax.swing.*; -import javax.swing.border.*; -import javax.swing.filechooser.*; -import javax.swing.table.*; -import javax.swing.tree.*; - -import org.josql.*; - -import com.gentlyweb.utils.*; - -import com.gentlyweb.xml.*; - -import com.jgoodies.forms.builder.*; -import com.jgoodies.forms.factories.*; -import com.jgoodies.forms.layout.*; - -import com.quollwriter.*; - -import com.quollwriter.data.*; -import com.quollwriter.data.comparators.*; - -import com.quollwriter.exporter.*; - -import com.quollwriter.ui.components.*; -import com.quollwriter.ui.renderers.*; - -import static com.quollwriter.LanguageStrings.*; -import static com.quollwriter.Environment.getUIString; - -public class BackupsManager extends Box implements ProjectEventListener -{ - - private AbstractViewer viewer = null; - private ProjectInfo proj = null; - private Box backupsBox = null; - private JLabel noBackups = null; - private JLabel backupsDir = null; - private JScrollPane scrollPane = null; - - public BackupsManager (AbstractViewer pv, - ProjectInfo pi) - { - - super (BoxLayout.Y_AXIS); - - this.viewer = pv; - this.proj = pi; - - Environment.addUserProjectEventListener (this); - - } - - public void eventOccurred (ProjectEvent ev) - { - - if (!ev.getType ().equals (ProjectEvent.BACKUPS)) - { - - return; - - } - - Object c = ev.getContextObject (); - - if ((c != null) - && - (c instanceof Project) - ) - { - - Project p = (Project) c; - - if (Environment.getProjectInfo (p) != this.proj) - { - - // Not interested in this project. - return; - - } - - } - - this.update (); - - } - - private void update () - { - - try - { - - final BackupsManager _this = this; - - this.noBackups.setVisible (true); - - this.backupsDir.setVisible (this.proj.getBackupDirectory ().exists ()); - - this.backupsBox.removeAll (); - - File[] _files = this.proj.getBackupDirectory ().listFiles (); - - if ((_files != null) - && - (_files.length > 0) - ) - { - - java.util.List files = (java.util.List) Arrays.asList (_files); - - Query q = new Query (); - - q.parse (String.format ("SELECT * FROM %s WHERE fileExtension(:_currobj) = 'zip' ORDER BY lastModified DESC", - File.class.getName ())); - - QueryResults qr = q.execute (files); - - files = (java.util.List) qr.getResults (); - - for (File f : files) - { - - Backup b = new Backup (f, - this.proj); - - b.init (); - - this.backupsBox.add (b); - - } - - this.noBackups.setVisible (files.size () == 0); - - UIUtils.doLater (new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - _this.scrollPane.getVerticalScrollBar ().setValue (0); - - } - - }); - - } - - } catch (Exception e) { - - Environment.logError ("Unable to build list of backups", - e); - - UIUtils.showErrorMessage (this.viewer, - getUIString (backups,show,actionerror)); - //"Unable to show list of backups, please contact Quoll Writer support for assistance."); - - } - - } - - public void init () - throws Exception - { - - final BackupsManager _this = this; - - JTextPane tp = UIUtils.createHelpTextPane (String.format (getUIString (backups,text), - //"Listed below are the backups you have for {project} %s.", - this.proj.getName ()), - this.viewer); - - tp.setBorder (UIUtils.createPadding (0, 0, 10, 0)); - - this.add (tp); - - this.backupsDir = UIUtils.createClickableLabel (getUIString (backups,viewbackupsdir), - //"Click to view the backups directory", - Environment.getIcon (Constants.VIEW_ICON_NAME, - Constants.ICON_MENU)); - - UIUtils.makeClickable (this.backupsDir, - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - try - { - - UIUtils.openURL (_this.viewer, - _this.proj.getBackupDirectory ().toURI ().toURL ()); - - } catch (Exception e) { - - // Can ignore. - - } - - } - - }); - - this.backupsDir.setBorder (UIUtils.createPadding (0, 0, 10, 0)); - - this.add (this.backupsDir); - - this.noBackups = UIUtils.createLabel (getUIString (backups,nobackups)); - //"You currently have no backups for this {project}."); - this.noBackups.setIcon (Environment.getIcon (Constants.INFO_ICON_NAME, - Constants.ICON_MENU)); - - this.noBackups.setBorder (UIUtils.createPadding (0, 0, 10, 0)); - - this.add (this.noBackups); - - this.backupsBox = new ScrollableBox (BoxLayout.Y_AXIS); - this.backupsBox.setAlignmentX (Component.LEFT_ALIGNMENT); - this.backupsBox.setOpaque (false); - - this.scrollPane = UIUtils.createScrollPane (backupsBox); - this.scrollPane.getVerticalScrollBar ().setUnitIncrement (20); - this.scrollPane.getViewport ().setPreferredSize (new Dimension (450, - 300)); - - Box wspsp = new Box (BoxLayout.Y_AXIS); - wspsp.add (this.scrollPane); - wspsp.setBorder (UIUtils.createPadding (0, 0, 0, 0)); - this.add (wspsp); - - this.update (); - - this.add (Box.createVerticalStrut (10)); - - JButton create = UIUtils.createButton (getUIString (backups,show,buttons,createbackup), - //Constants.CREATE_BACKUP_BUTTON_LABEL_ID, - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - UIUtils.showCreateBackup (proj, - null, - _this.viewer); - - } - - }); - - JButton finish = UIUtils.createButton (getUIString (backups,show,buttons, LanguageStrings.finish), - //Constants.FINISH_BUTTON_LABEL_ID, - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - UIUtils.closePopupParent (_this.getParent ()); - - } - - }); - - JButton[] buts = new JButton[] { create, finish }; - - JPanel bp = UIUtils.createButtonBar2 (buts, - Component.CENTER_ALIGNMENT); - bp.setOpaque (false); - - this.add (bp); - - UIUtils.doLater (new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - _this.scrollPane.getVerticalScrollBar ().setValue (0); - - } - - }); - - } - - private class Backup extends Box - { - - private File file = null; - private ProjectInfo proj = null; - - public Backup (File b, - ProjectInfo proj) - { - - super (BoxLayout.Y_AXIS); - - this.file = b; - this.proj = proj; - - this.setBorder (new CompoundBorder (new MatteBorder (0, - 0, - 1, - 0, - UIUtils.getInnerBorderColor ()), - new EmptyBorder (5, - 5, - 5, - 5))); - - } - - public void restore () - { - - java.util.List prefix = Arrays.asList (backups,restore,popup); - - final Backup _this = this; - - UIUtils.createQuestionPopup ((AbstractViewer) BackupsManager.this.viewer, - getUIString (prefix,title), - //"Confirm restore", - Constants.RESTORE_ICON_NAME, - String.format (getUIString (prefix,text), - //"Please confirm you wish to restore {project} %s using the backup file %s.

    A backup of the {project} will be created before the restore occurs.", - this.proj.getName (), - this.file.getName ()), - getUIString (prefix,buttons,confirm), - //"Yes, restore it", - getUIString (prefix,buttons,cancel), - //Constants.CANCEL_BUTTON_LABEL_ID, - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - final AbstractProjectViewer pv = Environment.getProjectViewer (_this.proj); - - ActionListener doRestore = new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - UIUtils.closePopupParent (BackupsManager.this); - - ActionListener doRestore = new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - try - { - - // Create a backup. - File f = Environment.createBackupForProject (_this.proj, - true); - - } catch (Exception e) { - - Environment.logError ("Unable to create backup for project: " + - _this.proj, - e); - - UIUtils.showErrorMessage (BackupsManager.this.viewer, - getUIString (backups,_new,actionerror)); - //"Unable to create a backup of the {project} in its current state."); - - } - - // Restore using our file. - try - { - - Environment.restoreBackupForProject (_this.proj, - _this.file); - - } catch (Exception e) { - - Environment.logError ("Unable to restore project with file: " + - _this.file + - ", project: " + - _this.proj, - e); - - UIUtils.showErrorMessage (BackupsManager.this.viewer, - getUIString (backups,restore,actionerror)); - //"Unable to restore backup"); - - return; - - } - - java.util.List prefix = Arrays.asList (backups,restore,confirmpopup); - - if (pv != null) - { - - try - { - - // Reopen the project. - Environment.openProject (_this.proj); - - AbstractProjectViewer p = Environment.getProjectViewer (_this.proj); - - // Show confirmation. - UIUtils.showMessage ((PopupsSupported) p, - getUIString (prefix,title), - //"{Project} restored", - String.format (getUIString (prefix,text), - //"The {project} has been restored from file %s.", - _this.file.getName ())); - - p.fireProjectEventLater (ProjectEvent.BACKUPS, - ProjectEvent.RESTORE); - - } catch (Exception e) { - - Environment.logError ("Unable to reopen project: " + - _this.proj, - e); - - UIUtils.showErrorMessage (BackupsManager.this.viewer, - getUIString (prefix,actionerror)); - //"Unable to re-open backup"); - - return; - - } - - return; - - } - - // Show confirmation. - UIUtils.showMessage ((PopupsSupported) BackupsManager.this.viewer, - getUIString (prefix,title), - //"{Project} restored", - String.format (getUIString (prefix,text), - //"{Project} %s has been restored using file %s.", - _this.proj.getName (), - _this.file.getName ())); - - } - - }; - - UIUtils.askForPasswordForProject (proj, - null, - doRestore, - BackupsManager.this.viewer); - - } - - }; - - if (pv != null) - { - - // Close the project. - pv.close (false, - doRestore); - - } else { - - doRestore.actionPerformed (new ActionEvent ("restore", 1, "restore")); - - } - - // Create a backup of the project first. - - // Close the project viewer, if open. - - // Unzip to the current dir. - - // Open the project, if already open. - - } - - }, - null, - null, - null); - - } - - public void delete () - { - - java.util.List prefix = Arrays.asList (backups,delete,confirmpopup); - - final Backup _this = this; - - UIUtils.createQuestionPopup ((AbstractViewer) BackupsManager.this.viewer, - getUIString (prefix,title), - //"Confirm delete", - Constants.DELETE_ICON_NAME, - String.format (getUIString (prefix,text), - //"Please confirm you wish to delete backup file %s.", - this.file.getName ()), - getUIString (prefix,buttons,confirm), - //"Yes, delete it", - getUIString (prefix,buttons,cancel), - //"No, keep it", - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - _this.file.delete (); - - Container p = _this.getParent (); - - p.remove (_this); - - p.validate (); - p.repaint (); - - BackupsManager.this.viewer.fireProjectEventLater (ProjectEvent.BACKUPS, - ProjectEvent.DELETE); - - BackupsManager.this.update (); - - } - - }, - null, - null, - null); - - } - - public void init () - { - - final Backup _this = this; - - this.setBorder (UIUtils.createBottomLineWithPadding (5, 5, 5, 5)); - - final Box main = new Box (BoxLayout.X_AXIS); - - this.add (main); - - this.setAlignmentX (Component.LEFT_ALIGNMENT); - this.setOpaque (false); - main.setAlignmentX (Component.LEFT_ALIGNMENT); - main.setOpaque (false); - - JComponent name = UIUtils.createHelpTextPane (String.format ("%s (%s)", - Environment.formatDateTime (new Date (this.file.lastModified ())), - this.file.getName ()), - BackupsManager.this.viewer); - - main.add (name); - main.add (Box.createHorizontalGlue ()); - - java.util.List buttons = new ArrayList (); - - buttons.add (UIUtils.createButton (Constants.RESTORE_ICON_NAME, - Constants.ICON_MENU, - getUIString (backups,restore,tooltip), - //"Restore the {project} using this backup", - new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.restore (); - - } - - })); - - buttons.add (UIUtils.createButton (Constants.DELETE_ICON_NAME, - Constants.ICON_MENU, - getUIString (backups,delete,tooltip), - //"Click to delete this backup", - new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.delete (); - - } - - })); - - JComponent bbar = UIUtils.createButtonBar (buttons); - - //this.buttons.setVisible (false); - bbar.setAlignmentX (Component.LEFT_ALIGNMENT); - - main.add (bbar); - - } - - } - -} diff --git a/src/com/quollwriter/ui/ChapterFindResultsBox.java b/src/com/quollwriter/ui/ChapterFindResultsBox.java deleted file mode 100644 index a40b0da9..00000000 --- a/src/com/quollwriter/ui/ChapterFindResultsBox.java +++ /dev/null @@ -1,210 +0,0 @@ -package com.quollwriter.ui; - -import java.util.List; -import java.util.Map; - -import java.awt.event.*; -import javax.swing.*; -import javax.swing.tree.*; -import javax.swing.text.*; - -import com.quollwriter.*; -import com.quollwriter.data.*; -import com.quollwriter.ui.renderers.*; -import com.quollwriter.ui.panels.*; -import com.quollwriter.ui.components.QTextEditor; - -public class ChapterFindResultsBox extends FindResultsBox -{ - - private Map> snippets = null; - private Object highlightId = null; - private QTextEditor highlightedEditor = null; - private String forObjType = null; - - public ChapterFindResultsBox (String title, - String iconType, - String forObjType, - AbstractProjectViewer viewer, - Map> snippets) - { - - super (title, - iconType, - forObjType, - viewer); - - this.forObjType = forObjType; - - this.snippets = snippets; - - } - - @Override - public String getId () - { - - return this.forObjType; - - } - - @Override - public void initTree () - { - - this.tree.setCellRenderer (new ChapterSnippetsTreeCellRenderer ());//new MultiLineTreeCellRenderer (this)); - - DefaultMutableTreeNode tn = new DefaultMutableTreeNode (this.viewer.getProject ()); - - UIUtils.createTree (this.snippets, - tn); - - // Create the tree. - ((DefaultTreeModel) this.tree.getModel ()).setRoot (tn); - - int c = 0; - - for (NamedObject n : this.snippets.keySet ()) - { - - c += this.snippets.get (n).size (); - - } - - this.count = c; - - this.updateItemCount (this.count); - - this.setContentVisible (true); - - } - - @Override - protected void handleViewObject (TreePath tp, - Object o) - { - - if (o instanceof Chapter) - { - - this.toggleTreePath (tp); - - DefaultMutableTreeNode node = (DefaultMutableTreeNode) tp.getLastPathComponent (); - - // Damn son this is fugly. - if ((node.getChildCount () == 1) - && - (this.tree.isExpanded (UIUtils.getTreePathForUserObject ((DefaultMutableTreeNode) this.tree.getModel ().getRoot (), - node.getUserObject ()))) - ) - { - - DefaultMutableTreeNode n = node.getFirstLeaf (); - - TreePath tpp = UIUtils.getTreePathForUserObject ((DefaultMutableTreeNode) this.tree.getModel ().getRoot (), - n.getUserObject ()); - - this.handleViewObject (tpp, - n.getUserObject ()); - - this.tree.setSelectionPath (tpp); - - } - - return; - - } - - if (o instanceof Segment) - { - - DefaultMutableTreeNode node = (DefaultMutableTreeNode) tp.getLastPathComponent (); - - // Get the offset. - DefaultMutableTreeNode parent = (DefaultMutableTreeNode) node.getParent (); - - Chapter c = (Chapter) parent.getUserObject (); - - Segment s = (Segment) o; - - this.showChapterSegment (c, - s); - - } else { - - this.toggleTreePath (tp); - - } - - } - - public void clearHighlight () - { - - if (this.highlightedEditor != null) - { - - this.highlightedEditor.removeHighlight (this.highlightId); - - } - - } - - public void showChapterSegment (final Chapter c, - final Segment s) - { - - this.clearHighlight (); - - final ChapterFindResultsBox _this = this; - - this.viewer.viewObject (c, - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - AbstractEditorPanel p = _this.viewer.getEditorForChapter (c); - - try - { - - p.scrollToPosition (s.getBeginIndex ()); - - } catch (Exception e) { - - Environment.logError ("Unable to scroll to: " + s.getBeginIndex (), - e); - - return; - - } - - final QTextEditor ed = p.getEditor (); - - UIUtils.doLater (new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - _this.highlightId = ed.addHighlight (s.getBeginIndex (), - s.getEndIndex (), - null, - true); - - _this.highlightedEditor = ed; - - } - - }); - - } - - }); - - } - -} diff --git a/src/com/quollwriter/ui/ChapterItemTransferHandler.java b/src/com/quollwriter/ui/ChapterItemTransferHandler.java deleted file mode 100644 index e2d3cadc..00000000 --- a/src/com/quollwriter/ui/ChapterItemTransferHandler.java +++ /dev/null @@ -1,113 +0,0 @@ -package com.quollwriter.ui; - -import java.awt.Point; -import java.awt.event.*; -import java.awt.datatransfer.*; - -import javax.swing.*; - -import com.quollwriter.*; -import com.quollwriter.ui.panels.*; -import com.quollwriter.ui.actionHandlers.*; -import com.quollwriter.data.*; - -public class ChapterItemTransferHandler extends TransferHandler -{ - - private IconColumn ic = null; - private ChapterItemMoveHandler moveHandler = null; - - public ChapterItemTransferHandler (IconColumn ic) - { - - this.ic = ic; - - this.moveHandler = new ChapterItemMoveHandler (this.ic); - - } - - public void setItem (ChapterItem item) - { - - this.moveHandler.setItem (item); - - } - - public Icon getVisualRepresentation (Transferable t) - { - - // Never called... bug in java - return Environment.getObjectIcon (this.moveHandler.getItem (), - Constants.ICON_COLUMN); - - } - - public int getSourceActions (JComponent comp) - { - - return TransferHandler.COPY_OR_MOVE; - - } - - public void exportDone (JComponent comp, - Transferable t, - int action) - { - - this.moveHandler.dragFinished (); - - } - - public Transferable createTransferable (JComponent comp) - { - - ChapterItem item = this.moveHandler.getItem (); - - return new javax.activation.DataHandler (item, "object/" + item.getObjectType ()); - - } - - public boolean importData (TransferHandler.TransferSupport supp) - { - - return true; - - } - - public void exportAsDrag (JComponent comp, - InputEvent ev, - int action) - { - - super.exportAsDrag (comp, - ev, - action); - - this.moveHandler.startDrag (); - - try - { - - Point xp = this.ic.getImagePanel (this.moveHandler.getItem ()).getBounds ().getLocation (); - - SwingUtilities.convertPointToScreen (xp, - this.ic); - - new java.awt.Robot ().mouseMove (xp.x, - xp.y); - - } catch (Exception e) {} - - } - - public boolean canImport (JComponent comp, - DataFlavor[] transferFlavors) - { - - this.moveHandler.doDrag (); - - return true; - - } - -} diff --git a/src/com/quollwriter/ui/DebugConsole.java b/src/com/quollwriter/ui/DebugConsole.java deleted file mode 100644 index 4dbb32b5..00000000 --- a/src/com/quollwriter/ui/DebugConsole.java +++ /dev/null @@ -1,685 +0,0 @@ -package com.quollwriter.ui; - -import java.awt.*; -import java.awt.event.*; - -import java.io.File; - -import java.util.ArrayList; -import java.util.Vector; -import java.util.Set; -import java.util.Map; - -import javax.swing.*; -import javax.swing.border.*; -import javax.swing.table.*; - -import com.gentlyweb.properties.*; - -import com.gentlyweb.utils.*; - -import com.gentlyweb.xml.*; - -import com.jgoodies.forms.builder.*; -import com.jgoodies.forms.factories.*; -import com.jgoodies.forms.layout.*; - -import com.quollwriter.*; - -import com.quollwriter.data.*; -import com.quollwriter.data.comparators.*; - -import com.quollwriter.ui.components.*; - -import org.jdom.*; - -import org.josql.*; - - -public class DebugConsole extends JFrame -{ - - private AbstractViewer viewer = null; - - public DebugConsole(AbstractViewer viewer) - { - - super (UIUtils.getFrameTitle ("Debug Console")); - - this.viewer = viewer; - - this.setMinimumSize (new Dimension (800, - 0)); - - this.setIconImage (Environment.getWindowIcon ().getImage ()); - - this.setDefaultCloseOperation (WindowConstants.DISPOSE_ON_CLOSE); - - JPanel content = new JPanel (new BorderLayout (), - true); - - Box b = new Box (BoxLayout.PAGE_AXIS); - content.add (b); - - b.setOpaque (false); - b.setBorder (new EmptyBorder (5, - 5, - 5, - 5)); - - // Add a tabbed pane. - JTabbedPane tp = new JTabbedPane (); - b.add (tp); - - tp.add ("Logs", - this.createLogPanel ()); - - if (this.viewer instanceof AbstractProjectViewer) - { - - AbstractProjectViewer pv = (AbstractProjectViewer) this.viewer; - - tp.add ("SQL Console", - this.createSQLConsolePanel (pv)); - - tp.add ("Properties", - this.createPropertiesPanel (pv.getProject ().getProperties ())); - - } - - tp.add ("Achievements", - this.createAchievementsPanel ()); - - b.add (Box.createVerticalStrut (5)); - - java.util.List bs = new ArrayList (); - - final DebugConsole _this = this; - - JButton but = new JButton ("Close"); - - but.addActionListener (new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.setVisible (false); - _this.dispose (); - - } - - }); - - bs.add (but); - - b.add (UIUtils.createButtonBar2 ((JButton[]) bs.toArray (new JButton[bs.size ()]), - Component.LEFT_ALIGNMENT)); - - this.getContentPane ().setPreferredSize (new Dimension (800, - 600)); - - this.getContentPane ().add (content); - - this.pack (); - this.pack (); - - this.setVisible (true); - - } - - private Header createHeader (String title) - { - - Header h = UIUtils.createHeader ("Schema Information", - Constants.SUB_PANEL_TITLE); - - h.setBorder (new CompoundBorder (new MatteBorder (0, 0, 1, 0, Environment.getBorderColor ()), - new EmptyBorder (0, 0, 3, 0))); - - return h; - - } - - private JComponent createSQLConsolePanel (final AbstractProjectViewer pv) - { - - final DebugConsole _this = this; - - Box bprops = new Box (BoxLayout.PAGE_AXIS); - bprops.setBorder (new EmptyBorder (5, - 10, - 5, - 10)); - - bprops.add (this.createHeader ("Schema Information")); - - FormLayout fl = new FormLayout ("right:p, 6px, p", - "p, 6px, p, 6px, p, 6px, p"); - - PanelBuilder builder = new PanelBuilder (fl); - - CellConstraints cc = new CellConstraints (); - - final JComboBox words = WarmupPromptSelect.getWordsOptions (); - - int row = 1; - - int max = Environment.getSchemaVersion (); - int projSchemaVersion = -1; - - try - { - - projSchemaVersion = pv.getObjectManager ().getSchemaVersion (); - - } catch (Exception e) { - - Environment.logError ("Unable to get project schema version", - e); - - } - - builder.addLabel ("System schema version", - cc.xy (1, - row)); - - builder.addLabel (max + "", - cc.xy (3, - row)); - - row += 2; - - builder.addLabel ("Project schema version", - cc.xy (1, - row)); - - builder.addLabel (projSchemaVersion + "", - cc.xy (3, - row)); - - row += 2; - - builder.addLabel ("Project db file", - cc.xy (1, - row)); - - String url = "jdbc:h2:" + pv.getObjectManager ().getDBDir ().toString () + "/" + Constants.PROJECT_DB_FILE_NAME_PREFIX + ".h2.db"; - - final JTextField urlf = new JTextField (url); - urlf.setText (url); - urlf.setEditable (false); - urlf.addMouseListener (new MouseAdapter () - { - - public void mouseEntered (MouseEvent ev) - { - - urlf.grabFocus (); - urlf.selectAll (); - - } - - }); - - - builder.add (urlf, - cc.xy (3, - row)); - - row += 2; - - Box versBox = new Box (BoxLayout.X_AXIS); - versBox.setAlignmentX (Component.LEFT_ALIGNMENT); - - Vector vers = new Vector (); - - for (int i = max; i > 0; i--) - { - - vers.add (" " + i); - - } - - final JComboBox versions = new JComboBox (vers); - - versBox.add (versions); - versBox.add (Box.createHorizontalStrut (5)); - - JButton upgradeButton = UIUtils.createButton ("Run"); - versBox.add (upgradeButton); - versBox.add (Box.createHorizontalGlue ()); - - upgradeButton.addActionListener (new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - int ver = -1; - - try - { - - ver = Integer.parseInt ((versions.getSelectedItem () + "").trim ()); - - } catch (Exception e) { - - return; - - } - - try - { - - pv.getObjectManager ().forceRunUpgradeScript (ver); - - } catch (Exception e) { - - UIUtils.showErrorMessage (_this, - "Unable to upgrade to version: " + ver + " see the log for details."); - - Environment.logError ("Unable to upgrade to version: " + ver, - e); - - } - - } - - }); - - builder.addLabel ("Upgrade to version", - cc.xy (1, - row)); - - builder.add (versBox, - cc.xy (3, - row)); - - row += 2; - - JPanel p = builder.getPanel (); - p.setOpaque (false); - p.setAlignmentX (Component.LEFT_ALIGNMENT); - p.setBorder (new EmptyBorder (5, 10, 10, 5)); - - bprops.add (p); - - JSplitPane sp = new JSplitPane (JSplitPane.HORIZONTAL_SPLIT); - sp.setAlignmentX (Component.LEFT_ALIGNMENT); - sp.setDividerLocation (0.5f); - - //bprops.add (sp); - - final JTextArea console = new JTextArea (); - console.setMargin (new Insets (5, - 5, - 5, - 5)); - console.setFont (new Font ("Consolas", - Font.PLAIN, - 12)); - // console.setBorder (null); - - JScrollPane scroll = new JScrollPane (console); - scroll.setBorder (null); - scroll.getViewport ().setBorder (null); - scroll.setAlignmentX (Component.LEFT_ALIGNMENT); - - Box b = new Box (BoxLayout.PAGE_AXIS); - b.add (scroll); - - // Add a button bar. - - sp.setTopComponent (b); - - - Vector colNames = new Vector (); - - /* - JTable tab = new JTable (data, - colNames); - - bprops.add (new JScrollPane (tab)); - */ - return bprops; - - } - - private JComponent createPropertiesPanel (Properties ps) - { - - Box bprops = new Box (BoxLayout.PAGE_AXIS); - bprops.setBorder (new EmptyBorder (10, - 3, - 3, - 3)); - - java.util.List props = ps.getProperties (); - - try - { - - Query q = new Query (); - q.parse ("SELECT * FROM " + AbstractProperty.class.getName () + " ORDER BY iD"); - - QueryResults qr = q.execute (ps.getProperties ()); - - props = qr.getResults (); - - } catch (Exception e) - { - - Environment.logError ("Unable to execute sort query on properties", - e); - - } - - Vector data = new Vector (); - - for (int i = 0; i < props.size (); i++) - { - - Vector d = new Vector (); - - AbstractProperty p = (AbstractProperty) props.get (i); - - d.add (p.getID ()); - - d.add (ps.getDefinedIn (p).getId ()); - - d.add (p.getValue ()); - - data.add (d); - - } - - Vector colNames = new Vector (); - colNames.add ("Name"); - colNames.add ("Scope"); - colNames.add ("Value"); - - JTable tab = new JTable (data, - colNames); - - bprops.add (new JScrollPane (tab)); - - return bprops; - - } - - private JComponent createAchievementsPanel () - { - - Box bprops = new Box (BoxLayout.PAGE_AXIS); - bprops.setBorder (new EmptyBorder (10, - 3, - 3, - 3)); - - Map> achieved = Environment.getAchievedAchievementIds (this.viewer); - - Vector data = new Vector (); - - Set user = achieved.get ("user"); - - for (String id : user) - { - - Vector d = new Vector (); - - d.add ("User"); - d.add (id); - - data.add (d); - - } - - Set project = achieved.get ("project"); - - if (project != null) - { - - for (String id : project) - { - - Vector d = new Vector (); - - d.add ("Project"); - d.add (id); - - data.add (d); - - } - - } - - Vector colNames = new Vector (); - colNames.add ("Type"); - colNames.add ("Id"); - - final JTable tab = new JTable (data, - colNames); - - bprops.add (new JScrollPane (tab)); - - bprops.add (Box.createVerticalStrut (10)); - - JButton b = new JButton ("Clear Selected Achievements"); - - b.setAlignmentX (Component.LEFT_ALIGNMENT); - - final DebugConsole _this = this; - - b.addActionListener (new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - // Get the selected rows. - int[] selRows = tab.getSelectedRows (); - - for (int i = selRows.length - 1; i > -1; i--) - { - - DefaultTableModel mod = (DefaultTableModel) tab.getModel (); - - String id = (String) mod.getValueAt (i, 1); - - try - { - - Environment.removeAchievedAchievement (((String) mod.getValueAt (i, 0)).toLowerCase (), - id, - _this.viewer); - - } catch (Exception e) { - - UIUtils.showErrorMessage (_this, - "Unable to remove achievement: " + id); - - Environment.logError ("Unable to remove achievement: " + id, - e); - - } - - mod.removeRow (i); - - } - - } - - }); - - bprops.add (b); - - return bprops; - - } - - private JComponent createLogPanel () - { - - JTabbedPane tp = new JTabbedPane (); - - tp.setBorder (new EmptyBorder (10, - 5, - 5, - 5)); - - Box errorlog = new Box (BoxLayout.PAGE_AXIS); - errorlog.setBorder (new EmptyBorder (3, - 3, - 3, - 3)); - - File file = Environment.getErrorLogFile (); - - JTextField f = UIUtils.createTextField (); - f.setText (file + ", can write: " + file.canWrite () + ", can read: " + file.canRead ()); - - f.setMaximumSize (new Dimension (Short.MAX_VALUE, - f.getPreferredSize ().height)); - f.setAlignmentX (Component.LEFT_ALIGNMENT); - - errorlog.add (f); - - errorlog.add (Box.createVerticalStrut (5)); - - JTextArea t = new JTextArea (); - - try - { - - t.setText (IOUtils.getFile (file)); - - } catch (Exception e) - { - - try - { - - t.setText ("Unable to read log file: " + - file + - ", Exception: \n" + - GeneralUtils.getExceptionTraceAsString (e)); - - } catch (Exception ee) - { - } - - } - - errorlog.add (Box.createVerticalStrut (5)); - - errorlog.add (new JScrollPane (t)); - - tp.add ("Error", - errorlog); - - Box sqllog = new Box (BoxLayout.PAGE_AXIS); - sqllog.setBorder (new EmptyBorder (3, - 3, - 3, - 3)); - - file = Environment.getSQLLogFile (); - - f = UIUtils.createTextField (); - f.setText (file + ", can write: " + file.canWrite () + ", can read: " + file.canRead ()); - f.setAlignmentX (Component.LEFT_ALIGNMENT); - - f.setMaximumSize (new Dimension (Short.MAX_VALUE, - f.getPreferredSize ().height)); - - sqllog.add (f); - - sqllog.add (Box.createVerticalStrut (5)); - - t = new JTextArea (); - - try - { - - t.setText (IOUtils.getFile (file)); - - } catch (Exception e) - { - - try - { - - t.setText ("Unable to read log file: " + - file + - ", Exception: \n" + - GeneralUtils.getExceptionTraceAsString (e)); - - } catch (Exception ee) - { - } - - } - - sqllog.add (Box.createVerticalStrut (5)); - - sqllog.add (new JScrollPane (t)); - - tp.add ("SQL", - sqllog); - - Box genlog = new Box (BoxLayout.PAGE_AXIS); - genlog.setBorder (new EmptyBorder (3, - 3, - 3, - 3)); - - file = Environment.getGeneralLogFile (); - - f = UIUtils.createTextField (); - f.setText (file + ", can write: " + file.canWrite () + ", can read: " + file.canRead ()); - f.setAlignmentX (Component.LEFT_ALIGNMENT); - - f.setMaximumSize (new Dimension (Short.MAX_VALUE, - f.getPreferredSize ().height)); - - genlog.add (f); - - genlog.add (Box.createVerticalStrut (5)); - - t = new JTextArea (); - - try - { - - t.setText (IOUtils.getFile (file)); - - } catch (Exception e) - { - - try - { - - t.setText ("Unable to read log file: " + - file + - ", Exception: \n" + - GeneralUtils.getExceptionTraceAsString (e)); - - } catch (Exception ee) - { - } - - } - - genlog.add (Box.createVerticalStrut (5)); - - genlog.add (new JScrollPane (t)); - - tp.add ("General", - genlog); - - return tp; - - } - -} diff --git a/src/com/quollwriter/ui/DefaultQuollWriterUpdater.java b/src/com/quollwriter/ui/DefaultQuollWriterUpdater.java deleted file mode 100644 index ba7032e4..00000000 --- a/src/com/quollwriter/ui/DefaultQuollWriterUpdater.java +++ /dev/null @@ -1,754 +0,0 @@ -package com.quollwriter.ui; - -import java.awt.*; -import java.awt.event.*; - -import java.io.*; - -import java.net.*; - -import java.security.*; - -import java.util.*; -import java.util.zip.*; - -import javax.swing.*; -import javax.swing.border.*; -import javax.swing.table.*; - -import com.gentlyweb.properties.*; - -import com.gentlyweb.utils.*; - -import com.gentlyweb.xml.*; - -import com.jgoodies.forms.builder.*; -import com.jgoodies.forms.factories.*; -import com.jgoodies.forms.layout.*; - -import com.quollwriter.*; - -import com.quollwriter.data.*; -import com.quollwriter.data.comparators.*; -import com.quollwriter.ui.*; -import com.quollwriter.ui.components.*; - -import org.jdom.*; - -import static com.quollwriter.LanguageStrings.*; -import static com.quollwriter.Environment.getUIString; - -public class DefaultQuollWriterUpdater implements QuollWriterUpdater -{ - - private AbstractViewer viewer = null; - private JProgressBar progressBar = null; - private boolean stop = false; - private Version version = null; - private long size = 0; - private byte[] digest = null; - private boolean beta = false; - private Notification downloadNotification = null; - private JTextPane help = null; - private JButton cancel = null; - - public DefaultQuollWriterUpdater () - { - - } - - public URL getUpgradeURL (Version version) - throws Exception - { - - String parms = "?version=" + version.getVersion (); - - return Environment.getSupportUrl (Constants.GET_UPGRADE_FILE_PAGE_PROPERTY_NAME, - parms); - - } - - private URL getNewsAndVersionCheckURL () - throws Exception - { - - String parms = "?"; - - if (UserProperties.getAsBoolean (Constants.OPTIN_TO_BETA_VERSIONS_PROPERTY_NAME)) - { - - parms += "beta=true&"; - - } - - String lastVersionCheckTime = UserProperties.get (Constants.LAST_VERSION_CHECK_TIME_PROPERTY_NAME); - - if (lastVersionCheckTime != null) - { - - parms += "since=" + lastVersionCheckTime; - - } - - return Environment.getSupportUrl (Constants.GET_LATEST_VERSION_PAGE_PROPERTY_NAME, - parms); - - } - - private void doDownload () - { - - final java.util.List prefix = new ArrayList<> (); - prefix.add (LanguageStrings.upgrade); - prefix.add (LanguageStrings.download); - - final DefaultQuollWriterUpdater _this = this; - - this.progressBar = new JProgressBar (); - - this.progressBar.setAlignmentX (Component.LEFT_ALIGNMENT); - - int ind = 0; - - Box c = new Box (BoxLayout.Y_AXIS); - - this.help = UIUtils.createHelpTextPane (String.format (Environment.getUIString (prefix, - LanguageStrings.start), - //"Downloading upgrade file for new version: %s", - version), - viewer); - this.help.setAlignmentX (Component.LEFT_ALIGNMENT); - this.help.setSize (new Dimension (500, 50)); - - this.help.setMaximumSize (new Dimension (Short.MAX_VALUE, - Short.MAX_VALUE)); - this.help.setBorder (null); - - c.add (this.help); - - c.add (Box.createVerticalStrut (5)); - - Box pb = new Box (BoxLayout.X_AXIS); - - pb.setAlignmentX (Component.LEFT_ALIGNMENT); - pb.add (this.progressBar); - - pb.add (Box.createHorizontalStrut (5)); - - this.progressBar.setPreferredSize (new Dimension (500, - 20)); - this.progressBar.setMaximumSize (new Dimension (500, - 20)); - - this.cancel = UIUtils.createButton (Environment.getUIString (LanguageStrings.buttons, - LanguageStrings.cancel)); - //"Cancel"); - - pb.add (this.cancel); - - pb.add (Box.createHorizontalGlue ()); - - this.cancel.addActionListener (new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.stop = true; - - _this.downloadNotification.removeNotification (); - - } - - }); - - c.add (pb); - - this.downloadNotification = viewer.addNotification (c, - Constants.DOWNLOAD_ICON_NAME, - -1); - - this.downloadNotification.setOnRemove (new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.stop = true; - - } - - }); - - File tf = null; - - try - { - - tf = File.createTempFile ("QuollWriter-install-" + _this.version.getVersion () + ".", - ".exe"); - -// tf.deleteOnExit (); - - } catch (Exception e) - { - - Environment.logError ("Unable to create temp file for: " + - _this.version + ".exe", - e); - - _this.showError (Environment.getUIString (prefix, - LanguageStrings.errors, - LanguageStrings.cantcreatetemporaryfile)); - //"Unable to create the temporary file for the download."); - - return; - - } - - final File outFile = tf; - - final javax.swing.Timer watch = new javax.swing.Timer (750, - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - int length = (int) outFile.length (); - - float v = (float) length / (float) _this.size; - - float perc = v * 90f; - - _this.help.setText (String.format (Environment.getUIString (prefix, - LanguageStrings.inprogress), - //"Downloading upgrade file for new version %s - %s of %s bytes", - _this.version.getVersion (), - Environment.formatNumber (length), - Environment.formatNumber (size))); - - _this.setProgress ((int) perc); - - _this.help.setSize (new Dimension (500, _this.help.getPreferredSize ().height)); - _this.downloadNotification.validate (); - _this.downloadNotification.repaint (); - - } - - }); - - Runnable r = new Runnable () - { - - @Override - public void run () - { - - try - { - - URL u = _this.getUpgradeURL (_this.version); - - HttpURLConnection conn = (HttpURLConnection) u.openConnection (); - - conn.setDoInput (true); - conn.setDoOutput (true); - - conn.connect (); - - int p = 0; - - BufferedOutputStream out = new BufferedOutputStream (new FileOutputStream (outFile)); - - BufferedInputStream in = new BufferedInputStream (conn.getInputStream ()); - - byte[] buf = new byte[65536]; - - int bRead = -1; - - while ((bRead = in.read (buf)) != -1) - { - - if (_this.stop) - { - - in.close (); - out.flush (); - out.close (); - - return; - - } - - out.write (buf, - 0, - bRead); - - } - - in.close (); - out.flush (); - out.close (); - - _this.setProgress (90); - - watch.stop (); - - if (_this.stop) - { - - return; - - } - - UIUtils.doLater (new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - _this.help.setText (Environment.getUIString (LanguageStrings.upgrade, - LanguageStrings.checkingfile)); - //)"Checking the file...")); - - } - - }); - - // Calculate a hash code. - MessageDigest md = MessageDigest.getInstance ("SHA-256"); - - DigestInputStream dis = new DigestInputStream (new BufferedInputStream (new FileInputStream (outFile)), - md); - - buf = new byte[65536]; - - bRead = -1; - - String ll = outFile.length () + ""; - - ll = ll.substring (ll.length () - 1); - - int v = 0; - - try - { - - v = Integer.parseInt (ll); - - } catch (Exception e) - { - } - - boolean odd = ((v % 2) == 0); - - while ((bRead = dis.read (buf)) != -1) - { - - if (odd) - { - - md.update (ll.getBytes ()); - - } else - { - - md.update (_this.version.getVersion ().getBytes ()); - - } - - } - - dis.close (); - - byte[] ddigest = md.digest (); - - if (_this.stop) - { - - return; - - } - - _this.setProgress (95); - - // Digest calculated from download file is not the same as gained from the server. - String digestNotEqualError = Environment.getUIString (prefix, - LanguageStrings.errors, - LanguageStrings.digestinvalid); - //"Digest calculated from download file is not the same as gained from the server."; - - // Compare the digest with that gained from the server. - if (!Arrays.equals (ddigest, - _this.digest)) - { - - throw new GeneralException (digestNotEqualError); - - } - - UIUtils.doLater (new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - _this.help.setText (Environment.getUIString (prefix, - LanguageStrings.complete)); - //"Download of upgrade file complete..."); - - _this.cancel.setVisible (false); - - } - - }); - - _this.setProgress (100); - - _this.downloadNotification.removeNotification (); - - Map buts = new LinkedHashMap (); - - buts.put (Environment.getUIString (LanguageStrings.upgrade, - LanguageStrings.restart, - LanguageStrings.buttons, - LanguageStrings.exitnow), - //"Yes, exit now", - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - _this.closeDown (); - - } - - }); - - buts.put (Environment.getUIString (LanguageStrings.upgrade, - LanguageStrings.restart, - LanguageStrings.buttons, - LanguageStrings.exitlater), - //"No, I'll exit later", - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - // Do nothing. - - } - - }); - - UIUtils.createQuestionPopup (_this.viewer, - Environment.getUIString (LanguageStrings.upgrade, - LanguageStrings.restart, - LanguageStrings.title), - //"Restart Quoll Writer?", - null, - String.format (getUIString (upgrade,restart,text), - //"Version %s of Quoll Writer has been downloaded. To complete the upgrade you must exit Quoll Writer, the installer will then guide you through the rest of the upgrade process.

    Would you like to exit now?", - _this.version), - buts, - null, - null); - - Environment.addDoOnShutdown (new Runnable () - { - - @Override - public void run () - { - - try - { - - java.util.List args = new ArrayList (); - args.add (outFile.getPath ()); - - ProcessBuilder pb = new ProcessBuilder (args); - pb.start (); - - } catch (Exception e) { - - Environment.logError ("Unable to run upgrade file: " + - outFile.getPath (), - e); - - } - - } - - }); - - } catch (Exception e) - { - - Environment.logError ("Unable to download the upgrade file", - e); - - _this.showError (Environment.getUIString (prefix, - LanguageStrings.errors, - LanguageStrings.unabletodownload)); - //"Unable to download the upgrade file."); - - } - - } - - }; - - Thread t = new Thread (r); - - t.setDaemon (true); - t.setPriority (Thread.MIN_PRIORITY); - - t.start (); - - watch.start (); - - } - - public void doUpdate (AbstractViewer viewer) - { - - final DefaultQuollWriterUpdater _this = this; - - this.viewer = viewer; - - try - { - - URL u = this.getNewsAndVersionCheckURL (); - - HttpURLConnection conn = (HttpURLConnection) u.openConnection (); - - conn.setDoInput (true); - conn.setDoOutput (true); - - conn.connect (); - - BufferedInputStream bin = new BufferedInputStream (conn.getInputStream ()); - - ByteArrayOutputStream bout = new ByteArrayOutputStream (); - - IOUtils.streamTo (bin, - bout, - 8192); - - UserProperties.set (Constants.LAST_VERSION_CHECK_TIME_PROPERTY_NAME, - String.valueOf (System.currentTimeMillis ())); - - String info = new String (bout.toByteArray (), - "utf-8"); - - // Should be json. - Map data = (Map) JSONDecoder.decode (info); - - Map version = (Map) data.get ("version"); - - if (version != null) - { - - this.version = new Version ((String) version.get ("version")); - - this.size = ((Number) version.get ("size")).longValue (); - - this.digest = com.quollwriter.Base64.decode ((String) version.get ("digest")); - - if (Environment.getQuollWriterVersion ().isNewer (this.version)) - { - - UIUtils.doLater (new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - Box ib = new Box (BoxLayout.Y_AXIS); - ib.setMaximumSize (new Dimension (Short.MAX_VALUE, - Short.MAX_VALUE)); - - JTextPane p = UIUtils.createHelpTextPane (String.format (Environment.getUIString (LanguageStrings.upgrade, - LanguageStrings.newversionavailable, - LanguageStrings.text), - //"A new version of %s is available. View the changes.", - // Constants.QUOLL_WRITER_NAME, - _this.version.getVersion ().replace (".", - "_")), - viewer); - - p.setAlignmentX (Component.LEFT_ALIGNMENT); - - p.setMaximumSize (new Dimension (Short.MAX_VALUE, - Short.MAX_VALUE)); - p.setBorder (null); - - ib.add (p); - ib.add (Box.createVerticalStrut (5)); - - JButton installNow = UIUtils.createButton (Environment.getUIString (LanguageStrings.upgrade, - LanguageStrings.newversionavailable, - LanguageStrings.buttons, - LanguageStrings.download)); - //"Download now"); - JButton installLater = UIUtils.createButton (Environment.getUIString (LanguageStrings.upgrade, - LanguageStrings.newversionavailable, - LanguageStrings.buttons, - LanguageStrings.later)); - //"Later"); - - Box bb = new Box (BoxLayout.X_AXIS); - bb.add (installNow); - bb.add (Box.createHorizontalStrut (5)); - bb.add (installLater); - bb.setAlignmentX (Component.LEFT_ALIGNMENT); - - ib.add (bb); - ib.add (Box.createVerticalStrut (5)); - - final ActionListener hasVersionNotification = _this.viewer.addNotification (ib, - "notify", - 600); - - installNow.addActionListener (new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - hasVersionNotification.actionPerformed (ev); - - _this.doDownload (); - - } - - }); - - installLater.addActionListener (hasVersionNotification); - - } - - }); - - } - - } - - } catch (Exception e) - { - - Environment.logError ("Unable to perform update check", - e); - - } - - } - - private void showError (String m) - { - - UIUtils.showErrorMessage (this.viewer, - m); - - this.downloadNotification.removeNotification (); - - } - - private void showGeneralError () - { - - this.showError (String.format (Environment.getUIString (LanguageStrings.upgrade, - LanguageStrings.download, - LanguageStrings.errors, - LanguageStrings.general), - //"Unable to download/install the new version. Click here to download the latest version from the Quoll Writer website", - Environment.getProperty (Constants.QUOLLWRITER_DOWNLOADS_URL_PROPERTY_NAME))); - - this.downloadNotification.removeNotification (); - - } - - public void setProgress (int p) - { - - final DefaultQuollWriterUpdater _this = this; - - UIUtils.doLater (new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - _this.progressBar.setValue (p); - _this.downloadNotification.validate (); - _this.downloadNotification.repaint (); - - } - - }); - - } - - private void closeDown () - { - - final DefaultQuollWriterUpdater _this = this; - - Map open = Environment.getOpenProjects (); - - // Get the first, close it. - if (open.size () > 0) - { - - AbstractProjectViewer pv = open.values ().iterator ().next (); - - pv.setState (java.awt.Frame.NORMAL); - pv.toFront (); - - pv.close (false, - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - _this.closeDown (); - - } - - }); - - return; - - } else { - - if (Environment.getLanding () != null) - { - - Environment.getLanding ().close (false, - null); - - } else { - - Environment.closeDown (); - - } - - } - - - } - -} diff --git a/src/com/quollwriter/ui/DictionaryManager.java b/src/com/quollwriter/ui/DictionaryManager.java deleted file mode 100644 index 754ea14e..00000000 --- a/src/com/quollwriter/ui/DictionaryManager.java +++ /dev/null @@ -1,232 +0,0 @@ -package com.quollwriter.ui; - -import java.awt.*; -import java.awt.event.*; - -import java.io.File; - -import java.net.*; - -import java.text.*; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.StringTokenizer; -import java.util.Vector; -import java.util.Set; -import java.util.TreeSet; -import java.util.HashSet; - -import javax.swing.*; -import javax.swing.border.*; -import javax.swing.filechooser.*; -import javax.swing.table.*; -import javax.swing.tree.*; -import javax.swing.event.*; - -import com.gentlyweb.utils.*; - -import com.gentlyweb.xml.*; - -//import com.jgoodies.forms.builder.*; -//import com.jgoodies.forms.factories.*; -//import com.jgoodies.forms.layout.*; - -import com.quollwriter.*; - -import com.quollwriter.data.*; -import com.quollwriter.data.comparators.*; -import com.quollwriter.events.*; - -import static com.quollwriter.LanguageStrings.*; -import static com.quollwriter.Environment.getUIString; - -import com.quollwriter.ui.components.*; -import com.quollwriter.ui.renderers.*; - -public class DictionaryManager extends TypesEditor implements TypesHandler -{ - - private FileWatcher watcher = null; - private Set listeners = new HashSet<> (); - private UserDictionaryProvider userDict = null; - - public DictionaryManager (final AbstractViewer pv) - throws Exception - { - - super (pv); - - this.userDict = new UserDictionaryProvider (); - - } - - @Override - public boolean renameType (String oldType, - String newType, - boolean reload) - { - - this.removeType (oldType, - reload); - this.addType (newType, - reload); - - return true; - - } - - @Override - public boolean removeType (String type, - boolean reload) - { - - this.userDict.removeWord (type); - - this.viewer.fireProjectEvent (ProjectEvent.PERSONAL_DICTIONARY, - ProjectEvent.REMOVE_WORD, - type); - - return true; - - } - - @Override - public void addType (String t, - boolean reload) - { - - this.userDict.addWord (t); - - this.viewer.fireProjectEvent (ProjectEvent.PERSONAL_DICTIONARY, - ProjectEvent.ADD_WORD, - t); - - } - - @Override - public Set getTypes () - { - - // Get the words. - File userDict = Environment.getUserDictionaryFile (); - - Set words = new TreeSet<> (); - - String w = null; - - try - { - - w = IOUtils.getFile (userDict); - - } catch (Exception e) - { - - w = ""; - - Environment.logError ("Unable to get user dictionary file: " + - userDict, - e); - - } - - StringTokenizer tt = new StringTokenizer (w, - String.valueOf ('\n')); - - while (tt.hasMoreTokens ()) - { - - words.add (tt.nextToken ()); - - } - - return words; - - } - - @Override - public void removePropertyChangedListener (PropertyChangedListener l) - { - - this.listeners.remove (l); - - } - - @Override - public void addPropertyChangedListener (PropertyChangedListener l) - { - - this.listeners.add (l); - - } - - @Override - public TypesHandler getTypesHandler () - { - - return this; - - } - - @Override - public String getNewItemsTitle () - { - - return getUIString (dictionary,manage,newwords,title); - } - - @Override - public String getNewItemsHelp () - { - - return getUIString (dictionary,manage,newwords,text); - } - - @Override - public String getExistingItemsTitle () - { - - return getUIString (dictionary,manage,table,title); - - } - - @Override - public void init () - { - - super.init (); - - final DictionaryManager _this = this; - - this.watcher = new FileWatcher (); - this.watcher.addFile (Environment.getUserDictionaryFile ()); - - this.watcher.addFileChangeListener (new FileChangeListener () - { - - public void fileChanged (FileChangeEvent ev, - int types) - { - - // Tell the listeners about the change. - for (PropertyChangedListener l : _this.listeners) - { - - l.propertyChanged (new PropertyChangedEvent (_this, - "changed", - 0, - 0)); - - } - - } - - }, - FileChangeEvent.MODIFIED | FileChangeEvent.EXISTS); - - this.watcher.start (); - - } - -} diff --git a/src/com/quollwriter/ui/FindResultsBox.java b/src/com/quollwriter/ui/FindResultsBox.java deleted file mode 100644 index 630aec83..00000000 --- a/src/com/quollwriter/ui/FindResultsBox.java +++ /dev/null @@ -1,142 +0,0 @@ -package com.quollwriter.ui; - -import java.awt.event.*; - -import javax.swing.*; -import javax.swing.tree.*; - -import com.quollwriter.data.*; - -public abstract class FindResultsBox extends ProjectObjectsAccordionItem -{ - - protected int count = 0; - - private String forObjType = null; - - public FindResultsBox (String title, - ImageIcon icon, - E viewer) - { - - super (title, - icon, - viewer); - - this.getTree ().getSelectionModel().setSelectionMode (TreeSelectionModel.SINGLE_TREE_SELECTION); - - } - - public FindResultsBox (String title, - String iconType, - String forObjType, - E viewer) - { - - super (title, - iconType, - viewer); - - this.forObjType = forObjType; - - this.getTree ().getSelectionModel().setSelectionMode (TreeSelectionModel.SINGLE_TREE_SELECTION); - - } - - @Override - public String getId () - { - - return this.forObjType; - - } - - @Override - public boolean showItemCountOnHeader () - { - - return true; - - } - - public void exapndAllResultsInTree () - { - - UIUtils.expandAllNodesWithChildren (this.tree); - - } - - public int getItemCount () - { - - return this.count; - - } - - @Override - public void reloadTree () - { - - } - - public void fillTreePopupMenu (JPopupMenu m, - MouseEvent ev) - { - - } - - @Override - public TreeCellEditor getTreeCellEditor (AbstractProjectViewer pv) - { - - return null; - - } - - public int getViewObjectClickCount (Object d) - { - - return 1; - - } - - @Override - public boolean isAllowObjectPreview () - { - - return true; - - } - - public boolean isTreeEditable () - { - - return false; - - } - - public boolean isDragEnabled () - { - - return false; - - } - - @Override - public DragActionHandler getTreeDragActionHandler (AbstractProjectViewer pv) - { - - return null; - - } - - public void clearResults () - { - - ((DefaultTreeModel) this.tree.getModel ()).setRoot (null); - - this.setVisible (false); - - } - -} diff --git a/src/com/quollwriter/ui/FirstUseWizard.java b/src/com/quollwriter/ui/FirstUseWizard.java deleted file mode 100644 index d0c2e4ec..00000000 --- a/src/com/quollwriter/ui/FirstUseWizard.java +++ /dev/null @@ -1,1641 +0,0 @@ -package com.quollwriter.ui; - -import java.io.*; -import java.net.*; -import java.util.*; -import java.awt.event.*; -import javax.swing.*; -import javax.swing.tree.*; -import javax.swing.filechooser.*; - -import com.jgoodies.forms.builder.*; -import com.jgoodies.forms.factories.*; -import com.jgoodies.forms.layout.*; - -import com.quollwriter.*; -import com.quollwriter.events.*; -import com.quollwriter.data.*; -import com.quollwriter.importer.*; -import com.quollwriter.data.comparators.*; -import com.quollwriter.ui.renderers.*; -import com.quollwriter.text.*; - -import static com.quollwriter.LanguageStrings.*; -import static com.quollwriter.Environment.getUIString; - -public class FirstUseWizard extends PopupWizard -{ - - private final static String SELECT_FILE_STAGE = "select-file"; - private final static String DECIDE_STAGE = "decide"; - private final static String START_STAGE = "start"; - private static final String EXISTING_STAGE = "existing"; - private static final String NEW_PROJECT_STAGE = "newproject"; - private static final String IMPORT_STAGE = "import"; - private static final String SELECT_PROJECT_DB_STAGE = "select-project-db"; - private static final String SPELL_CHECK_LANG_STAGE = "spell-check-lang"; - - private ImportTransferHandlerOverlay importOverlay = null; - private ImportProject importProject = null; - private JRadioButton importFile = null; - private JTree itemsTree = null; - private Project importProj = null; - - private JRadioButton createNewProject = null; - private NewProjectPanel newProjectPanel = null; - - private JRadioButton selectProjectDB = null; - private JRadioButton findProjects = null; - private FileFinder projDBFind = null; - private JLabel projDBFindError = null; - private JLabel dlUILangFile = null; - private JLabel dlUILangError = null; - - private FileFinder fileFind = null; - private JLabel fileFindError = null; - - public FirstUseWizard () - { - - super (null); - - final FirstUseWizard _this = this; - - this.importFile = new JRadioButton (); - this.createNewProject = new JRadioButton (); - this.findProjects = new JRadioButton (); - this.selectProjectDB = new JRadioButton (); - this.importFile.setSelected (false); - this.createNewProject.setSelected (false); - - this.newProjectPanel = new NewProjectPanel (); - - this.importProject = new ImportProject (); - this.importProject.init (); - - this.projDBFind = new FileFinder (); - - // This doesn't appear to ever be visible... - this.projDBFindError = UIUtils.createErrorLabel (""); - //Please select a directory."); - - this.fileFindError = UIUtils.createErrorLabel (""); - //"Please select a file to import."); - this.fileFind = new FileFinder (); - this.fileFind.setFileFilter (ImportProject.fileFilter); - this.fileFind.setClearOnCancel (true); - this.fileFind.showCancel (true, - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - _this.enableButton ("next", - false); - - } - - }); - - this.itemsTree = UIUtils.createTree (); - this.itemsTree.setModel (null); - - this.importOverlay = new ImportTransferHandlerOverlay (); - - this.importOverlay.addMouseListener (new MouseEventHandler () - { - - public void handlePress (MouseEvent ev) - { - - _this.importOverlay.setVisible (false); - - _this.validate (); - _this.repaint (); - - } - - }); - - this.setTransferHandler (new ImportTransferHandler (new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - File f = (File) ev.getSource (); - - _this.importOverlay.setFile (f); - - _this.setGlassPane (_this.importOverlay); - - _this.importOverlay.setVisible (true); - _this.validate (); - _this.repaint (); - - } - - }, - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.importOverlay.setVisible (false); - _this.validate (); - _this.repaint (); - - File f = (File) ev.getSource (); - - _this.importProject.setFile (f); - _this.fileFind.setFile (f); - _this.importFile.setSelected (true); - - _this.setImportFile (f); - - _this.showStage (IMPORT_STAGE); - - } - - }, - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.importOverlay.setVisible (false); - _this.validate (); - _this.repaint (); - - } - - }, - new java.io.FileFilter () - { - - @Override - public boolean accept (File f) - { - - return ImportProject.isSupportedFileType (f); - - } - - })); - - } - - @Override - public String getWindowTitle () - { - - return this.getHeaderTitle (); - - } - - @Override - public String getHeaderTitle () - { - - return Environment.getUIString (firstusewizard,title); - //return "Welcome to Quoll Writer"; - - } - - @Override - public String getHeaderIconType () - { - - return null; - - } - - @Override - public String getHelpText () - { - - return Environment.getUIString (firstusewizard,text); - //"Welcome to Quoll Writer, this page will help you get started. Don't worry, there are only a couple of questions and then you can get started on your first {project}."; - - } - - @Override - public int getMaximumContentHeight () - { - - return 350; - - } - - @Override - public boolean handleFinish () - { - - if ((this.importFile.isSelected ()) - || - (this.createNewProject.isSelected ()) - ) - { - - return this.newProjectPanel.createProject (this); - - } - - return true; - - } - - @Override - public void handleCancel () - { - - } - - @Override - public String getNextStage (String currStage) - { - - if (START_STAGE.equals (currStage)) - { - - return SPELL_CHECK_LANG_STAGE; - - } - - if (SPELL_CHECK_LANG_STAGE.equals (currStage)) - { - - return DECIDE_STAGE; - - } - - if (SELECT_FILE_STAGE.equals (currStage)) - { - - return IMPORT_STAGE; - - } - - if (EXISTING_STAGE.equals (currStage)) - { - - return SELECT_PROJECT_DB_STAGE; - - } - - if (IMPORT_STAGE.equals (currStage)) - { - - return NEW_PROJECT_STAGE; - - } - - if (DECIDE_STAGE.equals (currStage)) - { - - if (this.createNewProject.isSelected ()) - { - - return NEW_PROJECT_STAGE; - - } - - if (this.importFile.isSelected ()) - { - - return SELECT_FILE_STAGE; - - } - - return IMPORT_STAGE; - - } - - return null; - - } - - @Override - public String getPreviousStage (String currStage) - { - - if (SELECT_PROJECT_DB_STAGE.equals (currStage)) - { - - return EXISTING_STAGE; - - } - - if (SPELL_CHECK_LANG_STAGE.equals (currStage)) - { - - return START_STAGE; - - } - - if (START_STAGE.equals (currStage)) - { - - return null; - - } - - if (NEW_PROJECT_STAGE.equals (currStage)) - { - - return DECIDE_STAGE; - - } - - if (EXISTING_STAGE.equals (currStage)) - { - - return START_STAGE; - - } - - if (IMPORT_STAGE.equals (currStage)) - { - - return SELECT_FILE_STAGE; - - } - - if (SELECT_FILE_STAGE.equals (currStage)) - { - - return DECIDE_STAGE; - - } - - if (DECIDE_STAGE.equals (currStage)) - { - - return SPELL_CHECK_LANG_STAGE; - - } - - return null; - - } - - @Override - public boolean handleStageChange (String oldStage, - String newStage) - { - - final FirstUseWizard _this = this; - - if (SELECT_FILE_STAGE.equals (oldStage)) - { - - if (!IMPORT_STAGE.equals (newStage)) - { - - return true; - - } - - this.fileFindError.setVisible (false); - - File f = this.fileFind.getSelectedFile (); - - if (!f.isFile ()) - { - - this.fileFindError.setText (getUIString (firstusewizard,stages,selectfile,errors,novalue)); - this.fileFindError.setVisible (true); - - return false; - - } - - return true; - - } - - if (DECIDE_STAGE.equals (oldStage)) - { - - if (START_STAGE.equals (newStage)) - { - - return true; - - } - - return true; -/* - if (this.importFile.isSelected ()) - { - - this.showStage (SELECT_FILE_STAGE); - - return false; - - } - - if (this.createNewProject.isSelected ()) - { - - this.newProjectPanel.setProject (null); - this.newProjectPanel.setName (null); - - this.showStage (NEW_PROJECT_STAGE); - - return false; - - } -*/ - } - - if ((START_STAGE.equals (oldStage)) - && - (SPELL_CHECK_LANG_STAGE.equals (newStage)) - ) - { - - this.enableButton ("next", - true); - - String lsid = UserProperties.get (Constants.USER_UI_LANGUAGE_PROPERTY_NAME); - - try - { - - if (Environment.getUILanguageStrings (lsid) == null) - { - - this.enableButton ("next", - false); - - // Show the downloading message. - this.dlUILangFile.setVisible (true); - - Environment.downloadUILanguageFile (lsid, - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - // Set the language. - try - { - - Environment.setUILanguage (lsid); - - } catch (Exception e) { - - Environment.logError ("Unable to set ui language to: " + lsid, - e); - - UIUtils.showErrorMessage (_this, - getUIString (uilanguage,set,actionerror)); - - _this.dlUILangError.setVisible (true); - _this.dlUILangFile.setVisible (false); - - return; - - } - - _this.dlUILangFile.setVisible (true); - _this.showStage (SPELL_CHECK_LANG_STAGE); - - } - - }, - // On error - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - UIUtils.showErrorMessage (_this, - getUIString (uilanguage,set,actionerror)); - - _this.dlUILangFile.setVisible (false); - - _this.dlUILangError.setVisible (true); - - } - - }); - - this.validate (); - this.repaint (); - - //this.xxx - - return false; - - } else { - - // Set the language. - try - { - - Environment.setUILanguage (lsid); - - } catch (Exception e) { - - Environment.logError ("Unable to set ui language to: " + lsid, - e); - - UIUtils.showErrorMessage (_this, - getUIString (uilanguage,set,actionerror)); - - _this.dlUILangError.setVisible (true); - _this.dlUILangFile.setVisible (false); - - return false; - - } - - _this.dlUILangFile.setVisible (true); - _this.showStage (SPELL_CHECK_LANG_STAGE); - - } - - } catch (Exception e) { - - Environment.logError ("Unable to get ui language strings for: " + lsid, - e); - - UIUtils.showErrorMessage (this, - getUIString (firstusewizard,stages,start,actionerror)); - - return false; - - } - - } - - if ((SPELL_CHECK_LANG_STAGE.equals (oldStage)) - && - (DECIDE_STAGE.equals (newStage)) - ) - { - - this.enableButton ("next", - false); - - return true; - - } - - if ((EXISTING_STAGE.equals (oldStage)) - && - (newStage == null) - ) - { - - if (this.findProjects.isSelected ()) - { - - Environment.showLanding (); - - Environment.getLanding ().showFindProjects (); - - this.close (); - - return false; - - } - - } - - return true; - - } - - @Override - public String getStartStage () - { - - return START_STAGE; - - } - - @Override - public WizardStep getStage (String stage) - { - - final FirstUseWizard _this = this; - - WizardStep ws = new WizardStep (); - - if (NEW_PROJECT_STAGE.equals (stage)) - { - - java.util.List prefix = Arrays.asList (firstusewizard,stages,newproject); - - ws.title = Environment.getUIString (prefix, - title); - //"{Project} details"; - - ws.helpText = Environment.getUIString (prefix, - text); - //"Enter the name of the {project} below and select the directory where it should be saved."; - - ws.panel = this.newProjectPanel.createPanel (this, - null, - false, - null, - false); - - return ws; - - } - - if (SELECT_PROJECT_DB_STAGE.equals (stage)) - { - - java.util.List prefix = Arrays.asList (firstusewizard,stages,selectprojectdb); - - ws.title = Environment.getUIString (prefix, - title); - //"Select your {projects} directory"; - ws.helpText = String.format (Environment.getUIString (prefix, - text), - //"Use the finder below to find the directory where your {projects} database file is stored. The file is called %s%s", - Environment.getProjectInfoDBFile ().getName () + Constants.H2_DB_FILE_SUFFIX); - - Box b = new Box (BoxLayout.Y_AXIS); - - this.projDBFindError.setVisible (false); - this.projDBFindError.setBorder (UIUtils.createPadding (0, 5, 5, 5)); - b.add (this.projDBFindError); - - FormLayout fl = new FormLayout ("right:p, 6px, fill:200px:grow, 10px", - "p"); - - PanelBuilder builder = new PanelBuilder (fl); - - CellConstraints cc = new CellConstraints (); - - this.projDBFind.setOnSelectHandler (new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - //_this.file = _this.fileFind.getSelectedFile (); - - //_this.checkForFileToImport (); - - _this.enableButton ("next", - true); - - } - - }); - - this.projDBFind.setApproveButtonText (Environment.getUIString (prefix, - finder, - button)); - //"Select"); - this.projDBFind.setFinderSelectionMode (JFileChooser.DIRECTORIES_ONLY); - this.projDBFind.setFinderTitle (Environment.getUIString (prefix, - finder, - title)); - //"Select the directory"); - - this.projDBFind.setFile (Environment.getUserQuollWriterDir ()); - - this.projDBFind.setFindButtonToolTip (Environment.getUIString (prefix, - finder, - tooltip)); - //"Click to find a directory"); - this.projDBFind.setClearOnCancel (true); - this.projDBFind.init (); - - builder.addLabel (Environment.getUIString (prefix, - LanguageStrings.finder, - LanguageStrings.label), - //"Directory", - cc.xy (1, - 1)); - builder.add (this.projDBFind, - cc.xy (3, - 1)); - - JPanel p = builder.getPanel (); - p.setOpaque (false); - p.setAlignmentX (JComponent.LEFT_ALIGNMENT); - - b.add (p); - - ws.panel = b; - - return ws; - - } - - if (EXISTING_STAGE.equals (stage)) - { - - java.util.List prefix = new ArrayList<> (); - prefix.add (LanguageStrings.firstusewizard); - prefix.add (LanguageStrings.stages); - prefix.add (LanguageStrings.existing); - - ws.title = Environment.getUIString (prefix, - LanguageStrings.title); - //"Find your {projects}"; - ws.helpText = Environment.getUIString (prefix, - LanguageStrings.text); - //"If you would like {QW} to find your {projects} then click Finish below."; - - FormLayout fl = new FormLayout ("10px, p, 10px", - "p, 6px, p, 6px, p, 6px"); - - PanelBuilder builder = new PanelBuilder (fl); - - CellConstraints cc = new CellConstraints (); - - this.findProjects.setText (Environment.getUIString (prefix, - LanguageStrings.labels, - LanguageStrings.find)); - //.replaceObjectNames ("{QW} should find my {projects}")); - - this.findProjects.setOpaque (false); - - this.selectProjectDB = new JRadioButton (Environment.getUIString (prefix, - LanguageStrings.labels, - LanguageStrings.manual)); - //"I know where my {projects} database is")); - - this.selectProjectDB.setOpaque (false); - - ButtonGroup bg = new ButtonGroup (); - - bg.add (this.findProjects); - bg.add (this.selectProjectDB); - - this.findProjects.setSelected (false); - this.selectProjectDB.setSelected (false); - - this.findProjects.addActionListener (new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.enableButton ("next", - true); - - } - - }); - - this.selectProjectDB.addActionListener (new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.enableButton ("next", - true); - - } - - }); - - builder.add (this.findProjects, - cc.xy (2, - 1)); - - builder.add (this.selectProjectDB, - cc.xy (2, - 3)); - - JPanel p = builder.getPanel (); - p.setOpaque (false); - p.setAlignmentX (JComponent.LEFT_ALIGNMENT); - - ws.panel = p; - - return ws; - - - } - - if (DECIDE_STAGE.equals (stage)) - { - - java.util.List prefix = new ArrayList<> (); - prefix.add (LanguageStrings.firstusewizard); - prefix.add (LanguageStrings.stages); - prefix.add (LanguageStrings.decide); - - ws.title = Environment.getUIString (prefix, - LanguageStrings.title); - //"Your first {project}"; - ws.helpText = Environment.getUIString (prefix, - LanguageStrings.text); - //"If you already have your story in a .docx or .doc file then use the import option below, otherwise use the create option. You can also just drag your .docx or .doc file onto this window."; - - FormLayout fl = new FormLayout ("p", - "p, 6px, p"); - - PanelBuilder builder = new PanelBuilder (fl); - - CellConstraints cc = new CellConstraints (); - - this.importFile.setText (Environment.getUIString (prefix, - LanguageStrings.labels, - LanguageStrings.importfile)); - //"Import a File"); - - this.importFile.setOpaque (false); - - this.createNewProject = new JRadioButton (Environment.getUIString (prefix, - LanguageStrings.labels, - LanguageStrings.newproject)); - //Environment.replaceObjectNames ("Create a {project}")); - - this.createNewProject.setOpaque (false); - - ButtonGroup bg = new ButtonGroup (); - - bg.add (this.importFile); - bg.add (this.createNewProject); - - this.importFile.addActionListener (new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.enableButton ("next", - true); - - } - - }); - - this.createNewProject.addActionListener (new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.enableButton ("next", - true); - - } - - }); - - builder.add (this.createNewProject, - cc.xy (1, - 1)); - - builder.add (this.importFile, - cc.xy (1, - 3)); - - JPanel p = builder.getPanel (); - p.setOpaque (false); - p.setAlignmentX (JComponent.LEFT_ALIGNMENT); - p.setAlignmentY (JComponent.TOP_ALIGNMENT); - - Box b = new Box (BoxLayout.Y_AXIS); - - b.add (p); - b.add (Box.createVerticalGlue ()); - - JLabel l = UIUtils.createClickableLabel (Environment.getUIString (prefix, - LanguageStrings.labels, - LanguageStrings.notfirst), - //"Not your first {project}? Click here to find your {projects}.", - Environment.getIcon (Constants.FIND_ICON_NAME, - Constants.ICON_CLICKABLE_LABEL), - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - Environment.showLanding (); - - Environment.getLanding ().showFindProjects (); - - _this.close (); - - } - - }); - - b.add (l); - - ws.panel = b; - - return ws; - - } - - if (SELECT_FILE_STAGE.equals (stage)) - { - - java.util.List prefix = new ArrayList<> (); - prefix.add (LanguageStrings.firstusewizard); - prefix.add (LanguageStrings.stages); - prefix.add (LanguageStrings.selectfile); - - ws.title = Environment.getUIString (prefix, - LanguageStrings.title); - //"Select a file to import"; - ws.helpText = Environment.getUIString (prefix, - LanguageStrings.text); - //"Microsoft Word files (.doc and .docx) are supported. Please check the import guide to ensure your file has the correct format."; - - Box b = new Box (BoxLayout.Y_AXIS); - - this.fileFindError.setVisible (false); - this.fileFindError.setBorder (UIUtils.createPadding (0, 5, 5, 5)); - b.add (this.fileFindError); - - FormLayout fl = new FormLayout ("right:p, 6px, fill:200px:grow, 10px", - "p"); - - PanelBuilder builder = new PanelBuilder (fl); - - CellConstraints cc = new CellConstraints (); - - this.fileFind.setApproveButtonText (Environment.getUIString (prefix, - LanguageStrings.finder, - LanguageStrings.button)); - //"Select"); - this.fileFind.setFinderSelectionMode (JFileChooser.FILES_ONLY); - this.fileFind.setFinderTitle (Environment.getUIString (prefix, - LanguageStrings.finder, - LanguageStrings.title)); - //"Select a file to import"); - - if (this.fileFind.getSelectedFile () == null) - { - - this.fileFind.setFile (FileSystemView.getFileSystemView ().getDefaultDirectory ()); - - } - - this.fileFind.setOnSelectHandler (new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.setImportFile (_this.fileFind.getSelectedFile ()); - - } - - }); - - this.fileFind.setFileFilter (ImportProject.fileFilter); - - this.fileFind.setFindButtonToolTip (Environment.getUIString (prefix, - LanguageStrings.finder, - LanguageStrings.tooltip)); - //"Click to find a file"); - this.fileFind.setClearOnCancel (true); - this.fileFind.init (); - - builder.addLabel (Environment.getUIString (prefix, - LanguageStrings.finder, - LanguageStrings.label), - //"File", - cc.xy (1, - 1)); - builder.add (this.fileFind, - cc.xy (3, - 1)); - - JPanel p = builder.getPanel (); - p.setOpaque (false); - p.setAlignmentX (JComponent.LEFT_ALIGNMENT); - - b.add (p); - - ws.panel = b; - - return ws; - - } - - if (IMPORT_STAGE.equals (stage)) - { - - java.util.List prefix = new ArrayList<> (); - prefix.add (LanguageStrings.firstusewizard); - prefix.add (LanguageStrings.stages); - prefix.add (LanguageStrings.selectitems); - - ws.title = Environment.getUIString (prefix, - LanguageStrings.title); - //"Select the items you wish to import"; - - ws.helpText = Environment.getUIString (prefix, - LanguageStrings.text); - //"Check the items below to ensure that they match what is in your file. The first and last sentences of the description (if present) are shown for each item."; - - this.itemsTree.addMouseListener (new MouseAdapter () - { - - private void selectAllChildren (DefaultTreeModel model, - DefaultMutableTreeNode n, - boolean v) - { - - Enumeration en = n.children (); - - while (en.hasMoreElements ()) - { - - DefaultMutableTreeNode c = en.nextElement (); - - Object uo = c.getUserObject (); - - if (uo instanceof SelectableDataObject) - { - - SelectableDataObject s = (SelectableDataObject) uo; - - s.selected = v; - - // Tell the model that something has changed. - model.nodeChanged (c); - - // Iterate. - this.selectAllChildren (model, - c, - v); - - } - - } - - } - - public void mousePressed (MouseEvent ev) - { - - TreePath tp = _this.itemsTree.getPathForLocation (ev.getX (), - ev.getY ()); - - if (tp != null) - { - - DefaultMutableTreeNode n = (DefaultMutableTreeNode) tp.getLastPathComponent (); - - // Tell the model that something has changed. - DefaultTreeModel model = (DefaultTreeModel) _this.itemsTree.getModel (); - - if (n.getUserObject () instanceof SelectableDataObject) - { - - SelectableDataObject s = (SelectableDataObject) n.getUserObject (); - - s.selected = !s.selected; - - model.nodeChanged (n); - - this.selectAllChildren (model, - n, - s.selected); - - } - - } - - } - - }); - - this.itemsTree.setCellRenderer (new SelectableProjectTreeCellRenderer ()); - - this.itemsTree.setOpaque (false); - this.itemsTree.setBorder (UIUtils.createPadding (5, 5, 5, 5)); - - JScrollPane sp = UIUtils.createScrollPane (this.itemsTree); - - ws.panel = sp; - - return ws; - - } - - if (SPELL_CHECK_LANG_STAGE.equals (stage)) - { - - java.util.List prefix = Arrays.asList (firstusewizard,stages,spellcheck); - - ws.title = Environment.getUIString (prefix, - title); - //"Select the spell checker language"; - - ws.helpText = Environment.getUIString (prefix, - text); - //"Welcome to Quoll Writer, this wizard will help you get started.

    First, select the language you would like to use for the spell checker. You can download additional languages in the Options panel later."; - - Box b = new Box (BoxLayout.Y_AXIS); - JComboBox lb = UIUtils.getSpellCheckLanguagesSelector (new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - // Set the property. - String lang = ev.getActionCommand (); - - UserProperties.set (Constants.SPELL_CHECK_LANGUAGE_PROPERTY_NAME, - lang); - - } - - }, - UserProperties.get (Constants.SPELL_CHECK_LANGUAGE_PROPERTY_NAME)); - - lb.setMaximumSize (lb.getPreferredSize ()); - - Box wrap = new Box (BoxLayout.X_AXIS); - - wrap.add (lb); - wrap.add (Box.createHorizontalGlue ()); - wrap.setAlignmentX (JComponent.LEFT_ALIGNMENT); - wrap.setAlignmentY (JComponent.TOP_ALIGNMENT); - - b.add (wrap); - b.add (Box.createVerticalGlue ()); - - ws.panel = b; - - return ws; - - } - - if (START_STAGE.equals (stage)) - { - - java.util.List prefix = Arrays.asList (firstusewizard,stages,start); - - ws.title = getUIString (prefix,title); - - ws.helpText = getUIString (prefix,text); - - Box b = new Box (BoxLayout.Y_AXIS); - - JComboBox ub = UIUtils.getUILanguagesSelector (new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - // Set the property. - String uilid = ev.getActionCommand (); - - UserProperties.set (Constants.USER_UI_LANGUAGE_PROPERTY_NAME, - uilid); - - } - - }, - UserProperties.get (Constants.USER_UI_LANGUAGE_PROPERTY_NAME)); - - ub.setMaximumSize (ub.getPreferredSize ()); - - Box wrap = new Box (BoxLayout.X_AXIS); - - wrap.add (ub); - wrap.add (Box.createHorizontalGlue ()); - wrap.setAlignmentX (JComponent.LEFT_ALIGNMENT); - wrap.setAlignmentY (JComponent.TOP_ALIGNMENT); - - b.add (wrap); - - this.dlUILangFile = UIUtils.createInformationLabel (getUIString (prefix,downloading)); - this.dlUILangFile.setVisible (false); - - this.dlUILangFile.setBorder (UIUtils.createPadding (10, 0, 0, 5)); - this.dlUILangFile.setIcon (Environment.getIcon (Constants.INFO_ICON_NAME, - Constants.ICON_MENU)); - - b.add (this.dlUILangFile); - - this.dlUILangError = UIUtils.createErrorLabel (getUIString(firstusewizard,stages,start,actionerror)); - this.dlUILangError.setVisible (false); - - this.dlUILangError.setBorder (UIUtils.createPadding (10, 0, 0, 5)); - - b.add (this.dlUILangError); - - b.add (Box.createVerticalGlue ()); - - ws.panel = b; - - return ws; - - } - - return null; - - } - - @Override - protected void enableButtons (String currentStage) - { - - super.enableButtons (currentStage); - - if (DECIDE_STAGE.equals (currentStage)) - { - - this.enableButton ("next", - (this.importFile.isSelected () || this.createNewProject.isSelected ())); - - } - - if (SELECT_FILE_STAGE.equals (currentStage)) - { - - this.enableButton ("next", - (this.fileFind.getSelectedFile () != null)); - - } - - if (SELECT_PROJECT_DB_STAGE.equals (currentStage)) - { - - File f = this.projDBFind.getSelectedFile (); - - boolean enable = false; - - if (f != null) - { - - File pf = this.getProjectDBFile (f); - - enable = pf.exists () && pf.isFile (); - - } - - this.enableButton ("next", - enable); - - return; - - } - - if (EXISTING_STAGE.equals (currentStage)) - { - - this.enableButton ("next", - (this.selectProjectDB.isSelected () || this.findProjects.isSelected ())); - - } - - } - - private File getProjectDBFile (File dir) - { - - return new File (dir, - Constants.PROJECT_INFO_DB_FILE_NAME_PREFIX + Constants.H2_DB_FILE_SUFFIX); - - } - - private void addAssetsToTree (DefaultMutableTreeNode root, - UserConfigurableObjectType type, - Set assets) - { - - if ((assets == null) - || - (assets.size () == 0) - ) - { - - return; - - } - - TreeParentNode c = new TreeParentNode (type.getObjectTypeId (), - type.getObjectTypeNamePlural ()); - - SelectableDataObject sd = new SelectableDataObject (c); - - sd.selected = true; - - DefaultMutableTreeNode tn = new DefaultMutableTreeNode (sd); - - root.add (tn); - - java.util.List lassets = new ArrayList (assets); - - Collections.sort (lassets, - NamedObjectSorter.getInstance ()); - - for (Asset a : lassets) - { - - sd = new SelectableDataObject (a); - - sd.selected = true; - - DefaultMutableTreeNode n = new DefaultMutableTreeNode (sd); - - tn.add (n); - - String t = this.getFirstLastSentence (a.getDescriptionText ()); - - if (t.length () > 0) - { - - // Get the first and last sentence. - n.add (new DefaultMutableTreeNode (t)); - - } - - } - - } - - private Project getSelectedItems () - { - - String projName = null; - - Project p = new Project (projName); - - Book b = new Book (p, - null); - - p.addBook (b); - b.setName (projName); - - DefaultTreeModel dtm = (DefaultTreeModel) this.itemsTree.getModel (); - - DefaultMutableTreeNode root = (DefaultMutableTreeNode) dtm.getRoot (); - - Enumeration en = root.depthFirstEnumeration (); - - while (en.hasMoreElements ()) - { - - DefaultMutableTreeNode node = (DefaultMutableTreeNode) en.nextElement (); - - Object o = node.getUserObject (); - - if (o instanceof SelectableDataObject) - { - - SelectableDataObject so = (SelectableDataObject) o; - - if (so.selected) - { - - if (so.obj instanceof Asset) - { - - p.addAsset ((Asset) so.obj); - - } - - if (so.obj instanceof Chapter) - { - - b.addChapter ((Chapter) so.obj); - - } - - } - - } - - } - - if ((b.getChapters () != null) - && - (b.getChapters ().size () == 0) - ) - { - - p.getBooks ().remove (b); - - } - - return p; - - } - - private void setImportFile (final File f) - { - - final FirstUseWizard _this = this; - - try - { - - Importer.importProject (f.toURI (), - new ImportCallback () - { - - @Override - public void exceptionOccurred (Exception e, - URI uri) - { - - Environment.logError ("Unable to import file: " + - f, - e); - - UIUtils.showErrorMessage (_this, - Environment.getUIString (LanguageStrings.firstusewizard, - LanguageStrings.stages, - LanguageStrings.importfile, - LanguageStrings.actionerror)); - //"Unable to import file"); - - } - - @Override - public void projectCreated (final Project p, - URI uri) - { - - UIUtils.doLater (new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - if (_this.itemsTree != null) - { - - _this.itemsTree.setModel (new DefaultTreeModel (_this.createTree (p))); - - UIUtils.expandAllNodesWithChildren (_this.itemsTree); - - _this.importProj = p; - - _this.newProjectPanel.setName (p.getName ()); - - _this.newProjectPanel.setProject (p); - - } - - } - - }); - - } - - }); - - - - } catch (Exception e) { - - Environment.logError ("Unable to import file: " + - f, - e); - - UIUtils.showErrorMessage (this, - Environment.getUIString (LanguageStrings.firstusewizard, - LanguageStrings.stages, - LanguageStrings.importfile, - LanguageStrings.actionerror)); - //"Unable to import file"); - - } - - } - - private DefaultMutableTreeNode createTree (Project p) - { - - DefaultMutableTreeNode root = new DefaultMutableTreeNode (new SelectableDataObject (p)); - - DefaultMutableTreeNode n = null; - DefaultMutableTreeNode tn = null; - - if (p.getBooks ().size () > 0) - { - - Book b = p.getBooks ().get (0); - - if (b.getChapters ().size () > 0) - { - - TreeParentNode c = new TreeParentNode (Chapter.OBJECT_TYPE, - Environment.getObjectTypeNamePlural (Chapter.OBJECT_TYPE)); - - SelectableDataObject sd = new SelectableDataObject (c); - - sd.selected = true; - - tn = new DefaultMutableTreeNode (sd); - - root.add (tn); - - Collections.sort (b.getChapters (), - NamedObjectSorter.getInstance ()); - - for (Chapter ch : b.getChapters ()) - { - - sd = new SelectableDataObject (ch); - - sd.selected = true; - - n = new DefaultMutableTreeNode (sd); - - tn.add (n); - - String t = this.getFirstLastSentence (ch.getChapterText ()); - - if (t.length () > 0) - { - - // Get the first and last sentence. - n.add (new DefaultMutableTreeNode (t)); - - } - - } - - } - - } - - Set assetTypes = Environment.getAssetUserConfigurableObjectTypes (true); - - for (UserConfigurableObjectType t : assetTypes) - { - - Set as = p.getAssets (t); - - this.addAssetsToTree (root, - t, - as); - - } - - return root; - - } - - private String getFirstLastSentence (String st) - { - - if (st == null) - { - - return ""; - - } - - TextIterator t = new TextIterator (st); - - Paragraph p = t.getFirstParagraph (); - - if (p != null) - { - - Sentence s = p.getFirstSentence (); - - StringBuilder b = new StringBuilder (); - - b.append (s.getText ()); - - p = t.getLastParagraph (); - - if (p != null) - { - - b.append (" ... "); - - b.append (p.getLastSentence ().getText ()); - - } - - return b.toString (); - - } - - return ""; - - } - -} diff --git a/src/com/quollwriter/ui/FullScreenTextProperties.java b/src/com/quollwriter/ui/FullScreenTextProperties.java deleted file mode 100644 index 0929ebf4..00000000 --- a/src/com/quollwriter/ui/FullScreenTextProperties.java +++ /dev/null @@ -1,242 +0,0 @@ -package com.quollwriter.ui; - -import java.awt.Color; - -import com.gentlyweb.properties.*; - -import com.quollwriter.*; -import com.quollwriter.data.*; -import com.quollwriter.ui.sidebars.*; -import com.quollwriter.ui.panels.*; -import com.quollwriter.events.*; -import com.quollwriter.ui.components.TextProperties; -import com.quollwriter.ui.components.QTextEditor; - -public class FullScreenTextProperties extends TextProperties implements UserPropertySetter -{ - - private boolean allowSet = true; - - public FullScreenTextProperties () - { - - this.initInternal (UserProperties.get (Constants.FULL_SCREEN_EDITOR_FONT_PROPERTY_NAME, - Constants.EDITOR_FONT_PROPERTY_NAME), - UserProperties.getAsInt (Constants.FULL_SCREEN_EDITOR_FONT_SIZE_PROPERTY_NAME, - Constants.EDITOR_FONT_SIZE_PROPERTY_NAME), - UserProperties.get (Constants.FULL_SCREEN_EDITOR_ALIGNMENT_PROPERTY_NAME, - Constants.EDITOR_ALIGNMENT_PROPERTY_NAME), - UserProperties.getAsBoolean (Constants.FULL_SCREEN_EDITOR_INDENT_FIRST_LINE_PROPERTY_NAME, - Constants.EDITOR_INDENT_FIRST_LINE_PROPERTY_NAME), - UserProperties.getAsFloat (Constants.FULL_SCREEN_EDITOR_LINE_SPACING_PROPERTY_NAME, - Constants.EDITOR_LINE_SPACING_PROPERTY_NAME), - UIUtils.getColor (UserProperties.get (Constants.FULL_SCREEN_EDITOR_FONT_COLOR_PROPERTY_NAME, - Constants.EDITOR_FONT_COLOR_PROPERTY_NAME)), - UIUtils.getColor (UserProperties.get (Constants.FULL_SCREEN_EDITOR_FONT_BGCOLOR_PROPERTY_NAME, - Constants.EDITOR_BGCOLOR_PROPERTY_NAME)), - UIUtils.getColor (UserProperties.get (Constants.FULL_SCREEN_EDITOR_WRITING_LINE_COLOR_PROPERTY_NAME, - Constants.EDITOR_WRITING_LINE_COLOR_PROPERTY_NAME)), - UserProperties.getAsBoolean (Constants.FULL_SCREEN_EDITOR_HIGHLIGHT_WRITING_LINE_PROPERTY_NAME, - Constants.EDITOR_HIGHLIGHT_WRITING_LINE_PROPERTY_NAME), - UserProperties.getAsInt (Constants.FULL_SCREEN_EDITOR_TEXT_BORDER_PROPERTY_NAME, - Constants.EDITOR_TEXT_BORDER_PROPERTY_NAME) - ); - - } - - public FullScreenTextProperties (TextProperties props) - { - - this.initInternal (props); - - } - - @Override - public void stopSetting () - { - - this.allowSet = false; - - } - - @Override - public void startSetting () - { - - this.allowSet = true; - - } - - public void setBackgroundColor (Color c) - { - - super.setBackgroundColor (c); - - if (c.equals (this.getTextColor ())) - { - - if (c.equals (Color.black)) - { - - // Set the background to white. - this.setTextColor (Color.white); - - } - - if (c.equals (Color.white)) - { - - // Set the background to black. - this.setTextColor (Color.black); - - } - - } - - this.setProperty (new StringProperty (Constants.FULL_SCREEN_EDITOR_FONT_BGCOLOR_PROPERTY_NAME, - UIUtils.colorToHex (this.getBackgroundColor ()))); - - } - - public void setTextColor (Color c) - { - - super.setTextColor (c); - - if (c.equals (this.getBackgroundColor ())) - { - - if (c.equals (Color.black)) - { - - this.setBackgroundColor (Color.white); - - } - - if (c.equals (Color.white)) - { - - // Set the background to black. - this.setBackgroundColor (Color.black); - - } - - } - - this.setProperty (new StringProperty (Constants.FULL_SCREEN_EDITOR_FONT_COLOR_PROPERTY_NAME, - UIUtils.colorToHex (this.getTextColor ()))); - - } - - public void setWritingLineColor (Color c) - { - - super.setWritingLineColor (c); - - this.setProperty (new StringProperty (Constants.FULL_SCREEN_EDITOR_WRITING_LINE_COLOR_PROPERTY_NAME, - UIUtils.colorToHex (this.getWritingLineColor ()))); - - } - - public void setHighlightWritingLine (boolean v) - { - - super.setHighlightWritingLine (v); - - this.setProperty (new BooleanProperty (Constants.FULL_SCREEN_EDITOR_HIGHLIGHT_WRITING_LINE_PROPERTY_NAME, - v)); - - } - - public void setLineSpacing (float v) - { - - super.setLineSpacing (v); - - this.setProperty (new FloatProperty (Constants.FULL_SCREEN_EDITOR_LINE_SPACING_PROPERTY_NAME, - this.getLineSpacing ())); - - } - - public void setFirstLineIndent (boolean v) - { - - super.setFirstLineIndent (v); - - this.setProperty (new BooleanProperty (Constants.FULL_SCREEN_EDITOR_INDENT_FIRST_LINE_PROPERTY_NAME, - this.getFirstLineIndent ())); - - } - - public void setAlignment (String v) - { - - super.setAlignment (v); - - this.setProperty (new StringProperty (Constants.FULL_SCREEN_EDITOR_ALIGNMENT_PROPERTY_NAME, - this.getAlignment ())); - - } - - public void setFontSize (int v) - { - - super.setFontSize (v); - - this.setProperty (new IntegerProperty (Constants.FULL_SCREEN_EDITOR_FONT_SIZE_PROPERTY_NAME, - this.getFontSize ())); - - } - - public void setTextBorder (int v) - { - - super.setTextBorder (v); - - this.setProperty (new IntegerProperty (Constants.FULL_SCREEN_EDITOR_TEXT_BORDER_PROPERTY_NAME, - this.getTextBorder ())); - - } - - public void setFontFamily (String f) - { - - super.setFontFamily (f); - - this.setProperty (new StringProperty (Constants.FULL_SCREEN_EDITOR_FONT_PROPERTY_NAME, - this.getFontFamily ())); - - } - - private void setProperty (AbstractProperty prop) - { - - if (!this.allowSet) - { - - return; - - } - - UserProperties.set (prop.getID (), - prop); - - } - - public void resetToDefaults () - { - - this.setBackgroundColor (UIUtils.getColor (UserProperties.get (Constants.DEFAULT_EDITOR_BGCOLOR_PROPERTY_NAME))); - this.setTextColor (UIUtils.getColor (UserProperties.get (Constants.DEFAULT_EDITOR_FONT_COLOR_PROPERTY_NAME))); - this.setTextBorder (UserProperties.getAsInt (Constants.DEFAULT_EDITOR_TEXT_BORDER_PROPERTY_NAME)); - this.setFontFamily (UserProperties.get (Constants.DEFAULT_EDITOR_FONT_PROPERTY_NAME)); - this.setFontSize (UserProperties.getAsInt (Constants.DEFAULT_EDITOR_FONT_SIZE_PROPERTY_NAME)); - this.setAlignment (Environment.getDefaultTextAlignment ()); - this.setFirstLineIndent (UserProperties.getAsBoolean (Constants.DEFAULT_EDITOR_INDENT_FIRST_LINE_PROPERTY_NAME)); - this.setLineSpacing (UserProperties.getAsFloat (Constants.DEFAULT_EDITOR_LINE_SPACING_PROPERTY_NAME)); - this.setWritingLineColor (UIUtils.getColor (UserProperties.get (Constants.DEFAULT_EDITOR_WRITING_LINE_COLOR_PROPERTY_NAME))); - this.setHighlightWritingLine (UserProperties.getAsBoolean (Constants.DEFAULT_EDITOR_HIGHLIGHT_WRITING_LINE_PROPERTY_NAME)); - - } - -} diff --git a/src/com/quollwriter/ui/LanguageStringsEditor.java b/src/com/quollwriter/ui/LanguageStringsEditor.java deleted file mode 100644 index 1b3ac8f9..00000000 --- a/src/com/quollwriter/ui/LanguageStringsEditor.java +++ /dev/null @@ -1,5156 +0,0 @@ -package com.quollwriter.ui; - -import java.awt.*; -import java.io.*; -import java.awt.datatransfer.*; -import java.awt.event.*; -import java.util.*; -import java.util.concurrent.*; -import java.text.*; -import java.net.*; - -import javax.swing.*; -import javax.swing.border.*; -import javax.swing.text.*; -import javax.swing.event.*; -import javax.swing.filechooser.*; -import javax.swing.plaf.LayerUI; -import javax.swing.tree.*; - -import com.gentlyweb.properties.*; -import com.gentlyweb.utils.*; - -import org.josql.*; - -import com.jgoodies.forms.builder.*; -import com.jgoodies.forms.factories.*; -import com.jgoodies.forms.layout.*; - -import com.quollwriter.*; -import com.quollwriter.events.*; -import com.quollwriter.data.*; -import com.quollwriter.ui.events.*; -import com.quollwriter.data.comparators.*; -import com.quollwriter.data.editors.*; -import com.quollwriter.editors.*; -import com.quollwriter.ui.components.*; -import com.quollwriter.ui.panels.*; -import com.quollwriter.text.*; -import com.quollwriter.db.*; -import com.quollwriter.ui.sidebars.*; -import com.quollwriter.editors.*; -import com.quollwriter.editors.ui.*; -import com.quollwriter.editors.ui.sidebars.*; -import com.quollwriter.achievements.ui.*; -import com.quollwriter.ui.charts.*; -import com.quollwriter.ui.actionHandlers.*; -import com.quollwriter.ui.forms.*; -import com.quollwriter.ui.components.ScrollableBox; -import com.quollwriter.ui.components.SpellChecker; - -import static com.quollwriter.LanguageStrings.*; -import static com.quollwriter.Environment.getUIString; - -public class LanguageStringsEditor extends AbstractViewer implements RefValueProvider -{ - - public static final int DEFAULT_WINDOW_WIDTH = 800; - public static final int DEFAULT_WINDOW_HEIGHT = 500; - public static final int PROJECT_BOX_WIDTH = 250; - - public static final String MAIN_CARD = "main"; - public static final String OPTIONS_CARD = "options"; - - public static final String SUBMIT_HEADER_CONTROL_ID = "submit"; - public static final String USE_HEADER_CONTROL_ID = "use"; - public static final String HELP_HEADER_CONTROL_ID = "help"; - public static final String FIND_HEADER_CONTROL_ID = "find"; - - public static int INTERNAL_SPLIT_PANE_DIVIDER_WIDTH = 2; - - private JSplitPane splitPane = null; - private Header title = null; - private Box notifications = null; - private Box sideBar = null; - private Box sideBarWrapper = null; - private Box toolbarPanel = null; - private AbstractSideBar currentSideBar = null; - private AccordionItemsSideBar mainSideBar = null; - private Map sideBars = new HashMap (); - private Stack activeSideBars = new Stack (); - private java.util.List sideBarListeners = new ArrayList (); - private java.util.List mainPanelListeners = new ArrayList (); - private JPanel cards = null; - private CardLayout cardsLayout = null; - private JLabel importError = null; - private JLabel forwardLabel = null; - private ImportTransferHandlerOverlay importOverlay = null; - private Map panels = new HashMap (); - private String currentCard = null; - ///private Finder finder = null; - private LanguageStrings userStrings = null; - private String toolbarLocation = null; - private Map sectionTrees = new LinkedHashMap<> (); - private LanguageStrings baseStrings = null; - private LanguageStrings.Filter nodeFilter = null; - private Map> valuesCache = new HashMap<> (); - - public LanguageStringsEditor (LanguageStrings userStrings) - throws Exception - { - - this (userStrings, - Environment.getQuollWriterVersion ()); - - } - - public LanguageStringsEditor (LanguageStrings userStrings, - Version baseQWVersion) - throws Exception - { - - if (baseQWVersion == null) - { - - baseQWVersion = Environment.getQuollWriterVersion (); - - } - - final LanguageStringsEditor _this = this; - - if (userStrings == null) - { - - throw new IllegalArgumentException ("No strings provided."); - - } - - this.baseStrings = Environment.getUserUIEnglishLanguageStrings (baseQWVersion); - - if (this.baseStrings == null) - { - - throw new IllegalArgumentException ("Unable to find English strings for version: " + baseQWVersion); - - } - - // Create a split pane. - this.splitPane = new JSplitPane (JSplitPane.HORIZONTAL_SPLIT, - false); - this.splitPane.setDividerSize (UIUtils.getSplitPaneDividerSize ()); - this.splitPane.setBorder (null); - - javax.swing.plaf.basic.BasicSplitPaneDivider div = ((javax.swing.plaf.basic.BasicSplitPaneUI) this.splitPane.getUI ()).getDivider (); - div.setBorder (new MatteBorder (0, 0, 0, 1, Environment.getBorderColor ())); - this.splitPane.setOpaque (false); - this.splitPane.setBackground (UIUtils.getComponentColor ()); - - this.cardsLayout = new CardLayout (0, 0); - - this.cards = new JPanel (this.cardsLayout); - this.cards.setBackground (UIUtils.getComponentColor ()); - - this.splitPane.setRightComponent (this.cards); - - this.userStrings = userStrings; - - this.updateTitle (); - - this.forwardLabel = UIUtils.createClickableLabel ("", - Environment.getIcon (Constants.INFO_ICON_NAME, - Constants.ICON_CLICKABLE_LABEL)); - this.forwardLabel.setBorder (UIUtils.createBottomLineWithPadding (5, 5, 5, 5)); - - UIUtils.makeClickable (this.forwardLabel, - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - try - { - - if (_this.nodeFilter != null) - { - - _this.showAllStrings (); - - } else { - - _this.limitViewToPreviousVersionDiff (); - - } - - } catch (Exception e) { - - Environment.logError ("Unable to update view", - e); - - UIUtils.showErrorMessage (_this, - "Unable to update view."); - - } - - } - - }); - - // Create the sidebar. - this.mainSideBar = new AccordionItemsSideBar (this, - null)//items) - { - - @Override - public JComponent getContent () - { - - Box b = new Box (BoxLayout.Y_AXIS); - - b.add (_this.forwardLabel); - - _this.forwardLabel.setVisible (Environment.getQuollWriterVersion ().isNewer (_this.userStrings.getQuollWriterVersion ())); - - b.add (super.getContent ()); - - b.setBorder (UIUtils.createPadding (0, 0, 0, 0)); - - b.setPreferredSize (new Dimension (200, Short.MAX_VALUE)); - - return b; - - } - - @Override - public Dimension getMinimumSize () - { - - return new Dimension (200, - 250); - } - - @Override - public void panelShown (MainPanelEvent ev) - { - - _this.setIdSelectedInSidebar (ev.getPanel ().getPanelId ()); - - } - - }; - - this.initSideBar (); -/* - this.finder = new Finder (this); - - this.addSideBar (this.finder); -*/ - this.currentSideBar = this.mainSideBar; - - this.addMainPanelListener (this.currentSideBar); - - this.currentSideBar.init (null); - - this.sideBarWrapper = new Box (BoxLayout.Y_AXIS); - this.toolbarPanel = new Box (BoxLayout.Y_AXIS); - this.sideBarWrapper.setAlignmentX (LEFT_ALIGNMENT); - this.toolbarPanel.setAlignmentX (LEFT_ALIGNMENT); - - this.sideBar = new Box (BoxLayout.Y_AXIS); - this.sideBar.add (this.sideBarWrapper); - //this.sideBar.add (this.toolbarPanel); - - this.setToolbarLocation (null); - - JButton saveB = UIUtils.createToolBarButton (Constants.SAVE_ICON_NAME, - "Save all the strings", - "save", - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - //_this.userValue.setText (defValue); - - } - - }); - - JButton nextB = UIUtils.createToolBarButton (Constants.NEXT_ICON_NAME, - "Go to the next section", - "next", - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - //_this.userValue.setText (defValue); - - } - - }); - - this.toolbarPanel.add (UIUtils.createButtonBar (Arrays.asList (saveB, nextB))); - - this.toolbarPanel.setMaximumSize (new Dimension (Short.MAX_VALUE, - this.toolbarPanel.getPreferredSize ().height)); - - this.splitPane.setLeftComponent (this.sideBar); - - this.sideBarWrapper.add (this.currentSideBar); - - this.setContent (this.splitPane); - - this.importOverlay = new ImportTransferHandlerOverlay (); - - this.importOverlay.addMouseListener (new MouseEventHandler () - { - - public void handlePress (MouseEvent ev) - { - - _this.importOverlay.setVisible (false); - - _this.validate (); - _this.repaint (); - - } - - }); - - this.setTransferHandler (new ImportTransferHandler (new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - File f = (File) ev.getSource (); - - _this.importOverlay.setFile (f); - - _this.setGlassPane (_this.importOverlay); - - _this.importOverlay.setVisible (true); - _this.validate (); - _this.repaint (); - - } - - }, - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.importOverlay.setVisible (false); - _this.validate (); - _this.repaint (); - - File f = (File) ev.getSource (); - - } - - }, - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.importOverlay.setVisible (false); - _this.validate (); - _this.repaint (); - - } - - }, - new java.io.FileFilter () - { - - @Override - public boolean accept (File f) - { - - return f.getName ().endsWith (".json"); - - } - - })); - - this.setMinimumSize (new Dimension (500, 500)); - - // Check to see if a new version of the default strings is available. - Environment.schedule (new Runnable () - { - - @Override - public void run () - { - - String url = Environment.getProperty (Constants.QUOLL_WRITER_GET_UI_LANGUAGE_STRINGS_URL_PROPERTY_NAME); - - url = StringUtils.replaceString (url, - Constants.VERSION_TAG, - _this.baseStrings.getQuollWriterVersion ().toString ()); - url = StringUtils.replaceString (url, - Constants.ID_TAG, - _this.baseStrings.getId ()); - - url = StringUtils.replaceString (url, - Constants.LAST_MOD_TAG, - "0"); - - url += "&newer=true"; - - try - { - - String data = Environment.getUrlFileAsString (new URL (Environment.getQuollWriterWebsite () + "/" + url)); - - if (data.startsWith (Constants.JSON_RETURN_PREFIX)) - { - - data = data.substring (Constants.JSON_RETURN_PREFIX.length ()); - - } - - Object obj = JSONDecoder.decode (data); - - if (obj == null) - { - - return; - - } - - final LanguageStrings newls = new LanguageStrings (data); - - Box content = new Box (BoxLayout.Y_AXIS); - - content.add (UIUtils.createHelpTextPane (String.format ("A new version of the %s language strings is available. This is for version %s, of {QW}.
    You can view the changes and submit an update to your strings.", - newls.getNativeName (), - newls.getQuollWriterVersion ().toString ()), - _this)); - - content.add (Box.createVerticalStrut (5)); - - JButton b = UIUtils.createButton ("View the changes"); - - content.add (b); - - // Add a notification. - final Notification n = _this.addNotification (content, - Constants.INFO_ICON_NAME, - -1); - - b.addActionListener (new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - LanguageStrings uls = null; - - try - { - - uls = Environment.getUserUILanguageStrings (newls.getQuollWriterVersion (), - _this.userStrings.getId ()); - - } catch (Exception e) { - - Environment.logError ("Unable to get user strings for version: " + newls.getQuollWriterVersion () + ", " + _this.userStrings.getId (), - e); - - UIUtils.showErrorMessage (null, - getUIString (uilanguage,edit,actionerror)); - - return; - - } - - if (uls != null) - { - - // Open these instead. - LanguageStringsEditor lse = Environment.editUILanguageStrings (uls, - uls.getQuollWriterVersion ()); - - try - { - - lse.limitViewToPreviousVersionDiff (); - - } catch (Exception e) { - - Environment.logError ("Unable to update view", - e); - - UIUtils.showErrorMessage (_this, - "Unable to update view"); - - return; - - } - - _this.removeNotification (n); - - return; - - } - - _this.showChanges (newls); - - _this.removeNotification (n); - - } - - }); - - } catch (Exception e) { - - Environment.logError ("Unable to get new user interface strings", - e); - - } - - } - - }, - 5, - -1); - - } - - private int getErrorCount (LanguageStrings.Node n) - { - - int c = 0; - - // Get the card. - IdsPanel p = this.panels.get (n.getNodeId ()); - - if (p != null) - { - - return p.getErrorCount (); - - } - - for (LanguageStrings.Value nv : this.valuesCache.get (n)) - { - - LanguageStrings.Value uv = this.userStrings.getValue (nv.getId (), - true); - - if (uv != null) - { - - if (LanguageStrings.getErrors (uv.getRawText (), - LanguageStrings.toId (nv.getId ()), - nv.getSCount (), - this).size () > 0) - { - - c++; - - } - - } - - } - - return c; - - } - - private int getUserValueCount (LanguageStrings.Node n) - { - - int c = 0; - - // Get the card. - IdsPanel p = this.panels.get (n.getNodeId ()); - - if (p != null) - { - - return p.getUserValueCount (); - - } - - for (LanguageStrings.Value nv : this.valuesCache.get (n)) - { - - LanguageStrings.Value uv = this.userStrings.getValue (nv.getId (), - true); - - if (uv != null) - { - - c++; - - } - - } - - return c; - - } - - private void initSideBar () - { - - String defSection = "General"; - - Map> sections = this.baseStrings.getNodesInSections (defSection); - - java.util.List items = new ArrayList<> (); - - this.valuesCache = new HashMap<> (); - - for (LanguageStrings.Section sect : this.baseStrings.getSections ()) - { - - AccordionItem it = this.createSectionTree (sect.name, - sect.icon, - sections.get (sect.id)); - - if (it == null) - { - - continue; - - } - - items.add (it); - - } - - this.mainSideBar.setItems (items); - - if (this.nodeFilter == null) - { - - this.forwardLabel.setText (String.format ("Click to show what's changed/new between version %s and %s.", - Environment.getQuollWriterVersion ().toString (), - this.userStrings.getQuollWriterVersion ().toString ())); - - } else { - - this.forwardLabel.setText (String.format ("Click to show all the strings for version %s.", - this.userStrings.getQuollWriterVersion ().toString ())); - - } - - } - - private void showAllStrings () - { - - try - { - - this.save (); - - } catch (Exception e) { - - Environment.logError ("Unable to save", - e); - - UIUtils.showErrorMessage (this, - "Unable to update view."); - - return; - - } - - // Clear out the panel cache. - this.panels = new HashMap<> (); - - this.currentCard = null; - this.cards.removeAll (); - - this.nodeFilter = null; - this.initSideBar (); - - this.validate (); - this.repaint (); - - } - - private void showChanges (LanguageStrings newls) - { - - Version v = this.userStrings.getQuollWriterVersion (); - - try - { - - Environment.saveUserUILanguageStrings (newls); - - this.userStrings.setQuollWriterVersion (newls.getQuollWriterVersion ()); - - Environment.saveUserUILanguageStrings (this.userStrings); - - this.userStrings.setQuollWriterVersion (v); - - LanguageStrings uls = Environment.getUserUILanguageStrings (newls.getQuollWriterVersion (), - this.userStrings.getId ()); - - // Get a diff of the default to this new. - LanguageStringsEditor lse = Environment.editUILanguageStrings (uls, - newls.getQuollWriterVersion ()); - lse.limitViewToPreviousVersionDiff (); - - } catch (Exception e) { - - Environment.logError ("Unable to show strings editor for: " + - newls, - e); - - UIUtils.showErrorMessage (this, - "Unable to show strings."); - - } - - } - - private void limitViewToPreviousVersionDiff () - throws Exception - { - - try - { - - this.save (); - - } catch (Exception e) { - - Environment.logError ("Unable to save", - e); - - UIUtils.showErrorMessage (this, - "Unable to update view."); - - return; - - } - - final LanguageStrings basels = this.baseStrings; - - // Get the previous version (which will be the current QW version). - final LanguageStrings prevbasels = Environment.getUserUIEnglishLanguageStrings (Environment.getQuollWriterVersion ()); - - if (prevbasels == null) - { - - // No strings. - return; - - } - - this.nodeFilter = new LanguageStrings.Filter () - { - - @Override - public boolean accept (LanguageStrings.Node n) - { - - LanguageStrings.Node pn = prevbasels.getNode (n.getId ()); - - // Does the node exist in the current base strings but not the previous? - if (pn == null) - { - - // This is a new node. - return true; - - } - - // It exists, but has it changed? - if ((n instanceof LanguageStrings.Value) - && - (!(pn instanceof LanguageStrings.Value)) - ) - { - - // Node type changed. - return true; - - } - - if ((pn instanceof LanguageStrings.Value) - && - (!(n instanceof LanguageStrings.Value)) - ) - { - - // Node type changed. - return true; - - } - - if ((pn instanceof LanguageStrings.Value) - && - (n instanceof LanguageStrings.Value) - ) - { - - LanguageStrings.Value pnv = (LanguageStrings.Value) pn; - LanguageStrings.Value nv = (LanguageStrings.Value) n; - - // Value changed? - if (pnv.getRawText ().equals (nv.getRawText ())) - { - - return false; - - } - - } - - return true; - - } - - }; - - this.initSideBar (); - - // Clear out the panel cache. - this.panels = new HashMap<> (); - - this.currentCard = null; - this.cards.removeAll (); - - this.validate (); - this.repaint (); - - } - - private void updateSideBar (LanguageStrings.Node n) - { - - for (JTree t : this.sectionTrees.values ()) - { - - // See how many children there are. - TreePath tp = UIUtils.getTreePathForUserObject ((DefaultMutableTreeNode) t.getModel ().getRoot (), - n.getRoot ()); - - if (tp != null) - { - - ((DefaultTreeModel) t.getModel ()).nodeChanged ((DefaultMutableTreeNode) tp.getLastPathComponent ()); - - t.validate (); - t.repaint (); - - break; - - } - - } - - this.sideBar.validate (); - this.sideBar.repaint (); - - } - - private void updateSideBar () - { - - this.sideBar.validate (); - this.sideBar.repaint (); - - } - - private void saveToFile () - throws Exception - { - - Environment.saveUserUILanguageStrings (this.userStrings); - - } - - private void save () - throws Exception - { - - // Cycle over all the id boxes and set the values if present. - for (IdsPanel p : this.panels.values ()) - { - - p.saveValues (); - - } - - this.userStrings.setQuollWriterVersion (this.baseStrings.getQuollWriterVersion ()); - - this.saveToFile (); - - } - - private void fireMainPanelShownEvent (QuollPanel p) - { - - MainPanelEvent ev = new MainPanelEvent (this, - p); - - for (MainPanelListener l : this.mainPanelListeners) - { - - l.panelShown (ev); - - } - - } - - public void removeMainPanelListener (MainPanelListener l) - { - - this.mainPanelListeners.remove (l); - - } - - public void addMainPanelListener (MainPanelListener l) - { - - this.mainPanelListeners.add (l); - - } - - public String getPreviewText (String t) - { - - return LanguageStrings.buildText (t, - this); - - } - - @Override - public String getString (String id) - { - - java.util.List idparts = LanguageStrings.getIdParts (id); - - // See if we have a panel. - if (idparts.size () > 0) - { - - IdsPanel p = this.panels.get (idparts.get (0)); - - if (p != null) - { - - String t = p.getIdValue (id); - - if (t != null) - { - - return this.getPreviewText (t); - - } - - } - - } - - return this.userStrings.getString (id); - - } - - @Override - public int getSCount (String id) - { - - return this.baseStrings.getSCount (id); - - } - - @Override - public String getRawText (String id) - { - - java.util.List idparts = LanguageStrings.getIdParts (id); - - // See if we have a panel. - if (idparts.size () > 0) - { - - IdsPanel p = this.panels.get (idparts.get (0)); - - if (p != null) - { - - String t = p.getIdValue (id); - - if (t != null) - { - - return t; - - } - - } - - } - - return this.userStrings.getRawText (id); - - } - - private void updateTitle () - { - - this.setViewerTitle (String.format ("Edit Language Strings for: %s (%s)", - this.userStrings.getNativeName (), - this.baseStrings.getQuollWriterVersion ().toString ())); - - } - - public void setToolbarLocation (String loc) - { - - if (loc == null) - { - - loc = Constants.BOTTOM; - - } -/* - if (loc.equals (Constants.TOP)) - { - - this.toolbarPanel.setBorder (new CompoundBorder (new MatteBorder (0, 0, 1, 0, UIUtils.getBorderColor ()), - new EmptyBorder (0, - 0, - 0, - 0))); - - this.sideBar.add (this.toolbarPanel, - 0); - - } else - { - - this.toolbarPanel.setBorder (new CompoundBorder (new MatteBorder (1, 0, 0, 0, UIUtils.getBorderColor ()), - new EmptyBorder (0, - 0, - 0, - 0))); - - this.sideBar.add (this.toolbarPanel); - - } -*/ - this.toolbarLocation = loc; - - } - - private AccordionItem createSectionTree (String title, - String iconType, - Set sections) - { - - final LanguageStringsEditor _this = this; - - final JTree tree = this.createStringsTree (sections); - - if (tree == null) - { - - return null; - - } - - tree.setCellRenderer (new DefaultTreeCellRenderer () - { - - public Component getTreeCellRendererComponent (JTree tree, - Object value, - boolean sel, - boolean expanded, - boolean leaf, - int row, - boolean hasFocus) - { - - super.getTreeCellRendererComponent (tree, - value, - sel, - expanded, - leaf, - row, - hasFocus); - - DefaultMutableTreeNode tn = (DefaultMutableTreeNode) value; - - if (tn.getUserObject () instanceof String) - { - - return this; - - } - - this.setIcon (null); - - LanguageStrings.Node n = (LanguageStrings.Node) tn.getUserObject (); - - final java.util.List id = n.getId (); - - int c = _this.getUserValueCount (n); - int alls = 0; - int errCount = _this.getErrorCount (n); - - Set vals = _this.valuesCache.get (n); - - if (vals != null) - { - - alls = vals.size (); - - } - - String title = (n.getTitle () != null ? n.getTitle () : n.getNodeId ()); - - String name = null; - - if (errCount > 0) - { - - name = String.format ("%s (%s/%s) [%s errors]", - title, - Environment.formatNumber (c), - Environment.formatNumber (alls), - Environment.formatNumber (errCount)); - - this.setIcon (Environment.getIcon (Constants.ERROR_ICON_NAME, - Constants.ICON_SIDEBAR)); - - } else { - - name = String.format ("%s (%s/%s)", - title, - Environment.formatNumber (c), - Environment.formatNumber (alls)); - - if (alls == c) - { - - this.setIcon (Environment.getIcon (Constants.SAVE_ICON_NAME, - Constants.ICON_SIDEBAR)); - - } else { - - if (c > 0) - { - - this.setIcon (Environment.getIcon (Constants.NEXT_ICON_NAME, - Constants.ICON_SIDEBAR)); - - } - - } - - } - - this.setText (name); - - this.setBorder (new EmptyBorder (2, 2, 2, 2)); - - return this; - - } - - }); - - tree.addMouseListener (new MouseEventHandler () - { - - @Override - public void handlePress (MouseEvent ev) - { - - TreePath tp = tree.getPathForLocation (ev.getX (), - ev.getY ()); - - if (tp != null) - { - - DefaultMutableTreeNode n = (DefaultMutableTreeNode) tp.getLastPathComponent (); - - LanguageStrings.Node node = (LanguageStrings.Node) n.getUserObject (); - - String id = node.getNodeId (); - - _this.showIds (id); - /* - - IdsPanel p = _this.panels.get (id); - - if (p == null) - { - - p = _this.createIdsPanel (id); - - try - { - - p.init (); - - } catch (Exception e) { - - Environment.logError ("Unable to show ids for id: " + - id, - e); - - UIUtils.showErrorMessage (_this, - "Unable to show panel."); - - return; - - } - - _this.panels.put (id, - p); - - _this.cards.add (p, id); - - } - - _this.showCard (id); -*/ - } - - } - - }); - - AccordionItem acc = new AccordionItem (title, - iconType) - { - - @Override - public JComponent getContent () - { - - return tree; - - } - - }; - - this.sectionTrees.put (title, - tree); - - return acc; - - } - - public void showIds (String idPrefix) - { - - if (!this.valuesCache.containsKey (this.baseStrings.getNode (idPrefix))) - { - - return; - - } - - //String id = node.getNodeId (); - IdsPanel p = this.panels.get (idPrefix); - - if (p == null) - { - - p = this.createIdsPanel (idPrefix); - - try - { - - p.init (); - - } catch (Exception e) { - - Environment.logError ("Unable to show ids for id: " + - idPrefix, - e); - - UIUtils.showErrorMessage (this, - "Unable to show panel."); - - return; - - } - - this.panels.put (idPrefix, - p); - - this.cards.add (p, idPrefix); - - } - - this.showCard (idPrefix); - - this.fireMainPanelShownEvent (p); - - } - - public void setIdSelectedInSidebar (String id) - { - - for (JTree t : this.sectionTrees.values ()) - { - - t.clearSelection (); - - // See how many children there are. - TreePath tp = UIUtils.getTreePathForUserObject ((DefaultMutableTreeNode) t.getModel ().getRoot (), - this.baseStrings.createNode (id)); - - if (tp != null) - { - - t.setSelectionPath (tp); - - } - - } - - } - - private JTree createStringsTree (Set sections) - { - - final LanguageStringsEditor _this = this; - - DefaultMutableTreeNode root = new DefaultMutableTreeNode ("_strings"); - - for (LanguageStrings.Node k : sections) - { - - Set vals = k.getValues (this.nodeFilter); - - if (vals.size () == 0) - { - - continue; - - } - - this.valuesCache.put (k, vals); - - root.add (new DefaultMutableTreeNode (k)); - - } - - if (root.getChildCount () == 0) - { - - // Filtered out everything. - return null; - - } - - final JTree tree = UIUtils.createTree (); - - DefaultTreeModel dtm = (DefaultTreeModel) tree.getModel (); - - dtm.setRoot (root); - - return tree; - - } - - public void showMainCard () - { - - this.showCard (MAIN_CARD); - - } - - public void showCard (String name) - { - - this.cardsLayout.show (this.cards, - name); - - this.currentCard = name; - - this.validate (); - this.repaint (); - - } - - @Override - public void showPopupAt (Component popup, - Component showAt, - boolean hideOnParentClick) - { - - Point po = SwingUtilities.convertPoint (showAt, - 0, - 0, - this.getContentPane ()); - - this.showPopupAt (popup, - po, - hideOnParentClick); - - - } - - @Override - public void showPopupAt (Component c, - Point p, - boolean hideOnParentClick) - { - - Insets ins = this.getInsets (); - - if ((c.getParent () == null) - && - (c.getParent () != this.getLayeredPane ()) - ) - { - - this.addPopup (c, - hideOnParentClick, - false); - - } - - Dimension cp = c.getPreferredSize (); - - if ((p.y + cp.height) > (this.getBounds ().height - ins.top - ins.bottom)) - { - - p = new Point (p.x, - p.y); - - // See if the child is changing height. - if (c.getBounds ().height != cp.height) - { - - p.y = p.y - (cp.height - c.getBounds ().height); - - } else { - - p.y = p.y - cp.height; - - } - - } - - if (p.y < 0) - { - - p = new Point (p.x, - p.y); - - p.y = 10; - - } - - if ((p.x + cp.width) > (this.getBounds ().width - ins.left - ins.right)) - { - - p = new Point (p.x, - p.y); - - p.x = p.x - cp.width; - - } - - if (p.x < 0) - { - - p = new Point (p.x, - p.y); - - p.x = 10; - - } - - c.setBounds (p.x, - p.y, - c.getPreferredSize ().width, - c.getPreferredSize ().height); - - c.setVisible (true); - this.validate (); - this.repaint (); - - } - - public void addPopup (Component c) - { - - this.addPopup (c, - false, - false); - - } - - @Override - public void addPopup (Component c, - boolean hideOnClick, - boolean hideViaVisibility) - { - - this.getLayeredPane ().add (c, - JLayeredPane.POPUP_LAYER); - - this.getLayeredPane ().moveToFront (c); - - } - - @Override - public void removePopup (Component c) - { - - this.getLayeredPane ().remove (c); - - this.getLayeredPane ().validate (); - - this.getLayeredPane ().repaint (); - - } - - @Override - public void init () - throws Exception - { - - super.init (); - - final LanguageStringsEditor _this = this; - - int width = 0; - int height = 0; - - try - { - - width = UserProperties.getAsInt ("languagestringseditor-window-width"); - - height = UserProperties.getAsInt ("languagestringseditor-window-height"); - - } catch (Exception e) { - - // Ignore. - - } - - if (width < 1) - { - - width = DEFAULT_WINDOW_WIDTH; - - } - - if (height < 1) - { - - height = DEFAULT_WINDOW_HEIGHT; - - } - - this.splitPane.setPreferredSize (new Dimension (width, - height)); - - int scroll = 0; - - try - { - - scroll = UserProperties.getAsInt ("languagestringseditor-sidebar-scroll"); - - } catch (Exception e) { - - // Ignore. - - } - - if (scroll > 0) - { - - this.mainSideBar.scrollVerticalTo (scroll); - - } - - this.setTitleHeaderControlsVisible (true); - - this.showViewer (); - - String lastId = UserProperties.get ("languagestringseditor-stringsid-lasteditingid-" + this.userStrings.getId ()); - - if (lastId != null) - { - - this.showIds (lastId); - - } - - scroll = 0; - - try - { - - scroll = UserProperties.getAsInt ("languagestringseditor-stringsid-lasteditingscroll"); - - } catch (Exception e) { - - // Ignore. - - } - - if (scroll > 0) - { - - final int _scroll = scroll; - - UIUtils.doLater (new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - _this.panels.get (_this.currentCard).getScrollPane ().getVerticalScrollBar ().setValue (_scroll); - - } - - }); - - } - - if (!UserProperties.getAsBoolean (Constants.LANGUAGE_STRINGS_FIRST_USE_SEEN_PROPERTY_NAME)) - { - - UIUtils.showMessage ((PopupsSupported) this, - "Welcome to the (beta) editor!", - "Welcome to the strings editor. This window is where you'll create your own strings for a language for the {QW} User Interface.

    It is recommended that you read the strings editor guide before starting out. It describes how the editor works and the concepts used.

    Note: this is a beta release and I need your help to let me know what features you would like to see to help you create the strings. So please all feedback and ideas are welcome."); - - UserProperties.set (Constants.LANGUAGE_STRINGS_FIRST_USE_SEEN_PROPERTY_NAME, - true); - - } - - } - - public void showSideBar (String name) - { - - if ((this.currentSideBar != null) - && - (this.currentSideBar.getName ().equals (name)) - ) - { - - return; - - } - - AbstractSideBar b = this.sideBars.get (name); - - if (b == null) - { - - throw new IllegalArgumentException ("Unable to show sidebar: " + - name + - ", no sidebar found with that name."); - - } - - if (this.currentSideBar != null) - { - - // Will be hiding this one. - this.currentSideBar.onHide (); - - } - - this.currentSideBar = b; - - this.activeSideBars.remove (b); - - this.activeSideBars.push (b); - - this.currentSideBar.setVisible (true); - - this.setUILayout (); - - try - { - - b.onShow (); - - } catch (Exception e) { - - Environment.logError ("Unable to call onShow for sidebar: " + - name + - ", instance: " + - b, - e); - - } - - } - - public void setUILayout () - { - - final LanguageStringsEditor _this = this; - - this.splitPane.setResizeWeight (1f); - - if (this.currentSideBar != null) - { - - this.splitPane.setDividerSize (INTERNAL_SPLIT_PANE_DIVIDER_WIDTH); - this.splitPane.setRightComponent (this.currentSideBar); - - final Dimension min = this.currentSideBar.getMinimumSize (); - - int ww = this.splitPane.getSize ().width; - - int sbw = this.currentSideBar.getSize ().width; - - if (sbw == 0) - { - - sbw = min.width; - - } - - if (min.width > sbw) - { - - sbw = min.width; - - } - - int h = this.splitPane.getSize ().height; - - if (h == 0) - { - - h = 200; - - } - - int w = ww - sbw - INTERNAL_SPLIT_PANE_DIVIDER_WIDTH; - - this.splitPane.setDividerLocation (w); - - final int fw2 = w; - - UIUtils.doLater (new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - // For reasons best known to swing this has to be done separately otherwise when - // you exit full screen it will have the other sidebar as taking up all the space. - _this.splitPane.setDividerLocation (fw2); - - } - - }); - - } else { - - this.splitPane.setDividerSize (0); - this.splitPane.setRightComponent (this.createLayoutFiller ()); - - } - - } - - public void removeSideBarListener (SideBarListener l) - { - - this.sideBarListeners.remove (l); - - } - - public void addSideBarListener (SideBarListener l) - { - - this.sideBarListeners.add (l); - - } - - public void addSideBar (AbstractSideBar sb) - throws GeneralException - { - - if (sb == null) - { - - throw new IllegalArgumentException ("No sidebar provided."); - - } - - String id = sb.getId (); - - String state = null; - - if (id != null) - { - - state = UserProperties.get ("sidebarState-" + id); - - } - - sb.init (state); - - this.sideBars.put (id, - sb); - - } - - @Override - public void doSaveState () - { - - // Get the state from the sidebars. - for (AbstractSideBar sb : this.sideBars.values ()) - { - - String id = sb.getId (); - - if (id == null) - { - - continue; - - } - - UserProperties.set ("sidebarState-" + id, - sb.getSaveState ()); - - } - - } - - @Override - public boolean viewEditors () - throws GeneralException - { - - throw new UnsupportedOperationException ("Not supported."); - - } - - @Override - public void viewEditor (final EditorEditor ed) - throws GeneralException - { - - throw new UnsupportedOperationException ("Not supported."); - - } - - @Override - public boolean isEditorsVisible () - { - - return false; - - } - - @Override - public Set getTitleHeaderControlIds () - { - - Set ids = new LinkedHashSet (); - - ids.add (SUBMIT_HEADER_CONTROL_ID); - ids.add (FIND_HEADER_CONTROL_ID); - ids.add (USE_HEADER_CONTROL_ID); - ids.add (REPORT_BUG_HEADER_CONTROL_ID); - ids.add (HELP_HEADER_CONTROL_ID); - ids.add (SETTINGS_HEADER_CONTROL_ID); - - return ids; - - } - - @Override - public JComponent getTitleHeaderControl (String id) - { - - if (id == null) - { - - return null; - - } - - java.util.List prefix = Arrays.asList (allprojects,headercontrols,items); - - final LanguageStringsEditor _this = this; - - JComponent c = null; -/* - if (id.equals (FIND_HEADER_CONTROL_ID)) - { - - return UIUtils.createButton (Constants.FIND_ICON_NAME, - Constants.ICON_TITLE_ACTION, - "Find", - new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.showFind (); - - } - - }); - - } -*/ - if (id.equals (SUBMIT_HEADER_CONTROL_ID)) - { - - c = UIUtils.createButton (Constants.UP_ICON_NAME, - Constants.ICON_TITLE_ACTION, - "Click to submit the strings", - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - _this.submit (); - - } - - }); - - } - - if (id.equals (USE_HEADER_CONTROL_ID)) - { - - c = UIUtils.createButton (Constants.PLAY_ICON_NAME, - Constants.ICON_TITLE_ACTION, - "Click to try out your strings", - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - if (!_this.userStrings.getQuollWriterVersion ().equals (Environment.getQuollWriterVersion ())) - { - - UIUtils.showMessage ((PopupsSupported) _this, - "Unable to try out", - "Sorry, you can only try out a set of strings if the version matches the currently installed {QW} version."); - - return; - - } - - _this.tryOut (); - - } - - }); - - } - - if (id.equals (HELP_HEADER_CONTROL_ID)) - { - - c = UIUtils.createButton (Constants.HELP_ICON_NAME, - Constants.ICON_TITLE_ACTION, - "Click to view the help about editing your strings", - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - UIUtils.openURL (_this, - "help://uilanguages/overview"); - - } - - }); - - } - - if (c != null) - { - - return c; - - } - - return super.getTitleHeaderControl (id); - - } - - private void submit () - { - - final LanguageStringsEditor _this = this; - - try - { - - this.save (); - - } catch (Exception e) { - - Environment.logError ("Unable to save: " + this.userStrings, - e); - - UIUtils.showErrorMessage (this, - "Unable to save strings."); - - return; - - } - - Set vals = this.userStrings.getAllValues (); - - if (vals.size () == 0) - { - - UIUtils.showMessage ((PopupsSupported) this, - "No strings provided", - "Sorry, you must provide at least 1 string."); - - return; - - } - - int c = 0; - - for (LanguageStrings.Value uv : vals) - { - - LanguageStrings.Value nv = this.baseStrings.getValue (uv.getId ()); - - if (nv == null) - { - - // The string is present in the user strings but not the base! - Environment.logError ("Found string: " + uv.getId () + " present in user strings but not base."); - - continue; - - } - - c += LanguageStrings.getErrors (uv.getRawText (), - LanguageStrings.toId (nv.getId ()), - nv.getSCount (), - this).size (); - - } - - if (c > 0) - { - - UIUtils.showMessage ((PopupsSupported) this, - "Errors found in strings", - String.format ("Sorry, there are %s errors that must be corrected before you can submit the strings.", - Environment.formatNumber (c))); - - return; - - } - - final String popupName = "submit"; - QPopup popup = this.getNamedPopup (popupName); - - if (popup == null) - { - - popup = UIUtils.createClosablePopup ("Submit your strings", - Environment.getIcon (Constants.UP_ICON_NAME, - Constants.ICON_POPUP), - null); - - final QPopup qp = popup; - - Box content = new Box (BoxLayout.Y_AXIS); - - JTextPane help = UIUtils.createHelpTextPane ("Complete the form below to submit your strings. All the values are required.", - this); - - help.setBorder (null); - - content.add (help); - content.add (Box.createVerticalStrut (10)); - - final JLabel error = UIUtils.createErrorLabel (""); - error.setVisible (false); - error.setBorder (UIUtils.createPadding (0, 5, 5, 5)); - - content.add (error); - - Set items = new LinkedHashSet (); - - final TextFormItem nativelang = new TextFormItem ("Native Name (i.e. Espa\u00F1ol, Fran\u00E7ais, Deutsch)", - this.userStrings.getNativeName ()); - - items.add (nativelang); - - final TextFormItem lang = new TextFormItem ("English Name (i.e. Spanish, French, German)", - this.userStrings.getLanguageName ()); - - items.add (lang); - - final TextFormItem email = new TextFormItem ("Contact Email", - this.userStrings.getEmail ()); - - items.add (email); - - final JLabel tc = UIUtils.createClickableLabel ("View the Terms and Conditions for creating a translation", - Environment.getIcon (Constants.INFO_ICON_NAME, - Constants.ICON_CLICKABLE_LABEL), - Environment.getQuollWriterHelpLink ("uilanguages/terms-and-conditions", - null)); - - final CheckboxFormItem tandc = new CheckboxFormItem (null, "I have read and agree to the Terms and Conditions"); - - if (this.userStrings.getStringsVersion () == 0) - { - - items.add (new AnyFormItem (null, tc)); - items.add (tandc); - - } - - ActionListener saveAction = new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - String em = email.getValue (); - - if (em == null) - { - - error.setText ("Please enter a valid email."); - error.setVisible (true); - qp.resize (); - qp.resize (); - - return; - - } - - String l = lang.getValue (); - - if (l == null) - { - - error.setText ("Please enter the English Language name."); - error.setVisible (true); - qp.resize (); - - return; - - } - - String nl = nativelang.getValue (); - - if (nl == null) - { - - error.setText ("Please enter the Name Language name."); - error.setVisible (true); - qp.resize (); - - return; - - } - - if (_this.userStrings.getAllValues ().size () == 0) - { - - error.setText ("No strings provided. Please provide at least 1 string for your translation."); - error.setVisible (true); - qp.resize (); - - return; - - } - - if ((_this.userStrings.getStringsVersion () == 0) - && - (!tandc.isSelected ()) - ) - { - - error.setText ("To submit your strings you must agree to the Terms & Conditions, and please give them a quick read ;)"); - error.setVisible (true); - qp.resize (); - - return; - - } - - _this.userStrings.setEmail (em); - _this.userStrings.setLanguageName (l); - _this.userStrings.setNativeName (nl); - - _this.updateTitle (); - - try - { - - _this.save (); - - } catch (Exception e) { - - Environment.logError ("Unable to save strings: " + _this.userStrings, - e); - - UIUtils.showErrorMessage (_this, - "Unable to save strings."); - - return; - - } - - // Get the file, then send. - String t = null; - - try - { - - t = JSONEncoder.encode (_this.userStrings.getAsJSON ()); - - } catch (Exception e) - { - - Environment.logError ("Unable to upload strings: " + _this.userStrings, - e); - - UIUtils.showErrorMessage (_this, - "Unable to upload strings."); - - return; - - } - - Map headers = new HashMap<> (); - - String submitterid = UserProperties.get (Constants.UI_LANGUAGE_STRINGS_SUBMITTER_ID_PROPERTY_NAME); - - if (submitterid != null) - { - - headers.put (Constants.UI_LANGUAGE_STRINGS_SUBMITTER_ID_HEADER_NAME, - submitterid); - - } - - URL u = null; - - try - { - - u = new URL (Environment.getQuollWriterWebsite () + Environment.getProperty (Constants.SUBMIT_UI_LANGUAGE_STRINGS_URL_PROPERTY_NAME)); - - } catch (Exception e) { - - Environment.logError ("Unable to construct the url for submitting the ui language strings.", - e); - - UIUtils.showErrorMessage (_this, - "Unable to upload strings."); - - return; - - } - - Utils.postToURL (u, - headers, - t, - // On success - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - Map m = (Map) JSONDecoder.decode ((String) ev.getSource ()); - - String res = (String) m.get ("result"); - - String sid = (String) m.get ("submitterid"); - - UserProperties.set (Constants.UI_LANGUAGE_STRINGS_SUBMITTER_ID_PROPERTY_NAME, - sid); - - //_this.userStrings.setSubmitterId (sid); - _this.userStrings.setStringsVersion (((Number) m.get ("version")).intValue ()); - - try - { - - _this.saveToFile (); - - } catch (Exception e) { - - Environment.logError ("Unable to save strings file: " + - _this.userStrings, - e); - - UIUtils.showErrorMessage (_this, - "Your strings have been submitted to Quoll Writer support for review. However the associated local file, where the strings are kept on your machine, could not be updated."); - - return; - - } - - if (_this.userStrings.getStringsVersion () == 1) - { - - UIUtils.showMessage ((PopupsSupported) _this, - "Strings submitted", - String.format ("Your strings have been submitted to Quoll Writer support for review.

    A confirmation email has been sent to %s. Please click on the link in that email to confirm your email address.

    Thank you for taking the time and the effort to create the strings, it is much appreciated!", - _this.userStrings.getEmail ())); - - } else { - - UIUtils.showMessage ((PopupsSupported) _this, - "Strings submitted", - String.format ("Thank you! Your strings have been updated to version %s and will be made available to Quoll Writer users.

    Thank you for taking the time and effort to update the strings, it is much appreciated!", - Environment.formatNumber (_this.userStrings.getStringsVersion ()))); - - } - - qp.resize (); - qp.removeFromParent (); - - } - - }, - // On error - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - Map m = (Map) JSONDecoder.decode ((String) ev.getSource ()); - - String res = (String) m.get ("reason"); - - // Get the errors. - UIUtils.showErrorMessage (_this, - "Unable to submit the strings, reason:
    • " + res + "
    "); - - } - - }, - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - Map m = (Map) JSONDecoder.decode ((String) ev.getSource ()); - - String res = (String) m.get ("reason"); - - // Get the errors. - UIUtils.showErrorMessage (_this, - "Unable to submit the strings, reason:
    • " + res + "
    "); - - } - - }); - - } - - }; - - UIUtils.addDoActionOnReturnPressed (lang.getTextField (), - saveAction); - UIUtils.addDoActionOnReturnPressed (nativelang.getTextField (), - saveAction); - UIUtils.addDoActionOnReturnPressed (email.getTextField (), - saveAction); - - JButton save = UIUtils.createButton ("Submit", - saveAction); - JButton cancel = UIUtils.createButton ("Cancel", - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - qp.removeFromParent (); - _this.removeNamedPopup (popupName); - - } - - }); - - Set buttons = new LinkedHashSet (); - buttons.add (save); - buttons.add (cancel); - - Form f = new Form (Form.Layout.stacked, - items, - buttons); - - content.add (f); - - content.setSize (new Dimension (UIUtils.getPopupWidth () - 20, - content.getPreferredSize ().height)); - content.setBorder (UIUtils.createPadding (10, 10, 10, 10)); - - popup.setContent (content); - - popup.setDraggable (this); - - popup.setPopupName (popupName); - - this.addNamedPopup (popupName, - popup); - - //popup.resize (); - this.showPopupAt (popup, - UIUtils.getCenterShowPosition (this, - popup), - false); - - UIUtils.doLater (new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - //desc.grabFocus (); - qp.resize (); - - } - - }); - - } else { - - popup.setVisible (true); - popup.resize (); - - } - - } - - @Override - public String getViewerIcon () - { - - return Constants.EDIT_ICON_NAME; - - } - - private void tryOut () - { - - try - { - - this.save (); - - Environment.setUILanguage ("user-" + this.userStrings.getId ()); - - } catch (Exception e) { - - Environment.logError ("Unable to update ui language for: " + this.userStrings.getId (), - e); - - UIUtils.showErrorMessage (this, - "Unable to set strings."); - - return; - - } - - UIUtils.showMessage ((PopupsSupported) this, - "Restart recommended", - "{QW} has been updated to make use of your strings. To make full use of them it is recommended that you restart {QW}."); - - } - - @Override - public void fillSettingsPopup (JPopupMenu popup) - { - - //java.util.List prefix = Arrays.asList (allprojects,settingsmenu,items); - - final LanguageStringsEditor _this = this; - - popup.add (this.createMenuItem ("Submit your strings", - Constants.UP_ICON_NAME, - new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.submit (); - - } - - })); - - popup.add (this.createMenuItem ("Create a new translation", - Constants.NEW_ICON_NAME, - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - UIUtils.showAddNewLanguageStringsPopup (_this); - - } - - })); - - popup.add (this.createMenuItem ("Edit a translation", - Constants.EDIT_ICON_NAME, - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - UIUtils.showEditLanguageStringsSelectorPopup (_this); - - } - - })); - - if (this.baseStrings.getQuollWriterVersion ().equals (Environment.getQuollWriterVersion ())) - { - - popup.add (this.createMenuItem ("Try out your strings", - Constants.PLAY_ICON_NAME, - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - _this.tryOut (); - - } - - })); - - } - - popup.add (this.createMenuItem ("Delete", - Constants.DELETE_ICON_NAME, - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - _this.showDelete (); - - } - - })); - - popup.add (this.createMenuItem ("Close", - Constants.CLOSE_ICON_NAME, - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - _this.close (true, - null); - - } - - })); - - popup.addSeparator (); - - popup.add (this.createMenuItem ("Open Project", - Constants.UP_ICON_NAME, - new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - Environment.showLanding (); - - } - - })); - - - } - - public LanguageStrings getUserLanguageStrings () - { - - return this.userStrings; - - } - - public void showDelete () - { - - final LanguageStringsEditor _this = this; - - QPopup qp = UIUtils.createPopup ("Delete the strings", - Constants.DELETE_ICON_NAME, - null, - true, - null); - - final Box content = new Box (BoxLayout.Y_AXIS); - - JComponent mess = UIUtils.createHelpTextPane ("Please confirm you wish to delete your strings. Enter Yes in the box below to confirm deletion.

    To delete all versions of the strings please check the box below.

    Warning! This is an irreverisble operation and cannot be undone. This will make your strings unavailable to {QW} users but will not remove it from anyone who has already downloaded the strings.", - this); - mess.setBorder (null); - mess.setSize (new Dimension (UIUtils.getPopupWidth () - 20, - mess.getPreferredSize ().height)); - - content.add (mess); - - content.add (Box.createVerticalStrut (10)); - - final JCheckBox delAll = UIUtils.createCheckBox ("Delete all versions"); - - content.add (delAll); - - content.add (Box.createVerticalStrut (10)); - - final JLabel error = UIUtils.createErrorLabel ("Please enter the word Yes."); - //"Please enter a value."); - - error.setVisible (false); - error.setBorder (UIUtils.createPadding (0, 0, 5, 0)); - - final JTextField text = UIUtils.createTextField (); - - text.setMinimumSize (new Dimension (300, - text.getPreferredSize ().height)); - text.setPreferredSize (new Dimension (300, - text.getPreferredSize ().height)); - text.setMaximumSize (new Dimension (Short.MAX_VALUE, - text.getPreferredSize ().height)); - text.setAlignmentX (Component.LEFT_ALIGNMENT); - - error.setAlignmentX (Component.LEFT_ALIGNMENT); - - content.add (error); - content.add (text); - - content.add (Box.createVerticalStrut (10)); - - JButton confirm = null; - JButton cancel = UIUtils.createButton ("No, keep them", - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - qp.removeFromParent (); - - } - - }); - - ActionListener confirmAction = new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - String mess = UIUtils.getYesValueValidator ().isValid (text.getText ().trim ()); - - if (mess != null) - { - - // Should probably wrap this in a - error.setText (mess); - - error.setVisible (true); - - // Got to be an easier way of doing this. - content.setPreferredSize (null); - - content.setPreferredSize (new Dimension (UIUtils.getPopupWidth (), - content.getPreferredSize ().height)); - - _this.showPopupAt (qp, - qp.getLocation (), - false); - - return; - - } - - String submitterid = UserProperties.get (Constants.UI_LANGUAGE_STRINGS_SUBMITTER_ID_PROPERTY_NAME); - - if ((submitterid != null) - && - // Has they been submitted? - (_this.userStrings.getStringsVersion () > 0) - ) - { - - URL u = null; - - try - { - - String p = Environment.getProperty (Constants.DELETE_UI_LANGUAGE_STRINGS_URL_PROPERTY_NAME); - - p = StringUtils.replaceString (p, - Constants.ID_TAG, - _this.userStrings.getId ()); - - p = StringUtils.replaceString (p, - Constants.VERSION_TAG, - _this.userStrings.getQuollWriterVersion ().toString ()); - - p = StringUtils.replaceString (p, - Constants.ALL_TAG, - (delAll.isSelected () ? "true" : "")); - - u = new URL (Environment.getQuollWriterWebsite () + p); - - } catch (Exception e) { - - Environment.logError ("Unable to construct the url for submitting the ui language strings.", - e); - - UIUtils.showErrorMessage (_this, - "Unable to upload strings."); - - return; - - } - - Map headers = new HashMap<> (); - - headers.put (Constants.UI_LANGUAGE_STRINGS_SUBMITTER_ID_HEADER_NAME, - submitterid); - - Utils.postToURL (u, - headers, - "bogus", - // On success - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - String r = (String) JSONDecoder.decode ((String) ev.getSource ()); - - // Delete our local versions. - try - { - - Environment.deleteUserUILanguageStrings (_this.userStrings, - delAll.isSelected ()); - - } catch (Exception e) { - - Environment.logError ("Unable to delete user strings: " + _this.userStrings, - e); - - UIUtils.showErrorMessage (_this, - "Unable to delete the strings."); - - qp.removeFromParent (); - - return; - - } - - LanguageStringsEditor.super.close (true, - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - UIUtils.showMessage ((Component) null, - "Strings deleted", - "Your strings have been deleted.

    Thank you for the time and effort you put in to create the strings, it is much appreciated!"); - - } - - }); - - } - - }, - // On error - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - Map m = (Map) JSONDecoder.decode ((String) ev.getSource ()); - - String res = (String) m.get ("reason"); - - // Get the errors. - UIUtils.showErrorMessage (_this, - "Unable to submit the strings, reason:
    • " + res + "
    "); - - } - - }, - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - Map m = (Map) JSONDecoder.decode ((String) ev.getSource ()); - - String res = (String) m.get ("reason"); - - // Get the errors. - UIUtils.showErrorMessage (_this, - "Unable to delete the strings, reason:
    • " + res + "
    "); - - } - - }); - - } else { - - // Not been submitted. - // Delete our local versions. - try - { - - Environment.deleteUserUILanguageStrings (_this.userStrings, - delAll.isSelected ()); - - } catch (Exception e) { - - Environment.logError ("Unable to delete user strings: " + _this.userStrings, - e); - - UIUtils.showErrorMessage (_this, - "Unable to delete the strings."); - - qp.removeFromParent (); - - return; - - } - - // Close without saving. - LanguageStringsEditor.super.close (true, - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - UIUtils.showMessage ((Component) null, - "Strings deleted", - "Your strings have been deleted."); - - } - - }); - - } - - } - - }; - - confirm = UIUtils.createButton ("Yes, delete them", - confirmAction); - - UIUtils.addDoActionOnReturnPressed (text, - confirmAction); - - JButton[] buts = null; - - if (confirm != null) - { - - buts = new JButton[] { confirm, cancel }; - - } else { - - buts = new JButton[] { cancel }; - - } - - JComponent buttons = UIUtils.createButtonBar2 (buts, - Component.LEFT_ALIGNMENT); //ButtonBarFactory.buildLeftAlignedBar (buts); - buttons.setAlignmentX (Component.LEFT_ALIGNMENT); - content.add (buttons); - content.setBorder (UIUtils.createPadding (10, 10, 10, 10)); - - content.setPreferredSize (new Dimension (UIUtils.getPopupWidth (), - content.getPreferredSize ().height)); - - qp.setContent (content); - qp.setDraggable (this); - - this.showPopupAt (qp, - UIUtils.getCenterShowPosition (this, - qp), - false); - - } - - public void showImport () - { - - } - - @Override - public boolean viewStatistics () - throws GeneralException - { - - throw new UnsupportedOperationException ("Not supported."); - - } - - @Override - public boolean showChart (String chartType) - throws GeneralException - { - - throw new UnsupportedOperationException ("Not supported."); - - } - - @Override - public boolean showOptions (String section) - { - - throw new UnsupportedOperationException ("Not supported."); - - } - - @Override - public void showHelpText (String title, - String text, - String iconType, - String helpTextId) - { - - // TODO - - } - - @Override - public boolean viewAchievements () - { - - return true; - - } - - @Override - public void sendMessageToEditor (final EditorEditor ed) - throws GeneralException - { - - throw new UnsupportedOperationException ("Not supported."); - - } - - @Override - public boolean close (boolean noConfirm, - final ActionListener afterClose) - { - - try - { - - this.save (); - - } catch (Exception e) { - - Environment.logError ("Unable to save language strings: " + - this.userStrings, - e); - - UIUtils.showErrorMessage (this, - "Unable to save language strings."); - - return false; - - } - - this.setVisible (false); - - // Save state. - Map m = new LinkedHashMap (); - - UserProperties.set ("languagestringseditor-window-height", - this.splitPane.getSize ().height); - - UserProperties.set ("languagestringseditor-window-width", - this.splitPane.getSize ().width); - - if (this.currentCard != null) - { - - UserProperties.set ("languagestringseditor-stringsid-lasteditingid-" + this.userStrings.getId (), - this.currentCard); - - UserProperties.set ("languagestringseditor-stringsid-lasteditingscroll", - this.panels.get (this.currentCard).getScrollPane ().getVerticalScrollBar ().getValue ()); - - } - - UserProperties.set ("languagestringseditor-sidebar-scroll", - this.mainSideBar.getScrollPane ().getVerticalScrollBar ().getValue ()); - - // Close and remove all sidebars. - for (AbstractSideBar sb : new ArrayList (this.activeSideBars)) - { - - this.removeSideBar (sb); - - } - - super.close (true, - afterClose); - - return true; - - } - - public void removeSideBar (AbstractSideBar sb) - { - - if (sb == null) - { - - return; - - } - - try - { - - // Close the sidebar down gracefully. - sb.onHide (); - - sb.onClose (); - - } catch (Exception e) { - - Environment.logError ("Unable to close sidebar: " + sb.getName (), - e); - - } - - this.sideBars.remove (sb.getName ()); - - this.activeSideBars.remove (sb); - - this.removeSideBarListener (sb); - - AbstractSideBar _sb = (this.activeSideBars.size () > 0 ? this.activeSideBars.peek () : null); - - if (_sb != null) - { - - this.showSideBar (_sb.getName ()); - - } else { - - this.setUILayout (); - - } - - } - - @Override - public void closeSideBar () - { - - this.currentSideBar = null; - - this.setUILayout (); - - } - - @Override - public AbstractSideBar getActiveOtherSideBar () - { - - return null; - - } - - @Override - public int getActiveSideBarCount () - { - - return this.activeSideBars.size (); - - } - - @Override - public JPopupMenu getShowOtherSideBarsPopupSelector () - { - - final LanguageStringsEditor _this = this; - - JPopupMenu m = new JPopupMenu (); - - // Means we are showing the main sidebar and the other sidebar. - // Exclude those from the list. - for (AbstractSideBar sb : this.activeSideBars) - { - - if ((this.currentSideBar != null) - && - (this.currentSideBar == sb) - ) - { - - continue; - - } - - final AbstractSideBar _sb = sb; - - JMenuItem mi = UIUtils.createMenuItem (sb.getActiveTitle (), - sb.getActiveIconType (), - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.showSideBar (_sb.getName ()); - - } - - }); - - m.add (mi); - - } - - return m; - - } - - private JComponent createLayoutFiller () - { - - Box l = new Box (BoxLayout.X_AXIS); - l.setMinimumSize (new Dimension (0, 0)); - l.setPreferredSize (new Dimension (0, 0)); - l.setVisible (false); - - return l; - - } - - @Override - public void handleHTMLPanelAction (String v) - { - - StringTokenizer t = new StringTokenizer (v, - ",;"); - - if (t.countTokens () > 1) - { - - while (t.hasMoreTokens ()) - { - - this.handleHTMLPanelAction (t.nextToken ().trim ()); - - } - - return; - - } - - try - { - - if (v.equals ("import")) - { - - this.showImport (); - - } - - } catch (Exception e) { - - Environment.logError ("Unable to perform action: " + - v, - e); - - } - - super.handleHTMLPanelAction (v); - - } - - /** - * Display the targets for the project. - * - */ - public void viewTargets () - throws GeneralException - { - - throw new UnsupportedOperationException ("Not supported."); - - } - - @Override - public void initActionMappings (ActionMap am) - { - - super.initActionMappings (am); - - final LanguageStringsEditor _this = this; - - am.put ("show-main", - new ActionAdapter () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - _this.showMainCard (); - - } - - }); -/* - am.put (Constants.SHOW_FIND_ACTION, - new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.showFind (); - - } - - }); -*/ - } - - @Override - public void initKeyMappings (InputMap im) - { - - super.initKeyMappings (im); - - im.put (KeyStroke.getKeyStroke (KeyEvent.VK_ESCAPE, - 0), - "show-main"); - - im.put (KeyStroke.getKeyStroke (KeyEvent.VK_F1, - 0), - Constants.SHOW_FIND_ACTION); - - im.put (KeyStroke.getKeyStroke (KeyEvent.VK_F, - Event.CTRL_MASK), - Constants.SHOW_FIND_ACTION); - - im.put (KeyStroke.getKeyStroke (KeyEvent.VK_N, - Event.CTRL_MASK), - "new-project"); - im.put (KeyStroke.getKeyStroke (KeyEvent.VK_O, - Event.CTRL_MASK), - "open-project"); - - } -/* - public void showFind () - { - - this.showSideBar ("find"); - - this.finder.onShow (); - - } -*/ - private IdsPanel createIdsPanel (String id) - { - - final LanguageStringsEditor _this = this; - - return new IdsPanel (this, - this.baseStrings.getNode (id), - this.valuesCache.get (this.baseStrings.getNode (id))); - - } - - public class IdsPanel extends BasicQuollPanel - { - - private String parentId = null; - private Set vals = null; - private LanguageStrings.Node parent = null; - private Set values = null; - private Box content = null; - private LanguageStringsEditor editor = null; - - public IdsPanel (LanguageStringsEditor ed, - LanguageStrings.Node parent, - Set values) - { - - super (ed, - parent.getNodeId (), - null); - - this.editor = ed; - - this.parent = parent; - this.values = values; - - //this.node = this.editor.baseStrings.getNode (id); - - String title = (this.parent.getTitle () != null ? this.parent.getTitle () : this.parent.getNodeId ()); - - this.setTitle (String.format ("%s (%s)", - title, - Environment.formatNumber (this.values.size ()))); - - this.content = new ScrollableBox (BoxLayout.Y_AXIS); - this.content.setAlignmentY (Component.TOP_ALIGNMENT); - this.content.setAlignmentX (Component.LEFT_ALIGNMENT); - - } - - @Override - public String getPanelId () - { - - return this.parent.getNodeId (); - - } - - @Override - public boolean isWrapContentInScrollPane () - { - - return true; - - } - - public void updatePreviews () - { - - for (int i = 0; i < this.content.getComponentCount (); i++) - { - - Component c = this.content.getComponent (i); - - if (c instanceof IdBox) - { - - IdBox b = (IdBox) c; - - b.showPreview (); - - } - - } - - } - - @Override - public JComponent getContent () - { - - final IdsPanel _this = this; - - this.buildForm (this.parent.getNodeId ()); - - this.content.add (Box.createVerticalGlue ()); - - this.updatePreviews (); - - return this.content; - - } - - public void saveValues () - throws GeneralException - { - - for (int i = 0; i < this.content.getComponentCount (); i++) - { - - Component c = this.content.getComponent (i); - - if (c instanceof IdBox) - { - - IdBox b = (IdBox) c; - - b.saveValue (); - - } - - } - - } - - public String getIdValue (String id) - { - - for (int i = 0; i < this.content.getComponentCount (); i++) - { - - Component c = this.content.getComponent (i); - - if (c instanceof IdBox) - { - - IdBox b = (IdBox) c; - - if (b.getId ().equals (id)) - { - - return b.getUserValue (); - - } - - } - - } - - return null; - - } - - public int getErrorCount () - { - - int c = 0; - - for (int i = 0; i < this.content.getComponentCount (); i++) - { - - Component co = this.content.getComponent (i); - - if (co instanceof IdBox) - { - - IdBox b = (IdBox) co; - - if (b.hasErrors ()) - { - - c++; - - } - - } - - } - - return c; - - } - - public int getUserValueCount () - { - - int c = 0; - - for (int i = 0; i < this.content.getComponentCount (); i++) - { - - Component co = this.content.getComponent (i); - - if (co instanceof IdBox) - { - - IdBox b = (IdBox) co; - - if (b.hasUserValue ()) - { - - c++; - - } - - } - - } - - return c; - - } - - private void createComment (String comment) - { - - JComponent c = UIUtils.createLabel (comment); - c.setAlignmentX (LEFT_ALIGNMENT); - c.setBorder (UIUtils.createPadding (0, 15, 5, 5)); - - this.content.add (c); - - } - - private void buildForm (String idPrefix) - { - - // Check for the section comment. - if (this.parent.getComment () != null) - { - - this.createComment (this.parent.getComment ()); - - } - - for (LanguageStrings.Value v : this.values) - { - - this.content.add (new IdBox (v, - (this.editor.userStrings.containsId (v.getId ()) ? this.editor.userStrings.getValue (v.getId ()) : null), - this.editor)); // scount - - } - - } - - } - - private class IdBox extends Box - { - - private TextArea userValue = null; - private LanguageStringsEditor editor = null; - private Box selector = null; - private JList selections = null; - private LanguageStrings.Value baseValue = null; - private LanguageStrings.Value stringsValue = null; - - private JTextPane preview = null; - private Box previewWrapper = null; - private JLabel previewLabel = null; - private JTextPane errors = null; - private Box errorsWrapper = null; - private JLabel errorsLabel = null; - - public IdBox (final LanguageStrings.Value baseValue, - final LanguageStrings.Value stringsValue, - final LanguageStringsEditor editor) - { - - super (BoxLayout.Y_AXIS); - - final IdBox _this = this; - - this.editor = editor; - this.baseValue = baseValue; - this.stringsValue = stringsValue; - - Header h = UIUtils.createHeader (LanguageStrings.toId (this.baseValue.getId ()), - Constants.SUB_PANEL_TITLE); - - h.setBorder (UIUtils.createBottomLineWithPadding (0, 0, 3, 0)); - h.setAlignmentX (Component.LEFT_ALIGNMENT); - - this.add (h); - - String comment = this.baseValue.getComment (); - - Box b = new Box (BoxLayout.Y_AXIS); - FormLayout fl = new FormLayout ("right:60px, 5px, min(150px;p):grow", - (comment != null ? "top:p, 6px," : "") + "top:p, 6px, top:p:grow, 6px, top:p, top:p, top:p"); - fl.setHonorsVisibility (true); - PanelBuilder pb = new PanelBuilder (fl); - - CellConstraints cc = new CellConstraints (); - - int r = 1; - - if (comment != null) - { - - pb.addLabel ("Comment", - cc.xy (1, r)); - - String c = ""; - - if (this.baseValue.getSCount () > 0) - { - - for (int i = 0; i < this.baseValue.getSCount (); i++) - { - - if (c.length () > 0) - { - - c += ", "; - - } - - c += "%" + (i + 1) + "$s"; - - } - - c = "
    Requires values: " + c + " to be present in your value."; - - } - - pb.addLabel ("" + comment + c + "", - cc.xy (3, r)); - - r += 2; - - } - - pb.addLabel ("English", - cc.xy (1, - r)); - - JTextArea l = new JTextArea (baseValue.getRawText ()); //defValue); - l.setLineWrap (true); - l.setWrapStyleWord (true); - l.setEditable (false); - l.setBackground (UIUtils.getComponentColor ()); - l.setAlignmentX (Component.LEFT_ALIGNMENT); - - //l.setMinimumSize (new Dimension (200, 20)); - - pb.add (l, - cc.xy (3, r)); - - r += 2; - - pb.addLabel ("Your Value", - cc.xy (1, r)); - - this.userValue = new TextArea (null, - 3, - -1, - false) - { - - @Override - public void fillPopupMenuForExtraItems (MouseEvent ev, - JPopupMenu popup, - boolean compress) - { - - if (compress) - { - - java.util.List buts = new java.util.ArrayList (); - - buts.add (UIUtils.createButton (Constants.COPY_ICON_NAME, - Constants.ICON_MENU, - "Use the English value", - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.useEnglishValue (); - - } - - })); - - popup.add (UIUtils.createPopupMenuButtonBar ("Manage", - //"Edit", - popup, - buts)); - - } else { - - JMenuItem mi = null; - - mi = UIUtils.createMenuItem ("Use the English value", - Constants.COPY_ICON_NAME, - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.useEnglishValue (); - - } - - }); - popup.add (mi); - - } - - } - - }; - - this.userValue.addKeyListener (new KeyAdapter () - { - - private ScheduledFuture task = null; - - private void update () - { - - if (this.task != null) - { - - this.task.cancel (false); - - } - - this.task = _this.editor.schedule (new Runnable () - { - - @Override - public void run () - { - - UIUtils.doLater (new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - _this.showPreview (); - - } - - }); - - } - - }, - 750, - 0); - - } - - @Override - public void keyPressed (KeyEvent ev) - { - - this.update (); - - } - - @Override - public void keyReleased (KeyEvent ev) - { - - this.update (); - - } - - }); - - //this.userValue.setBorder (UIUtils.createLineBorder ()); - - try - { - - this.userValue.setDictionaryProvider (new UserDictionaryProvider (UserProperties.get (Constants.SPELL_CHECK_LANGUAGE_PROPERTY_NAME)) - { - - @Override - public SpellChecker getSpellChecker () - { - - final SpellChecker sp = super.getSpellChecker (); - - return new SpellChecker () - { - - @Override - public boolean isCorrect (Word word) - { - - int offset = word.getAllTextStartOffset (); - - LanguageStrings.Id id = _this.getIdAtOffset (offset); - - if (id != null) - { - - return id.isIdValid (_this.editor.baseStrings); - - } - - return sp.isCorrect (word); - - } - - @Override - public boolean isIgnored (Word word) - { - - return false; - - } - - @Override - public java.util.List getSuggestions (Word word) - { - - return sp.getSuggestions (word); - - } - - }; - - } - - }); - - this.userValue.setSpellCheckEnabled (true); - - } catch (Exception e) { - - e.printStackTrace (); - - } - - final Action defSelect = this.userValue.getEditor ().getActionMap ().get (DefaultEditorKit.selectWordAction); - - this.userValue.getEditor ().getActionMap ().put (DefaultEditorKit.selectWordAction, - new TextAction (DefaultEditorKit.selectWordAction) - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - int c = _this.userValue.getEditor ().getCaretPosition (); - - Id id = _this.getIdAtCaret (); - - if (id != null) - { - - _this.userValue.getEditor ().setSelectionStart (id.getPart (c).start); - _this.userValue.getEditor ().setSelectionEnd (id.getPart (c).end); - - } else { - - defSelect.actionPerformed (ev); - - } - - } - - }); - - if (stringsValue != null) - { - - this.userValue.setText (stringsValue.getRawText ()); - - } - - this.userValue.setAutoGrabFocus (false); - - InputMap im = this.userValue.getInputMap (JComponent.WHEN_FOCUSED); - ActionMap am = this.userValue.getActionMap (); - - im.put (KeyStroke.getKeyStroke (KeyEvent.VK_P, - InputEvent.CTRL_MASK), - "preview"); - - am.put ("preview", - new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.showPreview (); - - } - - }); - - this.userValue.addKeyListener (new KeyAdapter () - { - - @Override - public void keyPressed (KeyEvent ev) - { - - if ((ev.getKeyCode () == KeyEvent.VK_ENTER) - || - (ev.getKeyCode () == KeyEvent.VK_UP) - || - (ev.getKeyCode () == KeyEvent.VK_DOWN) - ) - { - - if (_this.isSelectorVisible ()) - { - - ev.consume (); - - return; - - } - - } - - if (ev.getKeyCode () == KeyEvent.VK_TAB) - { - - ev.consume (); - -/* - if (id.hasErrors ()) - { - - _this.hideSelector (); - - return; - - } -*/ - _this.fillMatch ();//m); - - } - - } - - @Override - public void keyReleased (KeyEvent ev) - { - - if ((ev.getKeyCode () == KeyEvent.VK_CLOSE_BRACKET) - && - (ev.isShiftDown ()) - ) - { - - _this.hideSelector (); - - return; - - } - - if (ev.getKeyCode () == KeyEvent.VK_ENTER) - { - - if (_this.isSelectorVisible ()) - { - - ev.consume (); - - _this.fillMatch (); - - return; - - } - - } - - if (ev.getKeyCode () == KeyEvent.VK_UP) - { - - if (_this.isSelectorVisible ()) - { - - ev.consume (); - - _this.updateSelectedMatch (-1); - - return; - - } - - } - - if (ev.getKeyCode () == KeyEvent.VK_DOWN) - { - - if (_this.isSelectorVisible ()) - { - - ev.consume (); - - _this.updateSelectedMatch (1); - - return; - - } - - } - - if (ev.getKeyCode () == KeyEvent.VK_ESCAPE) - { - - ev.consume (); - - _this.hideSelector (); - - return; - - } - - int c = _this.userValue.getEditor ().getCaretPosition (); - - String t = _this.userValue.getEditor ().getText (); - - LanguageStrings.Id id = LanguageStrings.getId (t, c); - - if (id == null) - { - - _this.hideSelector (); - - return; - - } - - Set matches = id.getPartMatches (c, - _this.editor.baseStrings); - - if ((matches == null) - || - (matches.size () == 0) - ) - { - - _this.hideSelector (); - - return; - - } - - if (matches.size () == 1) - { - - LanguageStrings.Id.Part p = id.getPart (c); - - if (p == null) - { - - p = id.getLastPart (); - - } - - if (p.part.equals (matches.iterator ().next ())) - { - - _this.hideSelector (); - return; - - } - - } - - try - { - - int ind = c; - - LanguageStrings.Id.Part pa = id.getPart (c); - - if (pa != null) - { - - ind = pa.start; - - } - - Rectangle r = _this.userValue.getEditor ().modelToView (ind); - - //Point p = r.getLocation (); - //p.y -= 10; - //p.x -= 10; - //p.y += r.height;. - - _this.showSelectionPopup (matches, - r.getLocation ()); - - } catch (Exception e) { - - e.printStackTrace (); - - } - - } - - }); - - pb.add (this.userValue, - cc.xy (3, r)); - - r += 2; - - // Needed to prevent the performance hit - this.errorsWrapper = new Box (BoxLayout.Y_AXIS); - - this.errorsLabel = UIUtils.createErrorLabel ("Errors"); - this.errorsLabel.setBorder (UIUtils.createPadding (6, 0, 0, 0)); - this.errorsLabel.setVisible (false); - this.errorsLabel.setIcon (null); - this.errorsLabel.setFocusable (false); - - pb.add (this.errorsLabel, - cc.xy (1, r)); - pb.add (this.errorsWrapper, - cc.xy (3, r)); - - r += 1; - - // Needed to prevent the performance hit - this.previewWrapper = new Box (BoxLayout.Y_AXIS); - - this.previewLabel = UIUtils.createInformationLabel ("Preview"); - this.previewLabel.setBorder (UIUtils.createPadding (6, 0, 0, 0)); - this.previewLabel.setVisible (false); - - pb.add (this.previewLabel, - cc.xy (1, r)); - pb.add (this.previewWrapper, - cc.xy (3, r)); - - JPanel p = pb.getPanel (); - p.setOpaque (false); - p.setAlignmentX (Component.LEFT_ALIGNMENT); - p.setBorder (UIUtils.createPadding (5, 5, 0, 0)); - - this.add (p); - - this.setBorder (UIUtils.createPadding (0, 10, 20, 10)); - this.setAlignmentX (Component.LEFT_ALIGNMENT); - this.setAlignmentY (Component.TOP_ALIGNMENT); - - } - - public void saveValue () - throws GeneralException - { - - String uv = this.getUserValue (); - - if (uv != null) - { - - if (this.stringsValue != null) - { - - this.stringsValue.setRawText (uv); - - } else { - - this.stringsValue = this.editor.userStrings.insertValue (this.baseValue.getId ()); - - //this.stringsValue.setSCount (this.baseValue.getSCount ()); - this.stringsValue.setRawText (uv); - - } - - } else { - - this.editor.userStrings.removeNode (this.baseValue.getId ()); - - } - - } - - public LanguageStrings.Id getIdAtOffset (int offset) - { - - return LanguageStrings.getId (this.userValue.getEditor ().getText (), - offset); -/* - Id id = new Id (this.userValue.getEditor ().getText (), - offset); - - if (id.fullId == null) - { - - return null; - - } - - return id; -*/ - } - - public LanguageStrings.Id getIdAtCaret () - { - - return this.getIdAtOffset (this.userValue.getEditor ().getCaretPosition ()); - - } - - public String getId () - { - - return LanguageStrings.toId (this.baseValue.getId ()); - - } - - public boolean hasUserValue () - { - - return this.getUserValue () != null; - - } - - public String getUserValue () - { - - StringWithMarkup sm = this.userValue.getTextWithMarkup (); - - if (sm != null) - { - - if (!sm.hasText ()) - { - - return null; - - } - - return sm.getMarkedUpText (); - - } - - return null; - - } - - public void useEnglishValue () - { - - this.userValue.updateText (this.baseValue.getRawText ()); - this.showPreview (); - this.validate (); - this.repaint (); - - } - - public boolean hasErrors () - { - - String s = this.getUserValue (); - - if (s == null) - { - - return false; - - } - - return LanguageStrings.getErrors (s, - LanguageStrings.toId (this.baseValue.getId ()), - this.baseValue.getSCount (), - this.editor).size () > 0; - - - } - - public boolean showErrors (boolean requireUserValue) - { - - String s = this.getUserValue (); - - if ((s == null) - && - (!requireUserValue) - ) - { - - this.errorsLabel.setVisible (false); - this.errorsWrapper.setVisible (false); - - return false; - - } - - Set errs = null; - - if (s == null) - { - - errs = new LinkedHashSet<> (); - - errs.add ("Cannot show a preview, no value provided."); - - } else { - - errs = LanguageStrings.getErrors (s, - LanguageStrings.toId (this.baseValue.getId ()), - this.baseValue.getSCount (), - this.editor); - - } - - LanguageStrings.Node root = this.baseValue.getRoot (); - - this.editor.updateSideBar (this.baseValue); - - if (errs.size () > 0) - { - - if (this.errors == null) - { - - this.errors = UIUtils.createHelpTextPane ("", - this.editor); - this.errors.setBorder (UIUtils.createPadding (6, 0, 0, 0)); - this.errors.setFocusable (false); - this.errorsWrapper.add (this.errors); - - } - - StringBuilder b = new StringBuilder (); - - for (String e : errs) - { - - if (b.length () > 0) - { - - b.append ("
    "); - - } - - b.append ("- " + e); - - } - - this.errors.setText ("" + b.toString () + ""); - this.errorsLabel.setVisible (true); - this.errorsWrapper.setVisible (true); - - this.editor.updateSideBar (this.baseValue); - - return true; - - } else { - - this.errorsLabel.setVisible (false); - this.errorsWrapper.setVisible (false); - - } - - return false; - - } - - public void showPreview () - { - - if (this.showErrors (false)) - { - - return; - - } - - String s = this.getUserValue (); - - if (s == null) - { - - if (this.preview != null) - { - - this.preview.setText (""); - - } - - this.previewWrapper.setVisible (false); - this.previewLabel.setVisible (false); - - this.editor.updateSideBar (this.baseValue); - - return; - - } - - if (this.preview == null) - { - - this.preview = UIUtils.createHelpTextPane ("", - this.editor); - this.preview.setBorder (UIUtils.createPadding (6, 0, 0, 0)); - this.preview.setFocusable (false); - - this.previewWrapper.add (this.preview); - - } - - String t = this.editor.getPreviewText (s); - - this.previewLabel.setVisible (true); - this.preview.setText (t); - this.previewWrapper.setVisible (true); - - this.editor.updateSideBar (this.baseValue); - - this.validate (); - this.repaint (); - - } - - private void fillMatch () - { - - QTextEditor editor = this.userValue.getEditor (); - - int c = editor.getCaretPosition (); - - LanguageStrings.Id id = LanguageStrings.getId (editor.getText (), - c); - - if (id == null) - { - - return; - - } - - String m = this.selections.getSelectedValue (); - - //m = id.getNewFullId (m); - - LanguageStrings.Id.Part part = id.getPart (c); - - if (part != null) - { - - editor.replaceText (part.start, part.end, m); - editor.setCaretPosition (part.start + m.length ()); - - } else { - - // Is the previous character a . if so append. - if ((editor.getText ().substring (c - 1, c).equals (".")) - || - (c == id.getEnd ()) - ) - { - - editor.replaceText (c, c, m); - editor.setCaretPosition (c + m.length ()); - - } else { - - part = id.getLastPart (); - - editor.replaceText (part.start, part.start + part.end, m); - editor.setCaretPosition (part.start + m.length ()); - - } - - } - - c = editor.getCaretPosition (); - - id = this.getIdAtCaret (); - - // We may be inserting into the middle of an id, check to see if it's valid. -/* - if (id.hasErrors ()) - { - - this.hideSelector (); - - // Update the view to "spell check" the ids. - return; - - } -*/ - // Check to see if the id maps to a string. - if (this.editor.baseStrings.getString (id.getId ()) != null) - { - - if (id.isPartial ()) - { - - editor.replaceText (id.getEnd (), id.getEnd (), "}"); - editor.setCaretPosition (c + 1); - - } - - this.hideSelector (); - - return; - - } - - // Check to see if there are more matches further down the tree. - String nid = id.getId () + "."; - - Set matches = this.editor.baseStrings.getIdMatches (nid); - - if (matches.size () > 0) - { - - c = editor.getCaretPosition (); - - editor.replaceText (c, c, "."); - editor.setCaretPosition (c + 1); - - try - { - - this.showSelectionPopup (matches, - editor.modelToView (id.getPart (c).start).getLocation ()); - - } catch (Exception e) { - - e.printStackTrace (); - - } - - return; - - } else { - - c = editor.getCaretPosition (); - - editor.replaceText (c, c, "}"); - editor.setCaretPosition (c + 1); - - this.hideSelector (); - - return; - - } - - } - - private String updateSelectedMatch (int incr) - { - - int i = this.selections.getSelectedIndex (); - - i += incr; - - int s = this.selections.getModel ().getSize (); - - if (i < 0) - { - - i = s + i; - - } - - if (i > s - 1) - { - - i -= s; - - } - - this.selections.setSelectedIndex (i); - - return this.selections.getSelectedValue (); - - } - - public boolean isSelectorVisible () - { - - if (this.selector != null) - { - - return this.selector.isVisible (); - - } - - return false; - - } - - public void hideSelector () - { - - if (this.selector != null) - { - - this.selector.setVisible (false); - - } - - this.userValue.getEditor ().setFocusTraversalKeysEnabled (true); - - } - - public void showSelectionPopup (Set matches, - Point point) - { - - if (this.selector == null) - { - - this.selector = new Box (BoxLayout.Y_AXIS); - - this.selector.setOpaque (true); - this.selector.setBackground (UIUtils.getComponentColor ()); - this.selector.setBorder (UIUtils.createLineBorder ()); - - } - - if ((matches == null) - || - (matches.size () == 0) - ) - { - - this.hideSelector (); - - return; - - } - - this.userValue.getEditor ().setFocusTraversalKeysEnabled (false); - - this.selector.removeAll (); - - DefaultListModel m = new DefaultListModel<> (); - - for (String o : matches) - { - - m.addElement (o); - - } - - this.selections = new JList (); - final JList l = this.selections; - l.setModel (m); - l.setLayoutOrientation (JList.VERTICAL); - l.setVisibleRowCount (0); - l.setOpaque (true); - l.setBackground (UIUtils.getComponentColor ()); - l.setMaximumSize (new Dimension (Short.MAX_VALUE, - Short.MAX_VALUE)); - UIUtils.setAsButton (l); - - l.setCellRenderer (new DefaultListCellRenderer () - { - - public Component getListCellRendererComponent (JList list, - Object value, - int index, - boolean isSelected, - boolean cellHasFocus) - { - - String obj = (String) value; - - JLabel l = (JLabel) super.getListCellRendererComponent (list, - value, - index, - isSelected, - cellHasFocus); - - l.setText (obj);//.getName ()); - - l.setFont (l.getFont ().deriveFont (UIUtils.getScaledFontSize (10)).deriveFont (Font.PLAIN)); -/* - l.setIcon (Environment.getObjectIcon (obj, - Constants.ICON_NOTIFICATION)); -*/ - l.setBorder (UIUtils.createBottomLineWithPadding (5, 5, 5, 5)); - l.setPreferredSize (new Dimension (l.getPreferredSize ().width, 29)); -/* - if (cellHasFocus) - { - - l.setBackground (Environment.getHighlightColor ()); - - } -*/ - return l; - - } - - }); - - l.setSelectedIndex (0); - - int rowHeight = 30; - - l.setAlignmentX (JComponent.LEFT_ALIGNMENT); - - JScrollPane sp = new JScrollPane (l); - - sp.setHorizontalScrollBarPolicy (ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); - sp.getVerticalScrollBar ().setUnitIncrement (rowHeight); - sp.setAlignmentX (JComponent.LEFT_ALIGNMENT); - sp.setOpaque (false); -/* - sp.getViewport ().setPreferredSize (new Dimension (300, - rowHeight * (matches.size () > 10 ? 10 : matches.size ()))); -*/ - sp.setBorder (null); - - this.selector.add (sp); - - l.addListSelectionListener (new ListSelectionListener () - { - - @Override - public void valueChanged (ListSelectionEvent ev) - { -/* - if (onSelect != null) - { - - NamedObject obj = (NamedObject) l.getSelectedValue (); - - onSelect.actionPerformed (new ActionEvent (l, - 0, - obj.getObjectReference ().asString ())); - - if (closeOnSelect) - { - - ep.removeFromParent (); - - } - - } -*/ - } - - }); - - this.selector.setPreferredSize (new Dimension (300, - rowHeight * (matches.size () > 10 ? 10 : matches.size ()))); - - this.editor.showPopupAt (this.selector, - SwingUtilities.convertPoint (this.userValue, - point, - this.editor), - false); - - } - - @Override - public Dimension getMaximumSize () - { - - return new Dimension (Short.MAX_VALUE, - this.getPreferredSize ().height); - - } -/* - public class Id - { - - private int _start = -1; - private String fullId = null; - private boolean hasClosingBrace = false; - private java.util.List parts = new ArrayList<> (); - public boolean hasErrors = false; - - public Id (String text, - int offset) - { - - if (text.length () < 3) - { - - return; - - } - - String idstart = LanguageStrings.ID_REF_START; - - int ind = text.lastIndexOf (idstart, offset); - - if (ind > -1) - { - - ind += idstart.length (); - this._start = ind; - - int idendind = text.indexOf (LanguageStrings.ID_REF_END, ind); - - if (idendind > -1) - { - - if (idendind < offset) - { - - return; - - } - - // We have an end, see if it's on the same line. - int leind = text.indexOf ("\n", ind); - - if (leind < 0) - { - - leind = text.length (); - - } - - if (idendind < leind) - { - - this.hasClosingBrace = true; - this.fullId = text.substring (ind, leind - 1); - - } - - } else { -System.out.println ("ELSE"); - StringBuilder b = new StringBuilder (); - - for (int i = ind; i < text.length (); i++) - { - - char c = text.charAt (i); - - if (Character.isWhitespace (c)) - { - - break; - - } - - b.append (c); - - } - - this.fullId = b.toString (); - - } -System.out.println ("ID: " + this.fullId); - if (this.fullId.equals ("")) - { - - this.fullId = null; - - } - - int start = ind; - - java.util.List parts = Utils.splitString (this.fullId, - "."); - - int cind = start; - - Part prevp = null; - - for (int i = 0; i < parts.size (); i++) - { - - if (i > 0) - { - - cind++; - - } - - String ps = parts.get (i); - - if (ps.trim ().length () != ps.length ()) - { - - this.hasErrors = true; - - } - - Part p = new Part (this, - cind, - ps, - prevp); - - prevp = p; - cind += ps.length (); - - this.parts.add (p); - - } - - } - - } - - public int getEnd () - { - - if (this.parts.size () == 0) - { - - return this._start; - - } - - return this.parts.get (this.parts.size () - 1).end; - - } - - public Part getPart (int offset) - { - - for (int i = 0; i < this.parts.size (); i++) - { - - Part p = this.parts.get (i); - - if ((offset >= p.start) - && - (offset <= p.end) - ) - { - - return p; - - } - - } - - return null; - - } - - public String getFullId () - { - - return this.fullId; - - } - - public boolean isIdValid (LanguageStrings baseStrings) - { - - if (this.fullId == null) - { - - return false; - - } - - return baseStrings.isIdValid (this.fullId); - - } - - public boolean hasErrors () - { - - return this.hasErrors; - - } - - public String getNewFullId (String suffix) - { - - if (this.fullId.endsWith (".")) - { - - return this.fullId + suffix; - - } - - String pref = this.getIdPrefix (); - - if (pref == null) - { - - return suffix; - - } - - return pref + "." + suffix; - - } - - public String getIdPrefix () - { - - StringBuilder b = new StringBuilder (); - - for (int i = 0; i < this.parts.size () - 1; i++) - { - - if (i > 0) - { - - b.append ("."); - - } - - b.append (this.parts.get (i).part); - - } - - if (b.length () == 0) - { - - return null; - - } - - return b.toString (); - - } - - public Part getLastPart () - { - - if (this.parts.size () == 0) - { - - return null; - - } - - return this.parts.get (this.parts.size () - 1); - - } - - public Set getPartMatches (int offset, - LanguageStrings baseStrings) - { - - Part p = this.getPart (offset); - - if (p != null) - { - - return baseStrings.getIdMatches (p.getFullId ()); - - } - - return this.getMatches (baseStrings); - - } - - public Set getMatches (LanguageStrings baseStrings) - { - - return baseStrings.getIdMatches (this.fullId); - - } - - public class Part - { - - public int start = -1; - public int end = -1; - public String part = null; - public Id parent = null; - public Part previous = null; - - public Part (Id parent, - int start, - String part, - Part prev) - { - - this.start = start; - this.end = this.start + part.length (); - this.parent = parent; - this.part = part; - this.previous = prev; - - } - - public String getFullId () - { - - StringBuilder b = new StringBuilder (this.part); - - Part prev = this.previous; - - while (prev != null) - { - - b.insert (0, prev.part + "."); - prev = prev.previous; - - } - - return b.toString (); - - } - - } - - } -*/ - - } - -} diff --git a/src/com/quollwriter/ui/NewProjectPanel.java b/src/com/quollwriter/ui/NewProjectPanel.java deleted file mode 100644 index 383d327b..00000000 --- a/src/com/quollwriter/ui/NewProjectPanel.java +++ /dev/null @@ -1,578 +0,0 @@ -package com.quollwriter.ui; - -import java.awt.Color; -import java.awt.Container; -import java.awt.Component; -import java.awt.event.*; - -import java.io.*; - -import java.util.*; - -import javax.swing.*; -import javax.swing.border.*; - -import com.jgoodies.forms.builder.*; -import com.jgoodies.forms.factories.*; -import com.jgoodies.forms.layout.*; - -import com.quollwriter.*; - -import com.quollwriter.data.*; -import com.quollwriter.data.comparators.*; - -import com.quollwriter.ui.components.*; - - -public class NewProjectPanel -{ - - private JTextField nameField = null; - private JTextField saveField = null; - private JPasswordField passwordField2 = null; - private JPasswordField passwordField = null; - private JCheckBox encryptField = null; - private JLabel error = null; - private Project project = null; - - public NewProjectPanel() - { - - this.nameField = UIUtils.createTextField (); - - } - - public void setProject (Project p) - { - - this.project = p; - - } - - public JTextField getNameField () - { - - return this.nameField; - - } - - public JComponent createPanel (final Container parent, - final ActionListener onCreate, - boolean createOnReturn, - final ActionListener onCancel, - boolean addButtons) - { - - final NewProjectPanel _this = this; - - String rows = "p, 6px, p, 6px, p, 6px, p"; - - if (addButtons) - { - - rows = rows + ", 6px, p"; - - } - - int row = 1; - - final FormLayout fl = new FormLayout ("right:p, 6px, fill:200px:grow, 2px, p", - rows); - fl.setHonorsVisibility (true); - final PanelBuilder builder = new PanelBuilder (fl); - - final CellConstraints cc = new CellConstraints (); - - builder.addLabel (Environment.getUIString (LanguageStrings.newprojectpanel, - LanguageStrings.labels, - LanguageStrings.name), - //"Name", - cc.xy (1, - row)); - builder.add (this.nameField, - cc.xy (3, - row)); - - row += 2; - - builder.addLabel (Environment.getUIString (LanguageStrings.newprojectpanel, - LanguageStrings.labels, - LanguageStrings.savein), - //"Save In", - cc.xy (1, - row)); - - File defDir = Environment.getDefaultSaveProjectDir (); - - this.saveField = UIUtils.createTextField (); - this.saveField.setText (defDir.getPath ()); - - // this.nameField.addKeyListener (k); - // this.saveField.addKeyListener (k); - - builder.add (this.saveField, - cc.xy (3, - row)); - - JButton findBut = new JButton (Environment.getIcon ("find", - Constants.ICON_MENU)); - - findBut.addActionListener (new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - JFileChooser f = new JFileChooser (); - f.setDialogTitle (Environment.getUIString (LanguageStrings.newprojectpanel, - LanguageStrings.find, - LanguageStrings.title)); - //"Select a Directory"); - f.setFileSelectionMode (JFileChooser.DIRECTORIES_ONLY); - f.setApproveButtonText (Environment.getUIString (LanguageStrings.newprojectpanel, - LanguageStrings.find, - LanguageStrings.confirm)); - //"Select"); - f.setCurrentDirectory (new File (_this.saveField.getText ())); - - // Need to run: attrib -r "%USERPROFILE%\My Documents" on XP to allow a new directory - // to be created in My Documents. - - if (f.showOpenDialog (parent) == JFileChooser.APPROVE_OPTION) - { - - _this.saveField.setText (f.getSelectedFile ().getPath ()); - - } - - } - - }); - - builder.add (findBut, - cc.xy (5, - row)); - - row += 2; - - this.encryptField = UIUtils.createCheckBox (Environment.getUIString (LanguageStrings.newprojectpanel, - LanguageStrings.labels, - LanguageStrings.encrypt)); - //"Encrypt this {project}? You will be prompted for a password."); - this.encryptField.setBackground (Color.WHITE); - - builder.add (this.encryptField, - cc.xyw (3, - row, - 2)); - - FormLayout pfl = new FormLayout ("right:p, 6px, 100px, 20px, p, 6px, fill:100px", - "p, 6px"); - pfl.setHonorsVisibility (true); - PanelBuilder pbuilder = new PanelBuilder (pfl); - - this.passwordField = new JPasswordField (); - - pbuilder.addLabel (Environment.getUIString (LanguageStrings.newprojectpanel, - LanguageStrings.labels, - LanguageStrings.password), - //"Password", - cc.xy (1, - 1)); - - pbuilder.add (this.passwordField, - cc.xy (3, - 1)); - - this.passwordField2 = new JPasswordField (); - - pbuilder.addLabel (Environment.getUIString (LanguageStrings.newprojectpanel, - LanguageStrings.labels, - LanguageStrings.confirmpassword), - //"Confirm", - cc.xy (5, - 1)); - - pbuilder.add (this.passwordField2, - cc.xy (7, - 1)); - - row += 2; - - final JPanel ppanel = pbuilder.getPanel (); - ppanel.setVisible (false); - ppanel.setOpaque (false); - - builder.add (ppanel, - cc.xyw (3, - row, - 2)); - - this.encryptField.addActionListener (new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - ppanel.setVisible (_this.encryptField.isSelected ()); - - UIUtils.resizeParent (parent); - - } - - }); - - ActionListener createProjectAction = new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - if (!_this.createProject (parent)) - { - - return; - - } - - if (onCreate != null) - { - - onCreate.actionPerformed (new ActionEvent (_this, - 0, - _this.nameField.getText ())); - - } - - if (parent instanceof PopupWindow) - { - - ((PopupWindow) parent).close (); - - } - - if (parent instanceof QPopup) - { - - ((QPopup) parent).removeFromParent (); - - } - - } - - }; - - if (addButtons) - { - - row += 2; - - JButton createBut = new JButton (); - createBut.setText (Environment.getUIString (LanguageStrings.newprojectpanel, - LanguageStrings.buttons, - LanguageStrings.create)); - //"Create"); - - createBut.addActionListener (createProjectAction); - - JButton cancelBut = new JButton (); - cancelBut.setText (Environment.getUIString (LanguageStrings.newprojectpanel, - LanguageStrings.buttons, - LanguageStrings.cancel)); - //"Cancel"); - - if (onCancel != null) - { - - cancelBut.addActionListener (onCancel); - - } - - if (parent instanceof PopupWindow) - { - - cancelBut.addActionListener (((PopupWindow) parent).getCloseAction ()); - - } - - if (parent instanceof QPopup) - { - - cancelBut.addActionListener (((QPopup) parent).getCloseAction ()); - - } - - JButton[] buts = { createBut, cancelBut }; - - JPanel bp = UIUtils.createButtonBar2 (buts, - Component.LEFT_ALIGNMENT); //ButtonBarFactory.buildLeftAlignedBar (buts); - bp.setOpaque (false); - bp.setAlignmentX (Component.LEFT_ALIGNMENT); - - builder.add (bp, - cc.xyw (3, - row, - 3)); - - } - - JPanel p = builder.getPanel (); - p.setOpaque (false); - p.setAlignmentX (JComponent.LEFT_ALIGNMENT); - - if (createOnReturn) - { - - UIUtils.addDoActionOnReturnPressed (this.nameField, - createProjectAction); - UIUtils.addDoActionOnReturnPressed (this.saveField, - createProjectAction); - UIUtils.addDoActionOnReturnPressed (this.passwordField, - createProjectAction); - UIUtils.addDoActionOnReturnPressed (this.passwordField2, - createProjectAction); - - } - - this.error = UIUtils.createErrorLabel (""); - this.error.setVisible (false); - this.error.setBorder (new EmptyBorder (0, - 0, - 5, - 0)); - - Box b = new Box (BoxLayout.Y_AXIS); - - b.add (this.error); - b.add (p); - - return b; - - } - - public boolean createProject (Container parent) - { - - if (!this.checkForm (parent)) - { - - return false; - - } - - Project proj = this.project; - - if (proj == null) - { - - proj = new Project (this.getName ()); - - } else { - - proj.setName (this.getName ()); - - } - - AbstractProjectViewer pj = null; - - try - { - - pj = Environment.getProjectViewerForType (proj); - - } catch (Exception e) - { - - Environment.logError ("Unable to create new project: " + - proj, - e); - - UIUtils.showErrorMessage (parent, - Environment.getUIString (LanguageStrings.newprojectpanel, - LanguageStrings.actionerror)); - //"Unable to create new project: " + proj.getName ()); - - return false; - - } - - try - { - - pj.newProject (this.getSaveDirectory (), - proj, - this.getPassword ()); - - } catch (Exception e) - { - - Environment.logError ("Unable to create new project: " + - proj, - e); - - UIUtils.showErrorMessage (parent, - Environment.getUIString (LanguageStrings.newprojectpanel, - LanguageStrings.actionerror)); - //"Unable to create new project: " + proj.getName ()); - - return false; - - } - - return true; - - } - - private boolean showError (Container parent, - String text) - { - - this.error.setText (Environment.replaceObjectNames (text)); - - this.error.setVisible (true); - - parent.repaint (); - - UIUtils.resizeParent (parent); - - return false; - - } - - private boolean hideError (Container parent) - { - - this.error.setVisible (false); - - parent.repaint (); - - UIUtils.resizeParent (parent); - - return false; - - } - - public boolean checkForm (Container parent) - { - - java.util.List prefix = new ArrayList (); - prefix.add (LanguageStrings.newprojectpanel); - prefix.add (LanguageStrings.errors); - - this.hideError (parent); - - String n = this.nameField.getText ().trim (); - - if (n.equals ("")) - { - - return this.showError (parent, - Environment.getUIString (prefix, - LanguageStrings.novalue)); - //"Please provide a name for the {project}."); - - } - - // See if the project already exists. - File pf = new File (saveField.getText (), Utils.sanitizeForFilename (n)); - - if (pf.exists ()) - { - - return this.showError (parent, - Environment.getUIString (prefix, - LanguageStrings.valueexists)); - - } - - String pwd = null; - - if (this.encryptField.isSelected ()) - { - - // Make sure a password has been provided. - pwd = new String (this.passwordField.getPassword ()).trim (); - - String pwd2 = new String (this.passwordField2.getPassword ()).trim (); - - if (pwd.equals ("")) - { - - return this.showError (parent, - Environment.getUIString (prefix, - LanguageStrings.nopassword)); - //"Please provide a password for securing the {project}."); - - } - - if (pwd2.equals ("")) - { - - return this.showError (parent, - Environment.getUIString (prefix, - LanguageStrings.confirmpassword)); - //"Please confirm your password."); - - } - - if (!pwd.equals (pwd2)) - { - - return this.showError (parent, - Environment.getUIString (prefix, - LanguageStrings.nomatch)); - //"The passwords do not match."); - - } - - } - - return true; - - } - - public File getSaveDirectory () - { - - return new File (this.saveField.getText ()); - - } - - public String getPassword () - { - - if (!this.encryptField.isSelected ()) - { - - return null; - - } - - String pwd = new String (this.passwordField.getPassword ()); - - if (pwd.trim ().equals ("")) - { - - pwd = null; - - } - - return pwd; - - } - - public void setName (String n) - { - - this.nameField.setText (n); - - } - - public String getName () - { - - return this.nameField.getText (); - - } - -} diff --git a/src/com/quollwriter/ui/Options.java b/src/com/quollwriter/ui/Options.java deleted file mode 100644 index 4edacf5a..00000000 --- a/src/com/quollwriter/ui/Options.java +++ /dev/null @@ -1,5101 +0,0 @@ -package com.quollwriter.ui; - -import java.awt.Component; -import java.awt.Color; -import java.awt.Dimension; -import java.awt.Toolkit; -import java.awt.Point; -import java.awt.event.*; - -import java.io.*; -import java.net.*; -import java.beans.*; - -import java.util.Arrays; -import java.util.List; -import java.util.Set; -import java.util.HashSet; -import java.util.LinkedHashSet; -import java.util.Map; -import java.util.HashMap; -import java.util.Vector; -import java.util.ArrayList; -import java.util.Date; -import java.util.StringTokenizer; - -import javax.sound.sampled.*; - -import javax.swing.*; -import javax.swing.event.*; -import javax.swing.border.*; -import javax.swing.tree.*; -import javax.swing.filechooser.*; - -import com.gentlyweb.properties.*; - -import com.jgoodies.forms.factories.*; -import com.jgoodies.forms.builder.*; -import com.jgoodies.forms.layout.*; - -import com.quollwriter.data.*; -import com.quollwriter.*; -import com.quollwriter.events.*; -import com.quollwriter.ui.*; -import com.quollwriter.ui.forms.*; -import com.quollwriter.ui.renderers.*; -import com.quollwriter.ui.events.*; -import com.quollwriter.ui.components.Header; -import com.quollwriter.ui.components.ItemAdapter; -import com.quollwriter.ui.components.ActionAdapter; -import com.quollwriter.ui.components.QPopup; -import com.quollwriter.ui.components.ChangeAdapter; -import com.quollwriter.ui.components.ImagePanel; -import com.quollwriter.ui.components.Accordion; -import com.quollwriter.achievements.*; -import com.quollwriter.achievements.ui.*; -import com.quollwriter.editors.*; -import com.quollwriter.data.editors.*; -import com.quollwriter.ui.panels.*; -import com.quollwriter.text.*; - -import com.quollwriter.editors.messages.*; -import com.quollwriter.editors.ui.*; - -import static com.quollwriter.LanguageStrings.*; -import static com.quollwriter.Environment.getUIString; - -public class Options extends Box -{ - - public enum Section - { - - warmups ("warmups"), - look ("look"), - naming ("naming"), - editing ("editing"), - editors ("editors"), - itemsAndRules ("itemsAndRules"), - achievements ("achievements"), - problems ("problems"), - betas ("betas"), - start ("start"), - landing ("landing"), - assets ("assets"), - project ("project"); - - private String type = null; - - Section (String type) - { - - this.type = type; - - } - - public String getType () - { - - return this.type; - - } - - } - - private Header header = null; - private AbstractViewer viewer = null; - private Accordion accordion = null; - private JScrollPane scrollPane = null; - private JCheckBox sendErrorsToSupport = null; - - private Map sections = new HashMap (); - - private Set
    sectIds = null; - - public Options (AbstractViewer viewer, - Section... sectIds) - throws GeneralException - { - - super (BoxLayout.Y_AXIS); - - this.viewer = viewer; - - this.sectIds = new LinkedHashSet (new ArrayList ((List
    ) Arrays.asList (sectIds))); - - this.header = UIUtils.createHeader (getUIString (options,title), - //"Options", - Constants.PANEL_TITLE, - Constants.OPTIONS_ICON_NAME, - null); - - } - - public class SectionInfo - { - - public String title = null; - public String help = null; - public JComponent content = null; - public String iconType = null; - - public SectionInfo (String title, - String iconType, - String help, - JComponent content) - { - - this.title = title; - this.iconType = iconType; - this.help = help; - this.content = content; - - } - - } - - public Header getHeader () - { - - return this.header; - - } - - public void init () - { - - this.add (this.header); - - Box b = new Box (BoxLayout.Y_AXIS); - - final Options _this = this; - - this.accordion = new Accordion (BoxLayout.Y_AXIS); - - this.accordion.setBorder (new EmptyBorder (0, - 10, - 10, - 10)); - - this.scrollPane = new JScrollPane (this.accordion); - this.scrollPane.setBorder (new EmptyBorder (1, 0, 0, 0)); - this.scrollPane.setOpaque (false); - this.scrollPane.getViewport ().setBorder (null); - this.scrollPane.getViewport ().setOpaque (false); - this.scrollPane.getVerticalScrollBar ().setUnitIncrement (50); - this.scrollPane.setAlignmentX (Component.LEFT_ALIGNMENT); - - this.scrollPane.getVerticalScrollBar ().addAdjustmentListener (new AdjustmentListener () - { - - public void adjustmentValueChanged (AdjustmentEvent ev) - { - - if (_this.scrollPane.getVerticalScrollBar ().getValue () > 0) - { - - _this.scrollPane.setBorder (new MatteBorder (1, 0, 0, 0, - UIUtils.getInnerBorderColor ())); - - } else { - - _this.scrollPane.setBorder (new EmptyBorder (1, 0, 0, 0)); - - } - - } - - }); - - this.add (this.scrollPane); - - this.accordion.setOpaque (false); - - for (Section sect : this.sectIds) - { - - SectionInfo inf = this.getSectionInfo (sect); - - if (inf == null) - { - - continue; - - } - - this.setContentBorder (inf.content); - - Accordion.Item item = this.accordion.add (this.createHeader (inf.title, - inf.iconType), - null, - inf.content, - UIUtils.createHelpTextPane (inf.help, - this.viewer)); - - this.sections.put (sect, - item); - - } - - this.accordion.add (Box.createVerticalGlue ()); - - this.accordion.setAllSectionsOpen (false); - - SwingUtilities.invokeLater (new Runnable () - { - - public void run () - { - - _this.scrollPane.getVerticalScrollBar ().setValue (0); - - } - - }); - - } - - public void showSection (String name) - { - - if (name == null) - { - - return; - - } - - this.showSection (Section.valueOf (name)); - - } - - public void showSection (Section name) - { - - final Options _this = this; - final Accordion.Item item = this.sections.get (name); - - if (item != null) - { - - item.setOpenContentVisible (true); - - this.validate (); - this.repaint (); - - final Border origBorder = item.getBorder (); - - final Color col = UIUtils.getBorderHighlightColor (); - - final int r = col.getRed (); - final int g = col.getGreen (); - final int b = col.getBlue (); - - PropertyChangeListener l = new PropertyChangeListener () - { - - @Override - public void propertyChange (PropertyChangeEvent ev) - { - - Color c = new Color (r, - g, - b, - ((Number) ev.getNewValue ()).intValue ()); - - item.setBorder (new CompoundBorder (new MatteBorder (3, 3, 3, 3, c), - UIUtils.createPadding (3, 3, 3, 3))); - - } - - }; - - final Timer cycle = UIUtils.createCyclicAnimator (l, - l, - 60, - 1500, - 0, - 255, - 2, - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - item.setBorder (origBorder); - - } - - }); - - UIUtils.doLater (new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - _this.scrollPane.scrollRectToVisible (SwingUtilities.convertRectangle (item, - item.getBounds (), - _this.scrollPane)); - - cycle.start (); - - } - - }); - - } - - } - - public SectionInfo getSectionInfo (Section sect) - { - - if (sect == Section.start) - { - - return this.createStartSection (); - - } - - if (sect == Section.warmups) - { - - return this.createWarmupsSection (); - - } - - if (sect == Section.project) - { - - return this.createProjectSection (); - - } - - if (sect == Section.assets) - { - - return this.createAssetsSection (); - - } - - if (sect == Section.look) - { - - return this.createLookSection (); - - } - - if (sect == Section.naming) - { - - return this.createNamingSection (); - - } - - if (sect == Section.editing) - { - - return this.createEditingSection (); - - } - - if (sect == Section.editors) - { - - return this.createEditorsSection (); - - } - - if (sect == Section.itemsAndRules) - { - - return this.createItemsAndRulesSection (); - - } - - if (sect == Section.achievements) - { - - return this.createAchievementsSection (); - - } - - if (sect == Section.problems) - { - - return this.createProblemsSection (); - - } - - if (sect == Section.betas) - { - - return this.createBetasSection (); - - } - - return null; - - } - - private SectionInfo createStartSection () - { - - final Options _this = this; - - Box box = new Box (BoxLayout.Y_AXIS); - - final JCheckBox showTips = UIUtils.createCheckBox (getUIString (options,qwstart,labels,showtips)); - //("Show useful tips")); - - final JCheckBox lastCB = UIUtils.createCheckBox (getUIString (options,qwstart,labels,showlastedited)); - // ("Open the last edited {project}")); - - final JCheckBox showCB = UIUtils.createCheckBox (getUIString (options,qwstart,labels,showprojectswindow)); - // ("Show the {Projects} window")); - - showTips.setSelected (UserProperties.getAsBoolean (Constants.SHOW_TIPS_PROPERTY_NAME)); - lastCB.setSelected (UserProperties.getAsBoolean (Constants.OPEN_LAST_EDITED_PROJECT_PROPERTY_NAME)); - showCB.setSelected (UserProperties.getAsBoolean (Constants.SHOW_LANDING_ON_START_PROPERY_NAME)); - - showTips.addItemListener (new ItemAdapter () - { - - public void itemStateChanged (ItemEvent ev) - { - - _this.updateUserProperty (Constants.SHOW_TIPS_PROPERTY_NAME, - showTips.isSelected ()); - - } - - }); - - JComponent c = this.createWrapper (showTips); - this.setAsMainItem (c); - - box.add (c); - - box.add (Box.createVerticalStrut (15)); - - lastCB.addActionListener (new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - if (!lastCB.isSelected ()) - { - - showCB.setSelected (true); - - UserProperties.set (Constants.SHOW_LANDING_ON_START_PROPERY_NAME, - showCB.isSelected ()); - - } - - UserProperties.set (Constants.OPEN_LAST_EDITED_PROJECT_PROPERTY_NAME, - lastCB.isSelected ()); - - } - - }); - - c = this.createWrapper (lastCB); - - this.setAsMainItem (c); - - box.add (c); - - box.add (Box.createVerticalStrut (15)); - - showCB.addActionListener (new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - if (!showCB.isSelected ()) - { - - lastCB.setSelected (true); - - UserProperties.set (Constants.OPEN_LAST_EDITED_PROJECT_PROPERTY_NAME, - lastCB.isSelected ()); - - } - - UserProperties.set (Constants.SHOW_LANDING_ON_START_PROPERY_NAME, - showCB.isSelected ()); - - } - - }); - - c = this.createWrapper (showCB); - - this.setAsMainItem (c); - - box.add (c); - - return new SectionInfo (getUIString (options,qwstart,title), - //"When {QW} starts", - "start", - getUIString (options,qwstart,text), - //"Want to see some tips when {QW} starts? Or maybe open the {project} you last edited? Look no further!", - box); - - } - - private SectionInfo createBetasSection () - { - - final Options _this = this; - - //box.add (this.createHeader (UIUtils.formatForUser ("When something goes wrong"))); - //box.add (Box.createVerticalStrut (5)); - - Box box = new Box (BoxLayout.Y_AXIS); - - final JCheckBox optinToBetas = UIUtils.createCheckBox (getUIString (options,betas,labels,optin)); - //"Opt-in to beta versions (enables auto-send of errors to Quoll Writer support)"); - optinToBetas.setSelected (UserProperties.getAsBoolean (Constants.OPTIN_TO_BETA_VERSIONS_PROPERTY_NAME)); - - optinToBetas.addActionListener (new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - if (optinToBetas.isSelected ()) - { - - UIUtils.showMessage ((PopupsSupported) _this.viewer, - getUIString (options,betas,about,popup,title), - //"About Betas", - getUIString (options,betas,about,popup,text)); - //"Quoll Writer betas are opt-in and are designed to elicit feedback from users. They will be functionally complete and as bug free as possible. However they won't be without issues, so please beware and report any problems you find.

    You can opt out at any time although this will not revert back to a previous version (that is potentially dangerous).

    Note: opting into betas will enable the Send errors to Quoll Writer support option, you can switch this off if you like to prevent errors being sent."); - - _this.sendErrorsToSupport.setSelected (true); - _this.updateUserProperty (Constants.AUTO_SEND_ERRORS_TO_SUPPORT_PROPERTY_NAME, - true); - - - } - - _this.updateUserProperty (Constants.OPTIN_TO_BETA_VERSIONS_PROPERTY_NAME, - optinToBetas.isSelected ()); - - } - - }); - - JComponent c = this.createWrapper (optinToBetas); - - this.setAsMainItem (c); - - box.add (c); - - return new SectionInfo (getUIString (options,betas,title), - //"Beta versions", - Constants.ABOUT_ICON_NAME, - getUIString (options,betas,text), - //"Want to get ahead of the crowd? Or maybe help improve Quoll Writer? This section lets you opt-in to beta versions. But be warned, betas aren't perfect.", - box); - - } - - private SectionInfo createProblemsSection () - { - - final Options _this = this; - - //box.add (this.createHeader (UIUtils.formatForUser ("When something goes wrong"))); - //box.add (Box.createVerticalStrut (5)); - - Box box = new Box (BoxLayout.Y_AXIS); - - this.sendErrorsToSupport = UIUtils.createCheckBox (getUIString (options,errors,labels,send)); - //"Send errors to Quoll Writer support"); - this.sendErrorsToSupport.setSelected (UserProperties.getAsBoolean (Constants.AUTO_SEND_ERRORS_TO_SUPPORT_PROPERTY_NAME)); - - this.sendErrorsToSupport.addActionListener (new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.updateUserProperty (Constants.AUTO_SEND_ERRORS_TO_SUPPORT_PROPERTY_NAME, - sendErrorsToSupport.isSelected ()); - - } - - }); - - JComponent c = this.createWrapper (this.sendErrorsToSupport); - - this.setAsMainItem (c); - - box.add (c); - - return new SectionInfo (getUIString (options,errors,title), - //"When something goes wrong", - Constants.BUG_ICON_NAME, - getUIString (options,errors,text), - //"Quoll Writer isn't perfect and it would be good to know when things cluck up. If you open this section you'll find a single setting that will let you send errors back to the magical worker elfs at Quoll Writer Headquarters located in deepest, darkest suburban Australia. Did you know that every error sent will prevent a Drop Bear attack. It's a serious and very real threat to our native elves.", - box); - - } - - private SectionInfo createAchievementsSection () - { - - java.util.List prefix = Arrays.asList (options,achievements); - - Box box = new Box (BoxLayout.Y_AXIS); - - final AchievementsManager man = Environment.getAchievementsManager (); - - final JCheckBox achievementsOn = UIUtils.createCheckBox (getUIString (prefix,labels,enable)); - //"Enable achievements"); - achievementsOn.setSelected (man.isAchievementsEnabled ()); - - achievementsOn.addActionListener (new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - man.setAchievementsEnabled (achievementsOn.isSelected ()); - - } - - }); - - JComponent c = this.createWrapper (achievementsOn); - - this.setAsMainItem (c); - - box.add (c); - - final JCheckBox achievementSounds = Achievements.createAchievementsSoundEnabledCheckbox (); - //"Play a sound when an achievement is reached"); - achievementSounds.setSelected (man.isSoundEnabled ()); - - final JCheckBox fullScreenSoundsOn = Achievements.createAchievementsSoundEnabledInFullScreenCheckbox (); - //"Play the sound in full screen mode"); - - achievementSounds.addActionListener (new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - man.setSoundEnabled (achievementSounds.isSelected ()); - - fullScreenSoundsOn.setEnabled (achievementSounds.isSelected ()); - - } - - }); - - box.add (Box.createVerticalStrut (15)); - - c = this.createWrapper (achievementSounds); - - this.setAsMainItem (c); - - box.add (c); - - fullScreenSoundsOn.setSelected (man.isSoundsInFullScreenEnabled ()); - - fullScreenSoundsOn.addActionListener (new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - man.setSoundsInFullScreenEnabled (fullScreenSoundsOn.isSelected ()); - - } - - }); - - //box.add (Box.createVerticalStrut (5)); - - c = this.createWrapper (fullScreenSoundsOn); - - this.setAsSubItem (c); - - box.add (c); - - return new SectionInfo (getUIString (prefix,title), - //"Achievements", - Constants.ACHIEVEMENT_ICON_NAME, - getUIString (prefix,text), - //"Are the achievements annoying you? Use this section to switch them off and they will bug you no more you underachiever.", - box); - - } - - private SectionInfo createItemsAndRulesSection () - { - - final Options _this = this; - - //box.add (this.createHeader ("Manage Items & Rules")); - //box.add (Box.createVerticalStrut (10)); - - Box box = new Box (BoxLayout.Y_AXIS); - - // Gaaah.... - boolean isAPV = (this.viewer instanceof AbstractProjectViewer); - - JButton[] buts = new JButton[ (isAPV ? 3 : 2) ]; - - JButton b = UIUtils.createButton (getUIString (objectnames,plural, Note.NOTE_TYPE_OBJECT_TYPE)); - //"{Note} Types")); - - b.addActionListener (new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.viewer.showEditNoteTypes (); - - } - - }); - - buts[0] = b; - - b = UIUtils.createButton (getUIString (objectnames,plural, Tag.OBJECT_TYPE)); - //"Tags"); - - b.addActionListener (new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.viewer.showEditTags (); - - } - - }); - - buts[1] = b; - - if (isAPV) - { - - b = UIUtils.createButton (getUIString (options,itemsandrules,labels,problemfinderrules)); - //"Problem Finder Rules"); - - b.addActionListener (new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - ((ProjectViewer) _this.viewer).showProblemFinderRuleConfig (); - - } - - }); - - buts[2] = b; - - } - - JPanel bp = UIUtils.createButtonBar2 (buts, - Component.LEFT_ALIGNMENT);//ButtonBarFactory.buildLeftAlignedBar (buts); - bp.setOpaque (false); - - JComponent c = this.createWrapper (bp); - - this.setAsMainItem (c); - - box.add (c); - - return new SectionInfo (getUIString (options,itemsandrules,title), - //"Manage Items & Rules", - Constants.EDIT_ICON_NAME, - getUIString (options,itemsandrules,text), - //"Set up the problem finder rules and manage the note and item types. A dull description but it does exactly what it says on the tin, well screen.", - box); - - } - - private SectionInfo createEditorsSection () - { - - if (EditorsEnvironment.getUserAccount () == null) - { - - return null; - - } - - final Options _this = this; - - Box box = new Box (BoxLayout.Y_AXIS); - - final JCheckBox autoLogin = UIUtils.createCheckBox (getUIString (options,editors,labels,autologin)); - //"Automatically login/go online whenever Quoll Writer starts"); - - autoLogin.setSelected (EditorsEnvironment.getEditorsPropertyAsBoolean (Constants.QW_EDITORS_SERVICE_LOGIN_AT_QW_START_PROPERTY_NAME)); - - autoLogin.addItemListener (new ItemAdapter () - { - - public void itemStateChanged (ItemEvent ev) - { - - try - { - - EditorsEnvironment.setEditorsProperty (Constants.QW_EDITORS_SERVICE_LOGIN_AT_QW_START_PROPERTY_NAME, - autoLogin.isSelected ()); - - } catch (Exception e) { - - Environment.logError ("Unable to set to login at start", - e); - - } - - } - - }); - - JComponent c = this.createWrapper (autoLogin); - this.setAsMainItem (c); - - box.add (c); - - box.add (Box.createVerticalStrut (15)); - - c = this.createHelpText (getUIString (options,editors,labels,defaultstatus)); - //"My default status when I go online is"); - this.setAsMainItem (c); - - box.add (c); - - Vector statuses = new Vector (); - - statuses.add (EditorEditor.OnlineStatus.online); - statuses.add (EditorEditor.OnlineStatus.busy); - statuses.add (EditorEditor.OnlineStatus.away); - statuses.add (EditorEditor.OnlineStatus.snooze); - - final JComboBox defStatus = new JComboBox (statuses); - - String defOnlineStatus = EditorsEnvironment.getEditorsProperty (Constants.QW_EDITORS_SERVICE_DEFAULT_ONLINE_STATUS_PROPERTY_NAME); - - if (defOnlineStatus != null) - { - - defStatus.setSelectedItem (EditorEditor.OnlineStatus.valueOf (defOnlineStatus)); - - } - - defStatus.addItemListener (new ItemAdapter () - { - - public void itemStateChanged (ItemEvent ev) - { - - if (ev.getStateChange () != ItemEvent.SELECTED) - { - - return; - - } - - try - { - - EditorsEnvironment.setEditorsProperty (Constants.QW_EDITORS_SERVICE_DEFAULT_ONLINE_STATUS_PROPERTY_NAME, - ((EditorEditor.OnlineStatus) defStatus.getSelectedItem ()).getType ()); - - } catch (Exception e) { - - Environment.logError ("Unable to set default online status", - e); - - } - - } - - }); - - defStatus.setRenderer (new DefaultListCellRenderer () - { - - public Component getListCellRendererComponent (JList list, - Object value, - int index, - boolean isSelected, - boolean cellHasFocus) - { - - JLabel l = (JLabel) super.getListCellRendererComponent (list, - value, - index, - isSelected, - cellHasFocus); - - EditorEditor.OnlineStatus status = (EditorEditor.OnlineStatus) value; - - String iconName = status.getType (); - - l.setText (status.getName ()); - l.setBorder (UIUtils.createPadding (3, 3, 3, 3)); - l.setIcon (Environment.getIcon (Constants.ONLINE_STATUS_ICON_NAME_PREFIX + iconName, - Constants.ICON_POPUP)); - - return l; - - } - - }); - - c = this.createWrapper (defStatus); - this.setAsSubItem (c); - - box.add (c); - - box.add (Box.createVerticalStrut (15)); - - final JCheckBox fullScreen = UIUtils.createCheckBox (getUIString (options,editors,labels,fullscreenbusystatus)); - //"Set my status to Busy when I enter full screen mode"); - - fullScreen.setSelected (EditorsEnvironment.getEditorsPropertyAsBoolean (Constants.QW_EDITORS_SERVICE_SET_BUSY_ON_FULL_SCREEN_ENTERED_PROPERTY_NAME)); - - fullScreen.addItemListener (new ItemAdapter () - { - - public void itemStateChanged (ItemEvent ev) - { - - try - { - - EditorsEnvironment.setEditorsProperty (Constants.QW_EDITORS_SERVICE_SET_BUSY_ON_FULL_SCREEN_ENTERED_PROPERTY_NAME, - fullScreen.isSelected ()); - - if (fullScreen.isSelected ()) - { - - if (Environment.isInFullScreen ()) - { - - EditorsEnvironment.fullScreenEntered (); - - } - - } - - } catch (Exception e) { - - Environment.logError ("Unable to set to busy on full screen entered", - e); - - } - - } - - }); - - c = this.createWrapper (fullScreen); - this.setAsMainItem (c); - - box.add (c); - - box.add (Box.createVerticalStrut (15)); - - final JCheckBox logMessages = UIUtils.createCheckBox (getUIString (options,editors,labels,logmessages,text)); - //"Log messages I send/receive (debug only)"); - - logMessages.addItemListener (new ItemAdapter () - { - - public void itemStateChanged (ItemEvent ev) - { - - EditorsEnvironment.logEditorMessages (logMessages.isSelected ()); - - } - - }); - - c = this.createWrapper (logMessages); - this.setAsMainItem (c); - - box.add (c); - - c = this.createHelpText (getUIString (options,editors,labels,logmessages,help)); - //"Save messages sent/received to a log file. You should only check this box if Quoll Writer support asks you to. Note: this value is not saved and must be activated everytime you run Quoll Writer."); - this.setAsSubItem (c); - - box.add (c); - - return new SectionInfo (getUIString (options,editors,title), - //"{Editors} Service", - Constants.EDITORS_ICON_NAME, - getUIString (options,editors,text), - //"Options related to the Editors service and how you interact with your {contacts}.", - box); - - } - - private SectionInfo createEditingSection () - { - - final Options _this = this; - - //final AbstractProjectViewer pv = (AbstractProjectViewer) this.viewer; - - //box.add (this.createHeader (UIUtils.formatForUser ("Editing {Chapters}"))); - //box.add (Box.createVerticalStrut (5)); - - Box box = new Box (BoxLayout.Y_AXIS); - - Vector chapterA = new Vector (); - chapterA.add (getUIString (times,mins5)); //Constants.MINS_5); - chapterA.add (getUIString (times,mins10)); //Constants.MINS_10); - chapterA.add (getUIString (times,mins20)); //Constants.MINS_20); - chapterA.add (getUIString (times,mins30)); //Constants.MINS_30); - chapterA.add (getUIString (times,hour1)); //Constants.HOUR_1); - - final JComboBox autosaveAmount = new JComboBox (chapterA); - - final JCheckBox enableAutosave = UIUtils.createCheckBox (getUIString (options,editingchapters,labels,autosave)); - //"Enable {Chapter} Auto-save")); - enableAutosave.setOpaque (false); - enableAutosave.setAlignmentX (Component.LEFT_ALIGNMENT); - - JComponent c = this.createWrapper (enableAutosave); - this.setAsMainItem (c); - - box.add (c); - - final Properties props = Environment.getDefaultProperties (Project.OBJECT_TYPE); - - boolean autosaveEnabled = props.getPropertyAsBoolean (Constants.CHAPTER_AUTO_SAVE_ENABLED_PROPERTY_NAME); - enableAutosave.setSelected (autosaveEnabled); - - long autosaveTime = Utils.getTimeAsMillis (props.getProperty (Constants.CHAPTER_AUTO_SAVE_INTERVAL_PROPERTY_NAME)); - - int selInd = 0; // 5 mins - - if (autosaveTime == (10 * Constants.MIN_IN_MILLIS)) - { - - selInd = 1; - - } - - if (autosaveTime == (20 * Constants.MIN_IN_MILLIS)) - { - - selInd = 2; - - } - - if (autosaveTime == (30 * Constants.MIN_IN_MILLIS)) - { - - selInd = 3; - - } - - if (autosaveTime == (60 * Constants.MIN_IN_MILLIS)) - { - - selInd = 4; - - } - - autosaveAmount.setSelectedIndex (selInd); - //props.getProperty (Constants.CHAPTER_AUTO_SAVE_INTERVAL_PROPERTY_NAME)); - autosaveAmount.setEnabled (enableAutosave.isSelected ()); - - enableAutosave.addItemListener (new ItemAdapter () - { - - public void itemStateChanged (ItemEvent ev) - { - - autosaveAmount.setEnabled (enableAutosave.isSelected ()); - - props.setProperty (Constants.CHAPTER_AUTO_SAVE_ENABLED_PROPERTY_NAME, - new BooleanProperty (Constants.CHAPTER_AUTO_SAVE_ENABLED_PROPERTY_NAME, - enableAutosave.isSelected ())); - - // For all the ProjectViewers (where text is editable) update the auto save settings. - Environment.doForOpenProjects (Project.NORMAL_PROJECT_TYPE, - new ProjectViewerAction () - { - - public void doAction (ProjectViewer pv) - { - - pv.scheduleAutoSaveForAllEditors (); - - } - - }); - - _this.updateDefaultProjectProperty (Constants.CHAPTER_AUTO_SAVE_ENABLED_PROPERTY_NAME, - enableAutosave.isSelected ()); - - Environment.fireUserProjectEvent (_this, - ProjectEvent.AUTO_SAVE, - (enableAutosave.isSelected () ? ProjectEvent.ON : ProjectEvent.OFF)); - - } - - }); - - autosaveAmount.addItemListener (new ItemAdapter () - { - - public void itemStateChanged (ItemEvent ev) - { - - if (ev.getStateChange () != ItemEvent.SELECTED) - { - - return; - - } - - long time = 5 * Constants.MIN_IN_MILLIS; - - int selInd = autosaveAmount.getSelectedIndex (); - - if (selInd == 1) - { - - time = 10 * Constants.MIN_IN_MILLIS; - - } - - if (selInd == 2) - { - - time = 20 * Constants.MIN_IN_MILLIS; - - } - - if (selInd == 3) - { - - time = 30 * Constants.MIN_IN_MILLIS; - - } - - if (selInd == 4) - { - - time = 60 * Constants.MIN_IN_MILLIS; - - } - - _this.updateDefaultProjectProperty (Constants.CHAPTER_AUTO_SAVE_INTERVAL_PROPERTY_NAME, - String.valueOf (time)); - //(String) autosaveAmount.getSelectedItem ()); - - // For all the ProjectViewers (where text is editable) update the auto save settings. - Environment.doForOpenProjects (Project.NORMAL_PROJECT_TYPE, - new ProjectViewerAction () - { - - public void doAction (ProjectViewer pv) - { - - pv.scheduleAutoSaveForAllEditors (); - - } - - }); - - } - - }); - - box.add (Box.createVerticalStrut (15)); - - c = this.createHelpText (getUIString (options,editingchapters,labels,autosavewhen)); - //"Auto-save every"); - this.setAsMainItem (c); - - box.add (c); - - c = this.createWrapper (autosaveAmount); - this.setAsSubItem (c); - - box.add (c); - - box.add (Box.createVerticalStrut (15)); - - c = this.createHelpText (getUIString (options,editingchapters,labels,showicon)); - //"Show an icon against a {chapter} in the {chapter} list when"); - this.setAsMainItem (c); - - box.add (c); - - final JCheckBox showEditPos = UIUtils.createCheckBox (getUIString (options,editingchapters,labels,haseditposition)); - //"it has an edit position")); - showEditPos.setSelected (UserProperties.getAsBoolean (Constants.SHOW_EDIT_POSITION_ICON_IN_CHAPTER_LIST_PROPERTY_NAME)); - showEditPos.setOpaque (false); - showEditPos.setAlignmentX (Component.LEFT_ALIGNMENT); - - showEditPos.addItemListener (new ItemAdapter () - { - - public void itemStateChanged (ItemEvent ev) - { - - Environment.doForOpenProjects (Project.NORMAL_PROJECT_TYPE, - new ProjectViewerAction () - { - - public void doAction (ProjectViewer pv) - { - - pv.reloadChapterTree (); - - } - - }); - - _this.updateUserProperty (Constants.SHOW_EDIT_POSITION_ICON_IN_CHAPTER_LIST_PROPERTY_NAME, - showEditPos.isSelected ()); - - } - - }); - - c = this.createWrapper (showEditPos); - this.setAsSubItem (c); - - box.add (c); - - final JCheckBox showEdited = UIUtils.createCheckBox (getUIString (options,editingchapters,labels,editcomplete)); - //new JCheckBox (Environment.replaceObjectNames ("it is set as edit complete")); - showEdited.setSelected (UserProperties.getAsBoolean (Constants.SHOW_EDIT_COMPLETE_ICON_IN_CHAPTER_LIST_PROPERTY_NAME)); - showEdited.setOpaque (false); - showEdited.setAlignmentX (Component.LEFT_ALIGNMENT); - - showEdited.addItemListener (new ItemAdapter () - { - - public void itemStateChanged (ItemEvent ev) - { - - Environment.doForOpenProjects (Project.NORMAL_PROJECT_TYPE, - new ProjectViewerAction () - { - - public void doAction (ProjectViewer pv) - { - - pv.reloadChapterTree (); - - } - - }); - - _this.updateUserProperty (Constants.SHOW_EDIT_COMPLETE_ICON_IN_CHAPTER_LIST_PROPERTY_NAME, - showEdited.isSelected ()); - - } - - }); - - c = this.createWrapper (showEdited); - this.setAsSubItem (c); - - box.add (c); - - box.add (Box.createVerticalStrut (5)); - - final JComponent label = UIUtils.createClickableLabel (getUIString (actions,viewexample), - //"View an example", - null); - - label.addMouseListener (new MouseEventHandler () - { - - public void handlePress (MouseEvent ev) - { - - QPopup popup = _this.viewer.getPopupByName ("edit-complete-example-popup"); - - if (popup == null) - { - - // Create a fake chapter tree. - JTree tree = UIUtils.createTree (); - - tree.setCellRenderer (new ProjectTreeCellRenderer (false) - { - - public boolean showEditPositionIcon () - { - - return true; - - } - - public boolean showEditCompleteIcon () - { - - return true; - - } - - }); - - Book testBook = null; - - try - { - - testBook = Environment.createTestBook (); - - } catch (Exception e) { - - Environment.logError ("Unable to create test book", - e); - - return; - - } - - for (Chapter c : testBook.getChapters ()) - { - - if (testBook.getChapterIndex (c) % 2 == 0) - { - - c.setEditComplete (true); - - } else { - - c.setEditPosition (1); - - } - - } - - tree.setModel (new DefaultTreeModel (UIUtils.createTree (testBook, - null, - null, - false))); - - popup = UIUtils.createClosablePopup (getUIString (names,example), - //"Example", - null, - null); - - popup.setName ("edit-complete-example-popup"); - tree.setBorder (new EmptyBorder (10, 10, 10, 10)); - - popup.setContent (tree); - - popup.setPreferredSize (new Dimension (250, - popup.getPreferredSize ().height)); - - } - - _this.viewer.showPopupAt (popup, - label, - true); - - } - - }); - - c = this.createWrapper (label); - this.setAsSubItem (c); - - box.add (c); - - box.add (Box.createVerticalStrut (15)); - - final JCheckBox showEditMarker = UIUtils.createCheckBox (getUIString (options,editingchapters,labels,showeditposition)); - //"Show the edit position in a {chapter}")); - showEditMarker.setSelected (UserProperties.getAsBoolean (Constants.SHOW_EDIT_MARKER_IN_CHAPTER_PROPERTY_NAME)); - showEditMarker.setOpaque (false); - showEditMarker.setAlignmentX (Component.LEFT_ALIGNMENT); - - showEditMarker.addItemListener (new ItemAdapter () - { - - public void itemStateChanged (ItemEvent ev) - { - - _this.updateUserProperty (Constants.SHOW_EDIT_MARKER_IN_CHAPTER_PROPERTY_NAME, - showEditMarker.isSelected ()); - - Environment.doForOpenProjectViewers (AbstractProjectViewer.class, - new ProjectViewerAction () - { - - public void doAction (AbstractProjectViewer pv) - { - - pv.doForPanels (QuollEditorPanel.class, - new DefaultQuollPanelAction () - { - - public void doAction (QuollPanel qp) - { - - try - { - - ((QuollEditorPanel) qp).reinitIconColumn (); - - } catch (Exception e) { - - Environment.logError ("Unable to reinit icon column for panel", - e); - - } - - } - - }); - - } - - }); - - } - - }); - - c = this.createWrapper (showEditMarker); - this.setAsMainItem (c); - - box.add (c); - - box.add (Box.createVerticalStrut (5)); - - c = this.createHelpText (getUIString (options,editingchapters,labels,seteditpositioncolor,text)); - //"Use the following color for the edit position indicator"); - this.setAsSubItem (c); - - box.add (c); - - final Color col = UIUtils.getColor (UserProperties.get (Constants.EDIT_MARKER_COLOR_PROPERTY_NAME)); - - final JPanel cSwatch = QColorChooser.getSwatch (col); - - UIUtils.setAsButton (cSwatch); - - cSwatch.addMouseListener (new MouseAdapter () - { - - public void mouseReleased (MouseEvent ev) - { - - QPopup popup = QColorChooser.getColorChooserPopup (getUIString (options,editingchapters,labels,seteditpositioncolor, LanguageStrings.popup,title), - //"Select the edit indicator color", - col, - Constants.EDIT_MARKER_COLOR_PROPERTY_NAME, - new ChangeAdapter () - { - - public void stateChanged (ChangeEvent ev) - { - - Color c = (Color) ev.getSource (); - - _this.updateUserProperty (Constants.EDIT_MARKER_COLOR_PROPERTY_NAME, - UIUtils.colorToHex (c)); - - Environment.doForOpenProjectViewers (AbstractProjectViewer.class, - new ProjectViewerAction () - { - - public void doAction (AbstractProjectViewer pv) - { - - pv.doForPanels (QuollEditorPanel.class, - new DefaultQuollPanelAction () - { - - public void doAction (QuollPanel qp) - { - - try - { - - ((QuollEditorPanel) qp).reinitIconColumn (); - - } catch (Exception e) { - - Environment.logError ("Unable to reinit icon column for panel", - e); - - } - - } - - }); - - } - - }); - - cSwatch.setBackground (c); - - } - - }, - new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { -/* - QPopup p = _this.popups.remove ("textcolor"); - - p.removeFromParent (); - */ - } - - }); - - popup.setDraggable (_this.viewer); - - _this.viewer.showPopupAt (popup, - cSwatch, - true); - - } - - }); - - c = this.createWrapper (cSwatch); - this.setAsSubItem (c); - - box.add (c); - - box.add (Box.createVerticalStrut (5)); - - final JComponent label2 = UIUtils.createClickableLabel (getUIString (actions,viewexample), - //"View an example", - null); - - label2.addMouseListener (new MouseEventHandler () - { - - @Override - public void handlePress (MouseEvent ev) - { - - QPopup popup = _this.viewer.getPopupByName ("edit-position-example-popup"); - - if (popup == null) - { - - popup = UIUtils.createClosablePopup (getUIString (names,example), - //"Example", - null, - null); - - popup.setName ("edit-position-example-popup"); - ImagePanel ip = new ImagePanel (Environment.getImage (Constants.EDIT_POSITION_TEST_IMAGE), - null); - - popup.setContent (ip); - - } - - _this.viewer.showPopupAt (popup, - label2, - true); - - } - - }); - - c = this.createWrapper (label2); - this.setAsSubItem (c); - - box.add (c); - - box.add (Box.createVerticalStrut (15)); - - final JCheckBox markEdited = UIUtils.createCheckBox (getUIString (options,editingchapters,labels,seteditcompleteatchapterend)); - //"Set a {chapter} as edit complete when the edit position is at the end of the {chapter}")); - markEdited.setOpaque (false); - markEdited.setSelected (UserProperties.getAsBoolean (Constants.SET_CHAPTER_AS_EDIT_COMPLETE_WHEN_EDIT_POSITION_IS_AT_END_OF_CHAPTER_PROPERTY_NAME)); - markEdited.setAlignmentX (Component.LEFT_ALIGNMENT); - - markEdited.addItemListener (new ItemAdapter () - { - - public void itemStateChanged (ItemEvent ev) - { - - _this.updateUserProperty (Constants.SET_CHAPTER_AS_EDIT_COMPLETE_WHEN_EDIT_POSITION_IS_AT_END_OF_CHAPTER_PROPERTY_NAME, - markEdited.isSelected ()); - - Environment.doForOpenProjectViewers (AbstractProjectViewer.class, - new ProjectViewerAction () - { - - public void doAction (final AbstractProjectViewer pv) - { - - pv.doForPanels (AbstractEditorPanel.class, - new DefaultQuollPanelAction () - { - - public void doAction (QuollPanel qp) - { - - AbstractEditorPanel p = (AbstractEditorPanel) qp; - - if (p == null) - { - - return; - - } - - try - { - - Chapter c = p.getChapter (); - - if (c.getEditPosition () > 0) - { - - pv.setChapterEditPosition (c, - c.getEditPosition ()); - - } - - } catch (Exception e) { - - Environment.logError ("Unable to set edit position for chapter: " + - p.getChapter (), - e); - - } - - } - - }); - - } - - }); - - } - - }); - - c = this.createWrapper (markEdited); - this.setAsMainItem (c); - - box.add (c); - - box.add (Box.createVerticalStrut (15)); - - final JCheckBox compressMenu = UIUtils.createCheckBox (getUIString (options,editingchapters,labels,compressrightclickmenu)); - //"Compress the {chapter} right click menu")); - compressMenu.setOpaque (false); - compressMenu.setSelected (UserProperties.getAsBoolean (Constants.COMPRESS_CHAPTER_CONTEXT_MENU_PROPERTY_NAME)); - compressMenu.setAlignmentX (Component.LEFT_ALIGNMENT); - - compressMenu.addItemListener (new ItemAdapter () - { - - public void itemStateChanged (ItemEvent ev) - { - - _this.updateUserProperty (Constants.COMPRESS_CHAPTER_CONTEXT_MENU_PROPERTY_NAME, - compressMenu.isSelected ()); - - } - - }); - - c = this.createWrapper (compressMenu); - this.setAsMainItem (c); - - box.add (c); - - box.add (Box.createVerticalStrut (5)); - - final JLabel label3 = UIUtils.createClickableLabel (getUIString (actions,viewexample), - //"View an example", - null); - - label3.addMouseListener (new MouseEventHandler () - { - - @Override - public void handlePress (MouseEvent ev) - { - - String img = Constants.COMPRESSED_CHAPTER_CONTEXT_MENU_IMAGE; - String name = "compress-chapter-menu-example-popup"; - - if (!compressMenu.isSelected ()) - { - - img = Constants.NONE_COMPRESSED_CHAPTER_CONTEXT_MENU_IMAGE; - - name = "no-compress-chapter-menu-example-popup"; - - } - - QPopup popup = _this.viewer.getPopupByName (name); - - if (popup == null) - { - - popup = UIUtils.createClosablePopup (getUIString (names,example), - //"Example", - null, - null); - - ImagePanel ip = new ImagePanel (Environment.getImage (img), - null); - - popup.setName (name); - popup.setContent (ip); - - popup.setDraggable (_this.viewer); - - } - - _this.viewer.showPopupAt (popup, - label3, - true); - - } - - }); - - c = this.createWrapper (label3); - - this.setAsSubItem (c); - - box.add (c); - - box.add (Box.createVerticalStrut (15)); - - c = this.createHelpText (getUIString (options,editingchapters,labels,setspellcheckerlanguage)); - //"Use the following language for the spellchecker"); - this.setAsMainItem (c); - - box.add (c); - - final JComponent downloadFiles = UIUtils.createClickableLabel (getUIString (options,editingchapters,labels,downloadlanguagefiles), - //"Download the language files", - null); - - if (this.viewer instanceof AbstractProjectViewer) - { - - AbstractProjectViewer pv = (AbstractProjectViewer) this.viewer; - - try - { - - downloadFiles.setVisible (!DictionaryProvider.isLanguageInstalled (pv.getSpellCheckLanguage ())); - - } catch (Exception e) { - - // Ignore. - - } - - } else { - - downloadFiles.setVisible (!DictionaryProvider.isLanguageInstalled (UserProperties.get (Constants.SPELL_CHECK_LANGUAGE_PROPERTY_NAME))); - - } - - final JCheckBox defLang = UIUtils.createCheckBox (getUIString (options,editingchapters,labels,setasdefaultlanguage)); - //"Set as default language")); - - final JComboBox spellcheckLang = new JComboBox (); - - // Get the languages supported by the spellchecker. - new Thread (new Runnable () - { - - public void run () - { - - String l = null; - - try - { - - l = Environment.getUrlFileAsString (new URL (Environment.getQuollWriterWebsite () + "/" + Environment.getProperty (Constants.QUOLL_WRITER_SUPPORTED_LANGUAGES_URL_PROPERTY_NAME))); - - } catch (Exception e) { - - // Something gone wrong, so just add english. - l = Constants.ENGLISH; - - Environment.logError ("Unable to get language files url", - e); - - } - - StringTokenizer t = new StringTokenizer (l, - String.valueOf ('\n')); - - final Vector langs = new Vector (); - - while (t.hasMoreTokens ()) - { - - String lang = t.nextToken ().trim (); - - if (lang.equals ("")) - { - - continue; - - } - - langs.add (lang); - - } - - UIUtils.doLater (new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - spellcheckLang.setModel (new DefaultComboBoxModel (langs)); - - String def = UserProperties.get (Constants.SPELL_CHECK_LANGUAGE_PROPERTY_NAME); - - if (_this.viewer instanceof AbstractProjectViewer) - { - - AbstractProjectViewer pv = (AbstractProjectViewer) _this.viewer; - - spellcheckLang.setSelectedItem (pv.getProject ().getProperty (Constants.SPELL_CHECK_LANGUAGE_PROPERTY_NAME)); - - } else { - - spellcheckLang.setSelectedItem (def); - - } - - spellcheckLang.setEnabled (true); - - boolean isDef = def.equals (spellcheckLang.getSelectedItem ().toString ()); - - defLang.setSelected (isDef); - - } - - }); - - } - - }).start (); - - final ActionListener setLang = new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - String lang = ev.getActionCommand (); - - if (_this.viewer instanceof AbstractProjectViewer) - { - - AbstractProjectViewer pv = (AbstractProjectViewer) _this.viewer; - - _this.updateProjectProperty (Constants.SPELL_CHECK_LANGUAGE_PROPERTY_NAME, - lang); - - try - { - - pv.setSpellCheckLanguage (lang, - true); - - } catch (Exception e) - { - - // Not good but not fatal either. - Environment.logError ("Unable to set spell check language to: " + - lang, - e); - - return; - - } - - if (!lang.equals (pv.getSpellCheckLanguage ())) - { - - pv.fireProjectEventLater (ProjectEvent.SPELL_CHECK, - ProjectEvent.CHANGE_LANGUAGE); - - } - - } - - } - - }; - - downloadFiles.addMouseListener (new MouseEventHandler () - { - - @Override - public void handlePress (MouseEvent ev) - { - - final String lang = spellcheckLang.getSelectedItem ().toString (); - - UIUtils.downloadDictionaryFiles (lang, - _this.viewer, - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - setLang.actionPerformed (new ActionEvent (_this, 0, lang)); - - // Add a notification saying that the language has been set. - // We do this "later" so that the previous notification is removed - // and we don't get an unwanted border. - UIUtils.doLater (new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - _this.viewer.addNotification (String.format (getUIString (options,editingchapters,downloaddictionaryfiles,notification,text), - //"The language files for %s have been downloaded and the project language set.", - lang), - Constants.INFO_ICON_NAME, - 30); - - } - - }); - - } - - }); - - } - - }); - - spellcheckLang.addItemListener (new ItemAdapter () - { - - public void itemStateChanged (ItemEvent ev) - { - - if (ev.getStateChange () != ItemEvent.SELECTED) - { - - return; - - } - - final String lang = spellcheckLang.getSelectedItem ().toString (); - - String def = UserProperties.get (Constants.SPELL_CHECK_LANGUAGE_PROPERTY_NAME); - - final String currLang = def; - - if (Environment.isEnglish (def)) - { - - def = Constants.ENGLISH; - - } - - defLang.setSelected (def.equals (lang)); - - if (_this.viewer instanceof AbstractProjectViewer) - { - - AbstractProjectViewer pv = (AbstractProjectViewer) _this.viewer; - - def = pv.getSpellCheckLanguage (); - - } - - if ((!Environment.isEnglish (lang)) - && - (!def.equals (lang)) - ) - { - - UIUtils.showMessage (_this.viewer, - getUIString (options,editingchapters,labels,nonenglishwarning)); - //"Please note: when changing the spell check language to something other
    than English the following features will be disabled:
    • Synonym lookups
    • The Problem Finder
    • Readability Indices
    "); - - } - - downloadFiles.setVisible (false); - - // Check to see if the files are available. - try - { - - if (!DictionaryProvider.isLanguageInstalled (lang)) - { - - downloadFiles.setVisible (true); - - java.util.List prefix = Arrays.asList (options,editingchapters,downloaddictionaryfiles,popup); - - UIUtils.createQuestionPopup (_this.viewer, - getUIString (prefix,title), - //"Download dictionary files?", - Constants.DOWNLOAD_ICON_NAME, - String.format (getUIString (prefix,text), - lang), - //"The dictionary files for " + - //lang + - //" need to be downloaded from the Quoll Writer server.

    Would you like to download them now?", - getUIString (prefix,buttons,confirm), - //"Yes, download them", - getUIString (prefix,buttons,cancel), - //null, - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - UIUtils.downloadDictionaryFiles (lang, - _this.viewer, - setLang); - - } - - }, - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - spellcheckLang.setSelectedItem (currLang); - - } - - }, - null, - null); - - return; - - } - - } catch (Exception e) { - - Environment.logError ("Unable to get language files for: " + - lang, - e); - - UIUtils.showErrorMessage (_this.viewer, - getUIString (options,editingchapters,downloaddictionaryfiles,actionerror)); - //"Unable to check for dictionary files, please contact Quoll Writer support."); - - return; - - } - - setLang.actionPerformed (new ActionEvent (this, 0, lang)); - - } - - }); - - c = this.createWrapper (spellcheckLang); - this.setAsSubItem (c); - - box.add (c); - - box.add (Box.createVerticalStrut (5)); - - defLang.setOpaque (false); - defLang.setAlignmentX (Component.LEFT_ALIGNMENT); - - defLang.addItemListener (new ItemAdapter () - { - - public void itemStateChanged (ItemEvent ev) - { - - if (!defLang.isSelected ()) - { - - return; - - } - - String lang = spellcheckLang.getSelectedItem ().toString (); - - _this.updateUserProperty (Constants.SPELL_CHECK_LANGUAGE_PROPERTY_NAME, - lang); - - } - - }); - - c = this.createWrapper (defLang); - this.setAsSubItem (c); - - box.add (c); - - box.add (Box.createVerticalStrut (5)); - - c = this.createWrapper (downloadFiles); - this.setAsSubItem (c); - - box.add (c); - - box.add (Box.createVerticalStrut (15)); - - JButton b = UIUtils.createButton (getUIString (options,editingchapters,labels,managedictionary)); - //"Manage your Personal Dictionary"); - - b.addActionListener (new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.viewer.showDictionaryManager (); - - } - - }); - - c = this.createWrapper (b); - this.setAsMainItem (c); - - box.add (c); - - return new SectionInfo (getUIString (options,editingchapters,title), - //"Editing {Chapters}", - Chapter.OBJECT_TYPE, - getUIString (options,editingchapters,text), - //"Everything to do with editing {chapters}. Manage your personal dictionary, the language for the project, set up auto save and how edit positions behave. All this and more for the low, low price of a few clicks.", - box); - - } - - private SectionInfo createNamingSection () - { - - final Options _this = this; - - Box box = new Box (BoxLayout.Y_AXIS); - - final JButton b = UIUtils.createButton (getUIString (options,naming,labels,changenames), - //"Change names", - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - _this.viewer.showObjectTypeNameChanger (); - - } - - }); - - JComponent c = this.createWrapper (b); - - this.setAsMainItem (c); - - box.add (c); - - return new SectionInfo (getUIString (options,naming,title), - //"What things are called", - Constants.CONFIG_ICON_NAME, - getUIString (options,naming,text), - //"Not happy with what things are called? Want to change {chapter} to sausage? What are you waiting for crack this section open and get changing. Yes that's a phrase now.", - box); - - } - - private SectionInfo createLookSection () - { - - final Options _this = this; - - //box.add (this.createHeader ("How things look and sound")); - //box.add (Box.createVerticalStrut (5)); - - Box box = new Box (BoxLayout.Y_AXIS); - - final JButton feedback = UIUtils.createButton (getUIString (options,lookandsound,labels,LanguageStrings.feedback), - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - _this.showSendFeedbackToUIStringsCreator (); - - } - - }); - - boolean showFeedbackB = true; - - LanguageStrings currUIL = Environment.getCurrentUILanguageStrings (); - - if ((currUIL.isEnglish ()) - || - (currUIL.isUser ()) - ) - { - - showFeedbackB = false; - - } - - feedback.setVisible (showFeedbackB); - - final JComboBox uiLangSel = UIUtils.getUILanguagesSelector (new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - final String uid = ev.getActionCommand (); - - feedback.setVisible ((!LanguageStrings.isEnglish (uid)) && (!uid.startsWith ("user-"))); - - if (uid.equals (UserProperties.get (Constants.USER_UI_LANGUAGE_PROPERTY_NAME))) - { - - return; - - } - - LanguageStrings ls = null; - - try - { - - ls = Environment.getUILanguageStrings (uid); - - } catch (Exception e) { - - Environment.logError ("Unable to get ui language for: " + uid, - e); - - UIUtils.showErrorMessage (_this, - getUIString (uilanguage,set,actionerror)); - - return; - - } - - ActionListener setLang = new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - try - { - - Environment.setUILanguage (uid); - - UIUtils.showMessage ((PopupsSupported) _this.viewer, - getUIString (uilanguage,set,restartwarning,title), - getUIString (uilanguage,set,restartwarning,text)); - - } catch (Exception e) { - - Environment.logError ("Unable to set ui language to: " + uid, - e); - - UIUtils.showErrorMessage (_this, - getUIString (uilanguage,set,actionerror)); - - } - - } - - }; - - if (ls == null) - { - - UIUtils.showMessage ((PopupsSupported) _this.viewer, - getUIString (uilanguage,set,downloading,title), - getUIString (uilanguage,set,downloading,text)); - - Environment.downloadUILanguageFile (uid, - setLang, - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - UIUtils.showErrorMessage (_this, - getUIString (uilanguage,set,actionerror)); - - } - - }); - - } else { - - setLang.actionPerformed (new ActionEvent (_this, 0, "set")); - - } - - } - - }, - UserProperties.get (Constants.USER_UI_LANGUAGE_PROPERTY_NAME)); - - JComponent c = this.createHelpText (getUIString (options,lookandsound,labels,uilanguage)); - this.setAsMainItem (c); - - box.add (c); - - Box lb = new Box (BoxLayout.X_AXIS); - - uiLangSel.setMaximumSize (uiLangSel.getPreferredSize ()); - - lb.add (uiLangSel); - lb.add (Box.createHorizontalStrut (10)); - - lb.add (feedback); - lb.add (Box.createHorizontalGlue ()); - - c = this.createWrapper (lb); - - box.add (Box.createVerticalStrut (5)); - this.setAsSubItem (c); - - box.add (c); - - JButton createTrans = UIUtils.createButton (getUIString (options,lookandsound,labels,createtranslation), - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - UIUtils.showAddNewLanguageStringsPopup (_this.viewer); - - } - - }); - - box.add (Box.createVerticalStrut (10)); - - JButton editTrans = UIUtils.createButton (getUIString (options,lookandsound,labels,edittranslation), - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - UIUtils.showEditLanguageStringsSelectorPopup (_this.viewer); - - } - - }); - - JButton[] tbuts = { createTrans, editTrans }; - - c = this.createWrapper (UIUtils.createButtonBar2 (tbuts, - JComponent.LEFT_ALIGNMENT)); - this.setAsSubItem (c); - - box.add (c); - - box.add (Box.createVerticalStrut (15)); - - final JCheckBox keepCB = UIUtils.createCheckBox (getUIString (options,lookandsound,labels,keepprojectswindowsopen)); - // ("Keep the {Projects} window open when a {project} is opened")); - - keepCB.setSelected (!UserProperties.getAsBoolean (Constants.CLOSE_PROJECTS_WINDOW_WHEN_PROJECT_OPENED_PROPERTY_NAME)); - - keepCB.addItemListener (new ItemAdapter () - { - - public void itemStateChanged (ItemEvent ev) - { - - _this.updateUserProperty (Constants.CLOSE_PROJECTS_WINDOW_WHEN_PROJECT_OPENED_PROPERTY_NAME, - !keepCB.isSelected ()); - - } - - }); - - c = this.createWrapper (keepCB); - this.setAsMainItem (c); - - box.add (c); - - box.add (Box.createVerticalStrut (15)); - - final JCheckBox openPWCB = UIUtils.createCheckBox (getUIString (options,lookandsound,labels,showprojectswindownoopenproject)); - //"Show the {Projects} window when I have no open {projects}")); - - openPWCB.setSelected (UserProperties.getAsBoolean (Constants.SHOW_PROJECTS_WINDOW_WHEN_NO_OPEN_PROJECTS_PROPERTY_NAME)); - - openPWCB.addItemListener (new ItemAdapter () - { - - public void itemStateChanged (ItemEvent ev) - { - - _this.updateUserProperty (Constants.SHOW_PROJECTS_WINDOW_WHEN_NO_OPEN_PROJECTS_PROPERTY_NAME, - openPWCB.isSelected ()); - - } - - }); - - c = this.createWrapper (openPWCB); - this.setAsMainItem (c); - - box.add (c); - - box.add (Box.createVerticalStrut (15)); - - final JCheckBox showPrev = UIUtils.createCheckBox (getUIString (options,lookandsound,labels,showpreview)); - //"Show a brief preview of the object when you mouse over its name in the {project} sidebar")); - showPrev.setSelected (UserProperties.getAsBoolean (Constants.SHOW_QUICK_OBJECT_PREVIEW_IN_PROJECT_SIDEBAR_PROPERTY_NAME)); - - showPrev.addItemListener (new ItemAdapter () - { - - public void itemStateChanged (ItemEvent ev) - { - - _this.updateUserProperty (Constants.SHOW_QUICK_OBJECT_PREVIEW_IN_PROJECT_SIDEBAR_PROPERTY_NAME, - showPrev.isSelected ()); - - } - - }); - - c = this.createWrapper (showPrev); - this.setAsMainItem (c); - - box.add (c); - - box.add (Box.createVerticalStrut (5)); - - JButton but = UIUtils.createButton (getUIString (options,lookandsound,labels,changedisplay), - //"Change what is displayed", - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - _this.showEditChapterInfo (); - - } - - }); - - c = this.createWrapper (but); - this.setAsSubItem (c); - - box.add (c); - - box.add (Box.createVerticalStrut (15)); - - final JCheckBox showNotesInChapterList = UIUtils.createCheckBox (getUIString (options,lookandsound,labels,shownotes)); - showNotesInChapterList.setSelected (UserProperties.getAsBoolean (Constants.SHOW_NOTES_IN_CHAPTER_LIST_PROPERTY_NAME)); - - showNotesInChapterList.addItemListener (new ItemAdapter () - { - - public void itemStateChanged (ItemEvent ev) - { - - _this.updateUserProperty (Constants.SHOW_NOTES_IN_CHAPTER_LIST_PROPERTY_NAME, - showNotesInChapterList.isSelected ()); - - Environment.doForOpenProjects (Project.NORMAL_PROJECT_TYPE, - new ProjectViewerAction () - { - - public void doAction (ProjectViewer pv) - { - - pv.reloadChapterTree (); - - } - - }); - - } - - }); - - c = this.createWrapper (showNotesInChapterList); - this.setAsMainItem (c); - - box.add (c); - - box.add (Box.createVerticalStrut (15)); - - c = this.createHelpText (getUIString (options,lookandsound,labels,interfacelayout,text)); - this.setAsMainItem (c); - - box.add (c); - - String selLayout = UserProperties.get (Constants.UI_LAYOUT_PROPERTY_NAME); - - final JLabel layoutSel = new JLabel (new LayoutImagePanel (selLayout)); - - UIUtils.setAsButton (layoutSel); - - layoutSel.addMouseListener (new MouseEventHandler () - { - - @Override - public void handlePress (MouseEvent ev) - { - - String selLayout = UserProperties.get (Constants.UI_LAYOUT_PROPERTY_NAME); - - final QPopup qp = UIUtils.createClosablePopup (getUIString (options,lookandsound,labels,interfacelayout,popup,title), - //"Select a layout", - Environment.getIcon (Constants.EDIT_ICON_NAME, - Constants.ICON_POPUP), - null); - - Box content = new Box (BoxLayout.Y_AXIS); - - Vector layoutTypes = new Vector (); - layoutTypes.add (Constants.LAYOUT_PS_CH); - layoutTypes.add (Constants.LAYOUT_CH_PS); - layoutTypes.add (Constants.LAYOUT_PS_CH_OS); - layoutTypes.add (Constants.LAYOUT_OS_CH_PS); - layoutTypes.add (Constants.LAYOUT_PS_OS_CH); - layoutTypes.add (Constants.LAYOUT_CH_OS_PS); - - final JList layoutL = new JList (layoutTypes); - - layoutL.setSelectedValue (selLayout, - false); - - layoutL.setToolTipText (getUIString (options,lookandsound,labels,interfacelayout,popup,tooltip)); - //"Click to select a layout"); - layoutL.addListSelectionListener (new ListSelectionListener () - { - - public void valueChanged (ListSelectionEvent ev) - { - - final String layout = layoutL.getSelectedValue (); - - layoutSel.setIcon (new LayoutImagePanel (layout)); - - qp.removeFromParent (); - - _this.updateUserProperty (Constants.UI_LAYOUT_PROPERTY_NAME, - layout); - - Environment.doForOpenProjectViewers (AbstractProjectViewer.class, - new ProjectViewerAction () - { - - public void doAction (AbstractProjectViewer pv) - { - - pv.setUILayout (layout); - - } - - }); - - Environment.fireUserProjectEvent (_this, - ProjectEvent.LAYOUT, - ProjectEvent.CHANGED); - - } - - }); - - layoutL.setCellRenderer (new DefaultListCellRenderer () - { - - private Map images = new HashMap (); - - public Component getListCellRendererComponent (JList list, - Object value, - int index, - boolean isSelected, - boolean cellHasFocus) - { - - super.getListCellRendererComponent (list, - value, - index, - isSelected, - cellHasFocus); - - String imName = value.toString (); - - this.setIcon (new LayoutImagePanel (imName)); - this.setText (String.format ("%s", - getUIString (options,lookandsound,interfacelayouts,imName))); - //Environment.replaceObjectNames (text))); - this.setBorder (UIUtils.createPadding (5, 3, 5, 3)); - this.setVerticalTextPosition (SwingConstants.TOP); - - if (isSelected) - { - - this.setBorder (new CompoundBorder (UIUtils.createLineBorder (), - this.getBorder ())); - - } - - return this; - - } - - }); - - UIUtils.setAsButton (layoutL); - - content.add (layoutL); - content.setBorder (UIUtils.createPadding (10, 10, 10, 10)); - qp.setContent (content); - - content.setPreferredSize (new Dimension (UIUtils.getPopupWidth (), - content.getPreferredSize ().height)); - - _this.viewer.showPopupAt (qp, - UIUtils.getCenterShowPosition (_this.viewer, - qp), - false); - - qp.setDraggable (_this.viewer); - - } - - }); - - c = this.createWrapper (layoutSel); - - box.add (Box.createVerticalStrut (5)); - - this.setAsSubItem (c); - - box.add (c); - - box.add (Box.createVerticalStrut (15)); - - c = this.createHelpText (getUIString (options,lookandsound,labels,showtoolbar)); - //"Show the toolbar"); - this.setAsMainItem (c); - - box.add (c); - - Vector v = new Vector (); - v.add (getUIString (options,lookandsound,labels,abovesidebar)); - //"Above the sidebar")); - v.add (getUIString (options,lookandsound,labels,belowsidebar)); - //"Below the sidebar")); - - final JComboBox toolbarLoc = new JComboBox (v); - - String loc = UserProperties.get (Constants.TOOLBAR_LOCATION_PROPERTY_NAME); - - int ind = 0; - - if (loc.equals (Constants.BOTTOM)) - { - - ind = 1; - - } - - toolbarLoc.setSelectedIndex (ind); - - toolbarLoc.addItemListener (new ItemAdapter () - { - - public void itemStateChanged (ItemEvent ev) - { - - if (ev.getStateChange () != ItemEvent.SELECTED) - { - - return; - - } - - String loc = Constants.TOP; - - if (toolbarLoc.getSelectedIndex () == 1) - { - - loc = Constants.BOTTOM; - - } - - if (loc.equals (UserProperties.get (Constants.TOOLBAR_LOCATION_PROPERTY_NAME))) - { - - return; - - } - - final String _loc = loc; - - _this.updateUserProperty (Constants.TOOLBAR_LOCATION_PROPERTY_NAME, - loc); - - Environment.doForOpenProjectViewers (AbstractProjectViewer.class, - new ProjectViewerAction () - { - - public void doAction (AbstractProjectViewer pv) - { - - pv.setToolbarLocation (_loc); - - } - - }); - - Environment.fireUserProjectEvent (_this, - ProjectEvent.TOOLBAR, - ProjectEvent.MOVE); - - } - - }); - - c = this.createWrapper (toolbarLoc); - this.setAsSubItem (c); - - box.add (c); - - box.add (Box.createVerticalStrut (15)); - - // Sidebar location - c = this.createHelpText (getUIString (options,lookandsound,labels,showtabs)); - //"Show the tabs"); - this.setAsMainItem (c); - - box.add (c); - - v = new Vector (); - v.add (getUIString (options,lookandsound,labels,showtabstop)); - // ("At the top")); - v.add (getUIString (options,lookandsound,labels,showtabsbottom)); - // ("At the bottom")); - - final JComboBox tabsLoc = new JComboBox (v); - - loc = UserProperties.get (Constants.TABS_LOCATION_PROPERTY_NAME); - - ind = 0; - - if (loc.equals (Constants.BOTTOM)) - { - - ind = 1; - - } - - tabsLoc.setSelectedIndex (ind); - - tabsLoc.addItemListener (new ItemAdapter () - { - - public void itemStateChanged (ItemEvent ev) - { - - if (ev.getStateChange () != ItemEvent.SELECTED) - { - - return; - - } - - String loc = Constants.TOP; - - if (tabsLoc.getSelectedIndex () == 1) - { - - loc = Constants.BOTTOM; - - } - - if (tabsLoc.getSelectedIndex () == 2) - { - - loc = Constants.LEFT; - - } - - if (tabsLoc.getSelectedIndex () == 3) - { - - loc = Constants.RIGHT; - - } - - if (loc.equals (UserProperties.get (Constants.TABS_LOCATION_PROPERTY_NAME))) - { - - return; - - } - - final String _loc = loc; - - _this.updateUserProperty (Constants.TABS_LOCATION_PROPERTY_NAME, - loc); - - Environment.doForOpenProjectViewers (AbstractProjectViewer.class, - new ProjectViewerAction () - { - - public void doAction (AbstractProjectViewer pv) - { - - pv.setTabsLocation (_loc); - - } - - }); - - Environment.fireUserProjectEvent (_this, - ProjectEvent.TABS, - ProjectEvent.MOVE); - - } - - }); - - c = this.createWrapper (tabsLoc); - this.setAsSubItem (c); - - box.add (c); - - box.add (Box.createVerticalStrut (15)); - - c = this.createHelpText (getUIString (options,lookandsound,labels,whenfind)); - //"When I do a find"); - this.setAsMainItem (c); - - box.add (c); - - final JRadioButton eachChap = UIUtils.createRadioButton (getUIString (options,lookandsound,labels,expandall)); - //"Expand all {chapters} to show all results"); - final JRadioButton justChap = UIUtils.createRadioButton (getUIString (options,lookandsound,labels,justchapter)); - //"Just show the {chapter}"); - - boolean showEachChapResult = UserProperties.getAsBoolean (Constants.SHOW_EACH_CHAPTER_FIND_RESULT_PROPERTY_NAME); - - eachChap.setSelected (showEachChapResult); - justChap.setSelected (!showEachChapResult); - - ButtonGroup g = new ButtonGroup (); - g.add (eachChap); - g.add (justChap); - - eachChap.addItemListener (new ItemAdapter () - { - - public void itemStateChanged (ItemEvent ev) - { - - UserProperties.set (Constants.SHOW_EACH_CHAPTER_FIND_RESULT_PROPERTY_NAME, - true); - - } - - }); - - justChap.addItemListener (new ItemAdapter () - { - - public void itemStateChanged (ItemEvent ev) - { - - UserProperties.set (Constants.SHOW_EACH_CHAPTER_FIND_RESULT_PROPERTY_NAME, - false); - - } - - }); - - c = this.createWrapper (eachChap); - this.setAsSubItem (c); - - box.add (c); - - c = this.createWrapper (justChap); - this.setAsSubItem (c); - - box.add (c); - - box.add (Box.createVerticalStrut (10)); - - final JCheckBox playSound = UIUtils.createCheckBox (getUIString (options,lookandsound,labels,playtypewritersound,text)); - //"Play a typewriter sound when editing a {chapter}.")); - - boolean playSoundEnabled = UserProperties.getAsBoolean (Constants.PLAY_SOUND_ON_KEY_STROKE_PROPERTY_NAME); - - final FileFinder f = new FileFinder (); - final JButton useB = UIUtils.createButton (getUIString (options,lookandsound,labels,playtypewritersound,buttons,usesound)); - //"Use Sound"); - final JButton testB = UIUtils.createButton (getUIString (options,lookandsound,labels,playtypewritersound,buttons,playsound)); - //"Play Sound"); - - f.setEnabled (playSoundEnabled); - playSound.setOpaque (false); - playSound.addItemListener (new ItemAdapter () - { - - public void itemStateChanged (ItemEvent ev) - { - - boolean sel = playSound.isSelected (); - - f.setEnabled (sel); - - if ((sel) - && - (f.getSelectedFile () != null) - && - (f.getSelectedFile ().exists ()) - ) - { - - useB.setEnabled (true); - - } else { - - useB.setEnabled (false); - - } - - Environment.setPlaySoundOnKeyStroke (sel); - - _this.updateUserProperty (Constants.PLAY_SOUND_ON_KEY_STROKE_PROPERTY_NAME, - sel); - - } - - }); - - playSound.setSelected (playSoundEnabled); - - box.add (Box.createVerticalStrut (5)); - - c = this.createWrapper (playSound); - this.setAsMainItem (c); - - box.add (c); - - box.add (Box.createVerticalStrut (5)); - - c = this.createHelpText (getUIString (options,lookandsound,labels,playtypewritersound,selectownwavfile)); - //"Or, select your own WAV file that will be played instead. (Note: only .wav files are supported.)"); - this.setAsSubItem (c); - - box.add (c); - - String sf = UserProperties.get (Constants.KEY_STROKE_SOUND_FILE_PROPERTY_NAME); - - if (sf == null) - { - - sf = ""; - - } - - final String sfv = sf; - - f.setFile (new File (sfv)); - - f.setApproveButtonText (getUIString (options,lookandsound,labels,playtypewritersound,finder,button)); - //"Select"); - f.setFinderSelectionMode (JFileChooser.FILES_ONLY); - f.setFinderTitle (getUIString (options,lookandsound,labels,playtypewritersound,finder,title)); - //"Select a File"); - - f.setFileFilter (new FileNameExtensionFilter (getUIString (options,lookandsound,labels,playtypewritersound,finder,filter), - //"Supported Files (wav)", - "wav")); - - f.setFindButtonToolTip (getUIString (options,lookandsound,labels,playtypewritersound,finder,tooltip)); - //"Click to find a wav file"); - f.setClearOnCancel (true); - f.setMaximumSize (new Dimension (400, - f.getPreferredSize ().height)); - - f.setOnSelectHandler (new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - useB.setEnabled (true); - testB.setEnabled (true); - - } - - }); - - f.showCancel (true, - new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - UserProperties.remove (Constants.KEY_STROKE_SOUND_FILE_PROPERTY_NAME); - - // Reset to the default. - Environment.setKeyStrokeSoundFile (null); - - useB.setEnabled (false); - testB.setEnabled (false); - - } - - }); - - f.init (); - - boolean sel = (f.getSelectedFile ().exists () && playSoundEnabled); - useB.setEnabled (sel); - testB.setEnabled (sel); - - c = this.createWrapper (f); - this.setAsSubItem (c); - - box.add (c); - - useB.addActionListener (new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - File file = f.getSelectedFile (); - - if ((file != null) - && - (file.exists ()) - ) - { - - try - { - - Environment.setKeyStrokeSoundFile (file); - - } catch (Exception e) - { - - Environment.logError ("Unable to set key stroke sound file to: " + - file.getPath (), - e); - - UIUtils.showErrorMessage (_this, - getUIString (options,lookandsound,labels,playtypewritersound,actionerror)); - //file.getName () + " is not a valid .wav file."); - - } - - } - - } - - }); - - testB.addActionListener (new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - File file = f.getSelectedFile (); - - try - { - - InputStream is = null; - - if (file != null) - { - - if ((file.exists ()) && - (file.getName ().toLowerCase ().endsWith (".wav"))) - { - - is = new BufferedInputStream (new FileInputStream (file)); - - } else - { - - UIUtils.showErrorMessage (_this, - getUIString (options,lookandsound,labels,playtypewritersound,actionerror)); - //file.getName () + " is not a valid .wav file."); - - return; - - } - - } - - if (is == null) - { - - // Play the default. - is = Environment.getResourceStream (Constants.DEFAULT_KEY_STROKE_SOUND_FILE); - - } - - // Get the clip. - AudioInputStream ais = AudioSystem.getAudioInputStream (is); - - Clip c = AudioSystem.getClip (); - - c.open (ais); - - c.start (); - - } catch (Exception e) - { - - Environment.logError ("Unable to play sound file: " + - file, - e); - - UIUtils.showErrorMessage (_this, - getUIString (options,lookandsound,labels,playtypewritersound,actionerror)); - //"Unable to play sound file."); - - } - - } - - }); - - JButton buts[] = new JButton[2]; - - buts[0] = useB; - buts[1] = testB; - - JPanel bp = UIUtils.createButtonBar2 (buts, - Component.LEFT_ALIGNMENT); //ButtonBarFactory.buildLeftAlignedBar (buts); - bp.setOpaque (false); - - c = this.createWrapper (bp); - - box.add (Box.createVerticalStrut (5)); - - this.setAsSubItem (c); - - box.add (c); - - final JCheckBox highlightSPDivs = UIUtils.createCheckBox (getUIString (options,lookandsound,labels,highlightdividers,text)); - //"Highlight dividers when I move the mouse over them"); - highlightSPDivs.setToolTipText (getUIString (options,lookandsound,labels,highlightdividers,tooltip)); - //"This is for dividers that allow you to slide panels left and right or up and down. It allows you to more easily see the divider."); - - boolean highlight = UserProperties.getAsBoolean (Constants.HIGHLIGHT_SPLITPANE_DIVIDERS_PROPERTY_NAME); - - highlightSPDivs.setSelected (highlight); - - highlightSPDivs.addItemListener (new ItemAdapter () - { - - public void itemStateChanged (ItemEvent ev) - { - - UserProperties.set (Constants.HIGHLIGHT_SPLITPANE_DIVIDERS_PROPERTY_NAME, - highlightSPDivs.isSelected ()); - - } - - }); - - box.add (Box.createVerticalStrut (10)); - - c = this.createWrapper (highlightSPDivs); - this.setAsMainItem (c); - - box.add (c); - - return new SectionInfo (getUIString (options,lookandsound,title), - //"How things look and sound", - "eye", - getUIString (options,lookandsound,text), - //"Want a sound to play whenever a key is pressed? Want to move the tabs or sidebar around? Want to show useful tips when Quoll Writer starts? This is the section for you.", - box); - - } - - private SectionInfo createAssetsSection () - { -/* - if (!(this.viewer instanceof ProjectViewer)) - { - - return null; - - } - */ - final Options _this = this; - - Box box = new Box (BoxLayout.Y_AXIS); - - JComponent c = this.createHelpText (getUIString (options,assets,labels,newasset,text)); - //"Add new Assets ({Characters}, {Locations}, etc) in"); - this.setAsMainItem (c); - - box.add (c); - - final JRadioButton rbAssetInPopup = UIUtils.createRadioButton (getUIString (options,assets,labels,newasset,options,alwayspopup,text)); - //"Always use a Popup"); - rbAssetInPopup.setToolTipText (getUIString (options,assets,labels,newasset,options,alwayspopup,tooltip)); - //"If the Asset has more than just a name and description field then a link will be shown to add the Asset, and thus see all the fields, in a tab instead."); - final JRadioButton rbAssetTryPopup = UIUtils.createRadioButton (getUIString (options,assets,labels,newasset,options,popupifpossible,text)); - //"Use a Popup if possible"); - rbAssetTryPopup.setToolTipText (getUIString (options,assets,labels,newasset,options,popupifpossible,tooltip)); - //"If the Asset only has a name and a description field then a popup will be used, otherwise a tab will be used."); - final JRadioButton rbAssetInTab = UIUtils.createRadioButton (getUIString (options,assets,labels,newasset,options,owntab,text)); - //"Their own tab"); - - String addAsset = UserProperties.get (Constants.ADD_ASSETS_PROPERTY_NAME); - - if (addAsset == null) - { - - addAsset = "popup"; - - } - - rbAssetInPopup.setSelected (addAsset.equals ("popup")); - rbAssetTryPopup.setSelected (addAsset.equals ("trypopup")); - rbAssetInTab.setSelected (addAsset.equals ("tab")); - - ButtonGroup g = new ButtonGroup (); - g.add (rbAssetInPopup); - g.add (rbAssetTryPopup); - g.add (rbAssetInTab); - - rbAssetInPopup.addItemListener (new ItemAdapter () - { - - public void itemStateChanged (ItemEvent ev) - { - - UserProperties.set (Constants.ADD_ASSETS_PROPERTY_NAME, - "popup"); - - } - - }); - - rbAssetTryPopup.addItemListener (new ItemAdapter () - { - - public void itemStateChanged (ItemEvent ev) - { - - UserProperties.set (Constants.ADD_ASSETS_PROPERTY_NAME, - "trypopup"); - - } - - }); - - rbAssetInTab.addItemListener (new ItemAdapter () - { - - public void itemStateChanged (ItemEvent ev) - { - - UserProperties.set (Constants.ADD_ASSETS_PROPERTY_NAME, - "tab"); - - } - - }); - - c = this.createWrapper (rbAssetInPopup); - this.setAsSubItem (c); - - box.add (c); - - c = this.createWrapper (rbAssetTryPopup); - this.setAsSubItem (c); - - box.add (c); - - c = this.createWrapper (rbAssetInTab); - this.setAsSubItem (c); - - box.add (c); - - box.add (Box.createVerticalStrut (15)); - - c = this.createHelpText (getUIString (options,assets,labels,editassetconfig)); - //"Edit the Asset configuration (Layout, Fields, Name, Icon etc)"); - this.setAsMainItem (c); - - box.add (c); - - Vector v = new Vector (); - - for (UserConfigurableObjectType t : Environment.getAssetUserConfigurableObjectTypes (true)) - { - - v.add (t); - - } - - final JComboBox assetTypes = new JComboBox (v); - assetTypes.setEditable (false); - - assetTypes.setRenderer (new DefaultListCellRenderer () - { - - @Override - public Component getListCellRendererComponent (JList list, - Object value, - int index, - boolean isSelected, - boolean cellHasFocus) - { - - super.getListCellRendererComponent (list, - value, - index, - isSelected, - cellHasFocus); - - UserConfigurableObjectType t = (UserConfigurableObjectType) value; - - this.setText (t.getObjectTypeNamePlural ()); - this.setIcon (t.getIcon16x16 ()); - this.setBorder (UIUtils.createPadding (3, 3, 3, 3)); - - return this; - - } - - }); - - assetTypes.setMaximumSize (assetTypes.getPreferredSize ()); - - Box bb = new Box (BoxLayout.X_AXIS); - - bb.add (assetTypes); - bb.add (Box.createHorizontalStrut (5)); - - JButton editType = UIUtils.createButton (getUIString (buttons,edit), - //"Edit", - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - UserConfigurableObjectType t = (UserConfigurableObjectType) assetTypes.getSelectedItem (); - - UIUtils.showObjectTypeEdit (t, - _this.viewer); - - } - - }); - - bb.add (editType); - bb.add (Box.createHorizontalGlue ()); - - c = this.createWrapper (bb); - this.setAsSubItem (c); - - box.add (c); - - box.add (Box.createVerticalStrut (15)); - -/* - JButton tags = new JButton ("Manage the Tags"); - - tags.addActionListener (new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.viewer.showEditTags (); - - } - - }); -*/ - JButton addType = UIUtils.createButton (getUIString (options,assets,labels,addtype)); - //"Add Type"); - - addType.addActionListener (new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - UIUtils.showAddNewObjectType (_this.viewer); - - } - - }); - - JButton buts[] = new JButton[] { addType }; - - JPanel bp = UIUtils.createButtonBar2 (buts, - Component.LEFT_ALIGNMENT); - bp.setOpaque (false); - - c = this.createWrapper (bp); - - //c = this.createWrapper (mb); - this.setAsMainItem (c); - - box.add (c); - - return new SectionInfo (getUIString (options,assets,title), - //"Assets", - Constants.ASSETS_ICON_NAME, - getUIString (options,assets,text), - ////"Need to add another field to an asset? Manage the tags? Change the names of things, change the icons? This section has you covered, you can also right click on the section header in the sidebar to do this stuff as well.", - box); - - } - - private SectionInfo createProjectSection () - { - - if (!(this.viewer instanceof AbstractProjectViewer)) - { - - return null; - - } - - final Options _this = this; - - final Project proj = ((AbstractProjectViewer) this.viewer).getProject (); - - Box box = new Box (BoxLayout.Y_AXIS); - - final JButton b = UIUtils.createButton (getUIString (options,projectandbackup,labels,selectprojectdir,finder,label)); - //"Change"); - - final FileFinder f = UIUtils.createFileFind (proj.getProjectDirectory ().getParentFile ().getPath (), - getUIString (options,projectandbackup,labels,selectprojectdir,finder,title), - //"Select a Directory", - JFileChooser.DIRECTORIES_ONLY, - getUIString (options,projectandbackup,labels,selectprojectdir,finder,button), - //"Select", - null); - f.setFindButtonToolTip (getUIString (options,projectandbackup,labels,selectprojectdir,finder,tooltip)); - //"Click to find a new {project} directory")); - f.setMaximumSize (new Dimension (400, - f.getPreferredSize ().height)); - - f.setOnSelectHandler (new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - b.setEnabled (!f.getSelectedFile ().getPath ().equals (proj.getProjectDirectory ().getParentFile ().getPath ())); - - } - - }); - - JComponent c = this.createHelpText (getUIString (options,projectandbackup,labels,selectprojectdir,text)); - //"Select the directory where your {project} is stored"); - this.setAsMainItem (c); - - box.add (c); - - c = this.createWrapper (f); - this.setAsSubItem (c); - - box.add (c); - - box.add (Box.createVerticalStrut (5)); - - b.setEnabled (false); - - b.addActionListener (new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.handleProjectDirChange (f); - - } - - }); - - c = this.createWrapper (b); - this.setAsSubItem (c); - - box.add (c); - - box.add (Box.createVerticalStrut (15)); - - Vector backupsA = new Vector (); - backupsA.add (getUIString (times,hours12)); //Constants.HOURS_12); - backupsA.add (getUIString (times,hours24)); //Constants.HOURS_24); - backupsA.add (getUIString (times,days2)); //Constants.DAYS_2); - backupsA.add (getUIString (times,days5)); //Constants.DAYS_5); - backupsA.add (getUIString (times,week1)); //Constants.WEEK_1); - - final JComboBox backupsAmount = new JComboBox (backupsA); - - Vector vals = new Vector (); - vals.add (Environment.formatNumber (10)); //Constants.COUNT_10); - vals.add (Environment.formatNumber (20)); //Constants.COUNT_20); - vals.add (Environment.formatNumber (50)); //Constants.COUNT_50); - vals.add (getUIString (options,projectandbackup,labels,all)); //Constants.COUNT_ALL); - - final JComboBox backupsCount = new JComboBox (vals); - - int count = -1; - - String backupsKeep = proj.getProperty (Constants.BACKUPS_TO_KEEP_COUNT_PROPERTY_NAME); - - // Pre 2.6.5 - if ((backupsKeep != null) - && - (backupsKeep.equals ("All")) - ) - { - - try - { - - count = Integer.parseInt (backupsKeep); - - } catch (Exception e) { - - Environment.logError ("Unable to convert property: " + - Constants.BACKUPS_TO_KEEP_COUNT_PROPERTY_NAME + - " with value: " + - backupsKeep + - " to an int.", - e); - - } - - } - - int selInd = 3; - - if (count == 10) - { - - selInd = 0; - - } - - if (count == 20) - { - - selInd = 1; - - } - - if (count == 50) - { - - selInd = 2; - - } - - backupsCount.setSelectedIndex (selInd); - //proj.getProperty (Constants.BACKUPS_TO_KEEP_COUNT_PROPERTY_NAME)); - - backupsCount.addItemListener (new ItemAdapter () - { - - public void itemStateChanged (ItemEvent ev) - { - - if (ev.getStateChange () != ItemEvent.SELECTED) - { - - return; - - } - - int selInd = backupsCount.getSelectedIndex (); - - int count = 10; - - if (selInd == 1) - { - - count = 20; - - } - - if (selInd == 2) - { - - count = 50; - - } - - if (selInd == 3) - { - - count = -1; - - } - - _this.updateDefaultProjectProperty (Constants.BACKUPS_TO_KEEP_COUNT_PROPERTY_NAME, - String.valueOf (count)); - //(String) backupsCount.getSelectedItem ()); - - if (count > -1) - { - - try - { - - AbstractProjectViewer pv = (AbstractProjectViewer) _this.viewer; - - pv.getObjectManager ().pruneBackups (pv.getProject (), - count); - //Utils.getCountAsInt ((String) backupsCount.getSelectedItem ())); - - } catch (Exception e) { - - Environment.logError ("Unable to prune backups for project: " + - proj, - e); - - } - - } - - } - - }); - - final JCheckBox enableBackups = UIUtils.createCheckBox (getUIString (options,projectandbackup,labels,autobackup)); - //"Automatically create backups of the {project}"); - enableBackups.setOpaque (false); - - c = this.createWrapper (enableBackups); - this.setAsMainItem (c); - - box.add (c); - - box.add (Box.createVerticalStrut (5)); - - boolean backupsEnabled = proj.getPropertyAsBoolean (Constants.AUTO_SNAPSHOTS_ENABLED_PROPERTY_NAME); - enableBackups.setSelected (backupsEnabled); - - long backupsTime = Utils.getTimeAsMillis (proj.getProperty (Constants.AUTO_SNAPSHOTS_TIME_PROPERTY_NAME)); - - int btInd = 0; // 12 hours - - if (backupsTime == (24 * Constants.HOUR_IN_MILLIS)) - { - - btInd = 1; - - } - - if (backupsTime == (2 * Constants.DAY_IN_MILLIS)) - { - - btInd = 2; - - } - - if (backupsTime == (5 * Constants.DAY_IN_MILLIS)) - { - - btInd = 3; - - } - - if (backupsTime == (7 * Constants.DAY_IN_MILLIS)) - { - - btInd = 4; - - } - - backupsAmount.setSelectedIndex (btInd); - // (proj.getProperty (Constants.AUTO_SNAPSHOTS_TIME_PROPERTY_NAME)); - backupsAmount.setEnabled (backupsEnabled); - - backupsAmount.addItemListener (new ItemAdapter () - { - - public void itemStateChanged (ItemEvent ev) - { - - if (ev.getStateChange () != ItemEvent.SELECTED) - { - - return; - - } - - int selInd = backupsAmount.getSelectedIndex (); - - long time = 0; - - if (selInd == 0) - { - - time = 12 * Constants.HOUR_IN_MILLIS; - - } - - if (selInd == 1) - { - - time = 24 * Constants.HOUR_IN_MILLIS; - - } - - if (selInd == 2) - { - - time = 2 * Constants.DAY_IN_MILLIS; - - } - - if (selInd == 3) - { - - time = 5 * Constants.DAY_IN_MILLIS; - - } - - if (selInd == 4) - { - - time = 7 * Constants.DAY_IN_MILLIS; - - } - - _this.updateDefaultProjectProperty (Constants.AUTO_SNAPSHOTS_TIME_PROPERTY_NAME, - String.valueOf (time)); - - } - - }); - - c = this.createHelpText (getUIString (options,projectandbackup,labels,createbackupafter)); - //"Create a new backup after the following time between sessions or during a session"); - this.setAsSubItem (c); - - box.add (c); - - c = this.createWrapper (backupsAmount); - this.setAsSubItem2 (c); - - box.add (c); - - box.add (Box.createVerticalStrut (10)); - - c = this.createHelpText (getUIString (options,projectandbackup,labels,nobackupstokeep)); - //"Number of backups to keep (oldest are deleted first)"); - this.setAsMainItem (c); - - box.add (c); - - c = this.createWrapper (backupsCount); - this.setAsSubItem (c); - - box.add (c); - - final JButton bb = UIUtils.createButton (getUIString (options,projectandbackup,labels,selectbackupdir,finder,label)); - //"Change"); - - final FileFinder bf = UIUtils.createFileFind (proj.getBackupDirectory ().getPath (), - getUIString (options,projectandbackup,labels,selectbackupdir,finder,title), - //"Select a Directory", - JFileChooser.DIRECTORIES_ONLY, - getUIString (options,projectandbackup,labels,selectbackupdir,finder,button), - //"Select", - null); - bf.setFindButtonToolTip (getUIString (options,projectandbackup,labels,selectbackupdir,finder,tooltip)); - // ("Click to find a new backup directory")); - bf.setMaximumSize (new Dimension (400, - bf.getPreferredSize ().height)); - - bf.setOnSelectHandler (new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - bb.setEnabled (!bf.getSelectedFile ().getPath ().equals (proj.getBackupDirectory ().getPath ())); - - } - - }); - - enableBackups.addItemListener (new ItemAdapter () - { - - public void itemStateChanged (ItemEvent ev) - { - - boolean sel = enableBackups.isSelected (); - - backupsAmount.setEnabled (sel); - - _this.updateDefaultProjectProperty (Constants.AUTO_SNAPSHOTS_ENABLED_PROPERTY_NAME, - sel); - - } - - }); - - box.add (Box.createVerticalStrut (10)); - - c = this.createHelpText (getUIString (options,projectandbackup,labels,selectbackupdir,text)); - //"Select the directory where {project} backups are stored"); - this.setAsMainItem (c); - - box.add (c); - - c = this.createWrapper (bf); - this.setAsSubItem (c); - - box.add (c); - - box.add (Box.createVerticalStrut (5)); - - bb.setEnabled (false); - - bb.addActionListener (new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.handleBackupsDirChange (bf); - - } - - }); - - c = this.createWrapper (bb); - this.setAsSubItem (c); - - box.add (c); - - box.add (Box.createVerticalStrut (10)); - - JButton create = UIUtils.createButton (getUIString (options,projectandbackup,labels,createbackup), - //Constants.CREATE_BACKUP_BUTTON_LABEL_ID, - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - UIUtils.showCreateBackup (proj, - null, - _this.viewer); - - } - - }); - - JButton manage = UIUtils.createButton (getUIString (options,projectandbackup,labels,managebackups), - //"Manage Backups", - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - UIUtils.showManageBackups (Environment.getProjectInfo (proj), - _this.viewer); - - } - - }); - - JButton buts[] = new JButton[] { create, manage }; - - JPanel bp = UIUtils.createButtonBar2 (buts, - Component.LEFT_ALIGNMENT); - bp.setOpaque (false); - - c = this.createWrapper (bp); - - //c = this.createWrapper (mb); - this.setAsMainItem (c); - - box.add (c); - - return new SectionInfo (getUIString (options,projectandbackup,title), - //"{Project} & Backups", - Constants.PROJECT_ICON_NAME, - getUIString (options,projectandbackup,text), - //"Click the title above to open this section. You can then change where your {project} is stored and how often backups are created and where they are stored.", - box); - - } - - private SectionInfo createWarmupsSection () - { - - final Options _this = this; - - //box.add (this.createHeader (UIUtils.formatForUser ("{Warmups}"))); - //box.add (Box.createVerticalStrut (5)); - - Box box = new Box (BoxLayout.Y_AXIS); - - JComponent c = this.createWrapper (WarmupPromptSelect.getDoWarmupOnStartupCheckbox ()); - this.setAsMainItem (c); - - box.add (c); - - box.add (Box.createVerticalStrut (5)); - - // Use the standard warmup strings. - - c = this.createHelpText (getUIString (options,warmups,labels,dofor)); - //"And do the {warmup} for"); - this.setAsSubItem (c); - - box.add (c); - - FormLayout fl = new FormLayout ("p, 6px, p, 6px, p, 6px, p", - "p"); - - PanelBuilder builder = new PanelBuilder (fl); - - CellConstraints cc = new CellConstraints (); - - final JComboBox words = WarmupPromptSelect.getWordsOptions (); - - builder.add (words, - cc.xy (1, - 1)); - - builder.addLabel (getUIString (options,warmups,labels,andor), - //"and/or", - cc.xy (3, - 1)); - - final JComboBox mins = WarmupPromptSelect.getTimeOptions (); - - builder.add (mins, - cc.xy (5, - 1)); - - builder.addLabel (getUIString (options,warmups,labels,whicheverfirst), - //"(whichever is reached first)", - cc.xy (7, - 1)); - - JPanel p = builder.getPanel (); - p.setOpaque (false); - p.setAlignmentX (Component.LEFT_ALIGNMENT); - - c = this.createWrapper (p); - this.setAsSubItem (c); - - box.add (c); - - //this.setContentBorder (box); - - SectionInfo info = new SectionInfo (getUIString (options,warmups,title), - //"{Warmups}", - Warmup.OBJECT_TYPE, - getUIString (options,warmups,text), - //"Want to flex your writing muscles everytime Quoll Writer starts? You'd better click the title above and get things set up while you still have time.", - box); - - return info; - - } - - private void setContentBorder (JComponent box) - { - - box.setBorder (UIUtils.createPadding (7, 0, 10, 0)); - - } - - private void updateUserProperty (String name, - boolean value) - { - - UserProperties.set (name, - value); - - if (this.viewer instanceof AbstractProjectViewer) - { - - ((AbstractProjectViewer) this.viewer).getProject ().getProperties ().removeProperty (name); - - } - - } - - private void updateUserProperty (String name, - String value) - { - - UserProperties.set (name, - value); - - if (this.viewer instanceof AbstractProjectViewer) - { - - ((AbstractProjectViewer) this.viewer).getProject ().getProperties ().removeProperty (name); - - } - - } - - private void updateDefaultProjectProperty (String name, - String value) - { - - Properties props = Environment.getDefaultProperties (Project.OBJECT_TYPE); - - props.setProperty (name, - new StringProperty (name, - value)); - - try - { - - Environment.saveDefaultProperties (Project.OBJECT_TYPE, - props); - - } catch (Exception e) - { - - Environment.logError ("Unable to save default project properties", - e); - - UIUtils.showErrorMessage (this, - getUIString (options,savepropertyerror)); - //"Unable to save default project properties"); - - } - - } - - private void updateDefaultProjectProperty (String name, - boolean value) - { - - Properties props = Environment.getDefaultProperties (Project.OBJECT_TYPE); - - props.setProperty (name, - new BooleanProperty (name, - value)); - - try - { - - Environment.saveDefaultProperties (Project.OBJECT_TYPE, - props); - - } catch (Exception e) - { - - Environment.logError ("Unable to save default project properties", - e); - - UIUtils.showErrorMessage (this, - getUIString (options,savepropertyerror)); - //"Unable to save default project properties"); - - } - - } - - private void updateProjectProperty (String name, - String value) - { - - AbstractProjectViewer pv = (AbstractProjectViewer) this.viewer; - - Properties props = pv.getProject ().getProperties (); - - props.setProperty (name, - new StringProperty (name, - value)); - - try - { - - pv.saveProject (); - - } catch (Exception e) - { - - Environment.logError ("Unable to save project", - e); - - UIUtils.showErrorMessage (this, - getUIString (options,savepropertyerror)); - //"Unable to save."); - - return; - - } - - } - - private boolean handleProjectDirChange (final FileFinder f) - { - - final Options _this = this; - - AbstractProjectViewer pv = (AbstractProjectViewer) this.viewer; - - final Project proj = pv.getProject (); - - final File oldProjDir = proj.getProjectDirectory (); - - final File newDir = f.getSelectedFile (); - - final File newProjDir = new File (newDir, - Utils.sanitizeForFilename (proj.getName ())); - - boolean backupIsSubDir = false; - - File _newBackupDir = null; - - if (Utils.isSubDir (proj.getProjectDirectory (), - proj.getBackupDirectory ())) - { - - backupIsSubDir = true; - - try - { - - _newBackupDir = new File (newProjDir.getPath () + proj.getBackupDirectory ().getCanonicalPath ().substring (proj.getProjectDirectory ().getCanonicalPath ().length ())); - - } catch (Exception e) { - - Environment.logError ("Unable to determine new backups directory for: " + - proj.getBackupDirectory () + - " to: " + - newProjDir); - - UIUtils.showErrorMessage (null, - getUIString (project,actions,changeprojectdir,actionerror)); - //"Unable to change project directory, please contact Quoll Writer support for assistance."); - - return false; - - } - - if (!Utils.isDirectoryEmpty (_newBackupDir)) - { - - UIUtils.showErrorMessage (this.viewer, - String.format (getUIString (project,actions,changeprojectdir,errors,backupdirnotempty), - _newBackupDir.getPath ())); - //"New backups directory: " + - //_newBackupDir + - //" is not empty."); - - f.setFile (oldProjDir); - - return false; - - } - - } - - final File newBackupDir = _newBackupDir; - - // See if the project directory is changing. - if (!newProjDir.equals (oldProjDir)) - { - - if (!Utils.isDirectoryEmpty (newProjDir)) - { - - UIUtils.showErrorMessage (this.viewer, - String.format (getUIString (project,actions,changeprojectdir,errors,dirnotempty), - newProjDir.getPath ())); - //"Unable to change {project} directory to: " + - //newProjDir + - //" directory is not empty."); - - f.setFile (oldProjDir); - - return false; - - } - - // Is changing so need to close the project. - Point p = SwingUtilities.convertPoint (f, - 0, - 0, - this.viewer); - - // Inception! Don't you just love asynchronous programming! - ActionListener confirmAction = new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - if (newBackupDir != null) - { - - // Need to change the backup dir first. - proj.setBackupDirectory (newBackupDir); - - } - - _this.viewer.close (true, - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - if (!proj.getProjectDirectory ().renameTo (newProjDir)) - { - - Environment.logError ("Unable to rename project directory: " + - proj.getProjectDirectory () + - " to: " + - newProjDir); - - UIUtils.showErrorMessage (null, - getUIString (project,actions,changeprojectdir,actionerror)); - //"Unable to change project directory, please contact Quoll Writer support for assistance."); - - } else { - - proj.setProjectDirectory (newProjDir); - - } - - // Open the project again. - try - { - - Environment.openProject (proj, - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - Environment.getProjectViewer (proj).fireProjectEventLater (proj.getObjectType (), - ProjectEvent.CHANGED_DIRECTORY); - - - } - - }); - - } catch (Exception e) - { - - // Show the projects window. - Environment.showLanding (); - - Environment.logError ("Unable to reopen project: " + - proj, - e); - - UIUtils.showErrorMessage (null, - getUIString (project,actions,changeprojectdir,errors,reopenproject)); - //"Unable to reopen project, please contact Quoll Writer support for assistance."); - - return; - - } - - // Finally, delete the old project directory. - //Utils.deleteDir (oldDir); - - } - - }); - - } - - }; - - ActionListener onCancel = new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - // Reset the file. - f.setFile (oldProjDir.getParentFile ()); - - } - - }; - - String extra = ""; - - if (backupIsSubDir) - { - - extra = getUIString (project,actions,changeprojectdir,confirmpopup,backupdirchangewarning); - //"Warning! The backups directory for this {project} will also be changed.

    "; - - } - - UIUtils.createQuestionPopup (this.viewer, - getUIString (project,actions,changeprojectdir,confirmpopup,title), - //"Confirm change to {project} directory?", - Project.OBJECT_TYPE, - String.format (getUIString (project,actions,changeprojectdir,confirmpopup,text), - extra), - //"To change the directory of a {project} it must first be saved and closed. Once the directory has been changed the {project} will be reopened.

    " + extra + "Do you wish to continue?", - getUIString (project,actions,changeprojectdir,confirmpopup,buttons,confirm), - //"Yes, change it", - getUIString (project,actions,changeprojectdir,confirmpopup,buttons,cancel), - //null, - confirmAction, - onCancel, - onCancel, - p); - - } - - return false; - - } - - private void handleBackupsDirChange (final FileFinder f) - { - - final Options _this = this; - - AbstractProjectViewer pv = (AbstractProjectViewer) this.viewer; - - final Project proj = pv.getProject (); - - final File oldDir = proj.getBackupDirectory (); - - final File newDir = f.getSelectedFile (); - - // See if the project directory is changing. - if (!newDir.equals (oldDir)) - { - - if (!Utils.isDirectoryEmpty (newDir)) - { - - UIUtils.showErrorMessage (this.viewer, - String.format (getUIString (project,actions,changebackupdir,errors,dirnotempty), - newDir.getPath ())); - //"Unable to change backup directory to: " + - //newDir + - //", directory is not empty."); - - return; - - } - - // Do a trick, delete the directory then rename to it. - if (newDir.exists ()) - { - - newDir.delete (); - - } - - // Just rename it. - if (!oldDir.renameTo (newDir)) - { - - UIUtils.showErrorMessage (this.viewer, - getUIString (project,actions,changebackupdir,actionerror)); - //"Unable to change backup directory to: " + - //newDir); - - return; - - } - - proj.setBackupDirectory (newDir); - - UIUtils.showMessage ((PopupsSupported) this.viewer, - getUIString (project,actions,changebackupdir,confirmpopup,title), - //"Backups directory changed", - String.format (getUIString (project,actions,changebackupdir,confirmpopup,text), - //"The backups directory for the {project} has been changed to %s.", - newDir.getPath ())); - - } - - } - - private Header createHeader (String title) - { - - return this.createHeader (title, - null); - - } - - private Header createHeader (String title, - String iconType) - { - - Header h = UIUtils.createHeader (title, - Constants.SUB_PANEL_TITLE, - iconType, - null); - - h.setBorder (UIUtils.createBottomLineWithPadding (0, 0, 3, 0)); - - return h; - - } - - private void setAsMainItem (JComponent c) - { - - c.setAlignmentX (Component.LEFT_ALIGNMENT); - c.setAlignmentY (Component.TOP_ALIGNMENT); - - c.setBorder (new CompoundBorder (new EmptyBorder (0, 5, 0, 10), - c.getBorder ())); - - } - - private void setAsSubItem (JComponent c) - { - - c.setAlignmentX (Component.LEFT_ALIGNMENT); - c.setAlignmentY (Component.TOP_ALIGNMENT); - - c.setBorder (new CompoundBorder (new EmptyBorder (0, 15, 0, 10), - c.getBorder ())); - - } - - private void setAsSubItem2 (JComponent c) - { - - c.setAlignmentX (Component.LEFT_ALIGNMENT); - c.setAlignmentY (Component.TOP_ALIGNMENT); - - c.setBorder (new CompoundBorder (new EmptyBorder (0, 20, 0, 10), - c.getBorder ())); - - } - - private JComponent createWrapper (JComponent c) - { - - if ((c instanceof JComboBox) - || - (c instanceof JCheckBox) - ) - { - - c.setMaximumSize (c.getPreferredSize ()); - - } - - c.setAlignmentX (Component.LEFT_ALIGNMENT); - c.setAlignmentY (Component.TOP_ALIGNMENT); - - if (!(c instanceof Box)) - { - - Box _b = new Box (BoxLayout.X_AXIS); - _b.add (Box.createHorizontalStrut (5)); - _b.add (c); - _b.add (Box.createHorizontalGlue ()); - _b.setAlignmentX (Component.LEFT_ALIGNMENT); - _b.setAlignmentY (Component.TOP_ALIGNMENT); - - c = _b; - - } else { - - c.setBorder (new EmptyBorder (0, 5, 0, 0)); - - } - - return c; - - } - - private JTextPane createHelpText (String text) - { - - JTextPane t = UIUtils.createHelpTextPane (text, - this.viewer); - t.setBorder (new EmptyBorder (0, - 5, - 5, - 5)); - - return t; - - } - - public void setState (final Map s) - { - - final Options _this = this; - - this.accordion.setState (s.get ("sections")); - - SwingUtilities.invokeLater (new Runnable () - { - - public void run () - { - - int o = 0; - - try - { - - o = Integer.parseInt (s.get ("scroll")); - - } catch (Exception e) { - - return; - - } - - _this.scrollPane.getVerticalScrollBar ().setValue (o); - - //_this.setReadyForUse (true); - - } - - }); - - } - - public void getState (Map m) - { - - m.put ("sections", - this.accordion.getState ()); - m.put ("scroll", - this.scrollPane.getVerticalScrollBar ().getValue ()); - - } - - public void showEditChapterInfo () - { - - final Options _this = this; - - String popupName = "editchapterinfo"; - final QPopup popup = UIUtils.createClosablePopup (getUIString (project,sidebar,chapters,preview,edit, LanguageStrings.popup,title), - //"Change what is displayed", - Environment.getIcon (Constants.EDIT_ICON_NAME, - Constants.ICON_POPUP), - null); - - popup.setPopupName (popupName); - - OptionsBox bb = new OptionsBox (this.viewer); - - final TextArea status = new TextArea (getUIString (project,sidebar,chapters,preview,edit, LanguageStrings.popup,tooltip), - //"Enter the format here...", - 3, - -1); - status.setMaximumSize (new Dimension (Short.MAX_VALUE, 100)); - status.setText (UserProperties.get (Constants.CHAPTER_INFO_PREVIEW_FORMAT, - Constants.DEFAULT_CHAPTER_INFO_PREVIEW_FORMAT)); - - final Chapter _bogus = new Chapter (); - _bogus.setKey (1L); - _bogus.setDescription (new StringWithMarkup (getUIString (project,sidebar,chapters,preview,edit, LanguageStrings.popup,examplechapter,description))); - //"This chapter will be really, really good once I actually start to write it.")); - _bogus.setText (new StringWithMarkup (getUIString (project,sidebar,chapters,preview,edit, LanguageStrings.popup,examplechapter,text))); - //"Once upon a time there was a little chapter that wanted to be written.")); - - final ProjectViewer _bogusPV = new ProjectViewer () - { - - public ChapterCounts getChapterCounts (Chapter c) - { - - ChapterCounts cc = new ChapterCounts (); - cc.wordCount = new TextIterator (_bogus.getChapterText ()).getWords ().size (); - - return cc; - - } - - public Set getSpellingErrors (Chapter c) - { - - Set ret = new HashSet (); - return ret; - - } - - public Set getProblems (Chapter c) - { - - Set ret = new HashSet (); - return ret; - - } - - }; - - final JComponent pb = UIUtils.getChapterInfoPreview (_bogus, - null, - _bogusPV); - - bb.addMain (getUIString (project,sidebar,chapters,preview,edit, LanguageStrings.popup,text), - //"Use the following format for {chapter} information. Click here for help on the format/tags that can be used.", - status); - - Box pbb = new Box (BoxLayout.X_AXIS); - - int BOX_WIDTH = 380; - - pbb.setMaximumSize (new Dimension (BOX_WIDTH, - Short.MAX_VALUE)); - - final Box previewWrapper = new Box (BoxLayout.Y_AXIS); - - previewWrapper.add (pb); - pbb.add (previewWrapper); - - status.addCaretListener (new CaretListener () - { - - @Override - public void caretUpdate (CaretEvent ev) - { - - UIUtils.doLater (new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - previewWrapper.removeAll (); - - previewWrapper.add (UIUtils.getChapterInfoPreview (_bogus, - status.getText (), - _bogusPV)); - - popup.resize (); - - } - - }); - - } - - }); - - bb.addMain (UIUtils.createBoldSubHeader (getUIString (project,sidebar,chapters,preview,edit, LanguageStrings.popup,examplechapter,title), - //"Example", - null), - pbb); - - Box content = new Box (BoxLayout.Y_AXIS); - - content.add (bb); - content.add (pbb); - content.add (Box.createVerticalStrut (15)); - - //content.add (Box.createVerticalGlue ()); - - JButton save = UIUtils.createButton (getUIString (project,sidebar,chapters,preview,edit, LanguageStrings.popup,buttons, LanguageStrings.save), - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - UserProperties.set (Constants.CHAPTER_INFO_PREVIEW_FORMAT, - status.getText ()); - - previewWrapper.removeAll (); - - previewWrapper.add (UIUtils.getChapterInfoPreview (_bogus, - status.getText (), - _bogusPV)); - - popup.resize (); - - } - - }); - - JButton cancel = UIUtils.createButton (getUIString (project,sidebar,chapters,preview,edit, LanguageStrings.popup,buttons, LanguageStrings.cancel), - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - UserProperties.set (Constants.CHAPTER_INFO_PREVIEW_FORMAT, - status.getText ()); - - popup.removeFromParent (); - - } - - }); - - JButton reset = UIUtils.createButton (getUIString (project,sidebar,chapters,preview,edit, LanguageStrings.popup,usedefault)); - //"Use default"); - - reset.addActionListener (new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - status.setText (UserProperties.get (Constants.DEFAULT_CHAPTER_INFO_PREVIEW_FORMAT)); - - previewWrapper.removeAll (); - - previewWrapper.add (UIUtils.getChapterInfoPreview (_bogus, - status.getText (), - _bogusPV)); - - popup.resize (); - - UserProperties.set (Constants.CHAPTER_INFO_PREVIEW_FORMAT, - status.getText ()); - - } - - }); - - JButton[] buts = { save, reset, cancel }; - - JPanel bp = UIUtils.createButtonBar2 (buts, - Component.CENTER_ALIGNMENT); - bp.setOpaque (false); - bp.setAlignmentX (JComponent.LEFT_ALIGNMENT); - content.add (bp); - - Box _content = new Box (BoxLayout.Y_AXIS); - _content.add (content); - - content.setBorder (UIUtils.createPadding (10, 10, 10, 10)); - - _content.setPreferredSize (new Dimension (UIUtils.getPopupWidth (), - _content.getPreferredSize ().height)); - - popup.setContent (_content); - - this.viewer.showPopupAt (popup, - UIUtils.getCenterShowPosition (this, - popup), - false); - - popup.setDraggable (this.viewer); - - } - - private void showSendFeedbackToUIStringsCreator () - { - - final Options _this = this; - - java.util.List prefix = Arrays.asList (uilanguage,feedback); - - String popupName = "contactuilangstrings-" + UserProperties.get (Constants.USER_UI_LANGUAGE_PROPERTY_NAME); - QPopup popup = this.viewer.getNamedPopup (popupName); - - if (popup == null) - { - - popup = UIUtils.createClosablePopup (getUIString (prefix, LanguageStrings.popup, LanguageStrings.title), - Environment.getIcon (Constants.EMAIL_ICON_NAME, - Constants.ICON_POPUP), - null); - - final QPopup qp = popup; - - popup.setPopupName (popupName); - - this.viewer.addNamedPopup (popupName, - popup); - - Box content = new Box (BoxLayout.Y_AXIS); - - JTextPane help = UIUtils.createHelpTextPane (String.format (getUIString (prefix, LanguageStrings.popup,text), - Environment.getCurrentUILanguageStrings ().getNativeName ()), - this.viewer); - - help.setBorder (null); - - content.add (help); - content.add (Box.createVerticalStrut (10)); - - String errText = getUIString (prefix, LanguageStrings.popup,errorlabel); - - final JLabel error = UIUtils.createErrorLabel (errText); - error.setVisible (false); - error.setBorder (UIUtils.createPadding (0, 0, 5, 5)); - - content.add (error); - - final MultiLineTextFormItem desc = new MultiLineTextFormItem (getUIString (prefix, LanguageStrings.popup,message,text), - getUIString (prefix, LanguageStrings.popup,message,tooltip), - 10, - 10000, - false, - null); - - final TextFormItem email = new TextFormItem (getUIString (prefix, LanguageStrings.popup, LanguageStrings.email,text), - null); - - Set items = new LinkedHashSet (); - - items.add (desc); - items.add (email); - - ActionListener sendAction = new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - error.setVisible (false); - - String emErr = Utils.checkEmail (email.getText ()); - - if (emErr != null) - { - - error.setText (emErr); - - error.setVisible (true); - - qp.resize (); - - return; - - } - - if (desc.getText ().trim ().equals ("")) - { - - error.setText (errText); - error.setVisible (true); - - qp.resize (); - - return; - - } - - qp.resize (); - - // Send the message. - Map details = new HashMap (); - details.put ("details", - desc.getText ()); - details.put ("email", - email.getText ()); - details.put ("uilanguageid", - Environment.getCurrentUILanguageStrings ().getId ()); - - try - { - - Environment.sendMessageToSupport ("uilanguage", - details, - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - desc.setText (""); - - UIUtils.showMessage ((PopupsSupported) _this.viewer, - getUIString (prefix,confirmpopup, LanguageStrings.title), - getUIString (prefix,confirmpopup,text)); - - } - - }); - - } catch (Exception e) - { - - Environment.logError ("Unable to send message to support", - e); - - UIUtils.showErrorMessage (_this, - getUIString (prefix,actionerror)); - //"Unable to send message."); - - } - - qp.removeFromParent (); - - } - - }; - - UIUtils.addDoActionOnReturnPressed (desc.getTextArea (), - sendAction); - UIUtils.addDoActionOnReturnPressed (email.getTextField (), - sendAction); - - JButton send = UIUtils.createButton (getUIString (prefix, LanguageStrings.popup, LanguageStrings.buttons, LanguageStrings.send), - sendAction); - JButton cancel = UIUtils.createButton (getUIString (prefix, LanguageStrings.popup, LanguageStrings.buttons, LanguageStrings.cancel), - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - qp.removeFromParent (); - - } - - }); - - Set buttons = new LinkedHashSet (); - buttons.add (send); - buttons.add (cancel); - - Form f = new Form (Form.Layout.stacked, - items, - buttons); - - content.add (f); - - content.setSize (new Dimension (UIUtils.getPopupWidth () - 20, - content.getPreferredSize ().height)); - content.setBorder (UIUtils.createPadding (10, 10, 10, 10)); - - popup.setContent (content); - - popup.setDraggable (this); - - popup.resize (); - this.viewer.showPopupAt (popup, - UIUtils.getCenterShowPosition (this.viewer, - popup), - false); - - UIUtils.doLater (new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - desc.grabFocus (); - - } - - }); - - } else { - - popup.setVisible (true); - - - } - - } - -} diff --git a/src/com/quollwriter/ui/ProjectViewer.java b/src/com/quollwriter/ui/ProjectViewer.java deleted file mode 100644 index 2627a054..00000000 --- a/src/com/quollwriter/ui/ProjectViewer.java +++ /dev/null @@ -1,3815 +0,0 @@ -package com.quollwriter.ui; - -import java.awt.*; -import java.awt.dnd.*; -import java.awt.event.*; - -import java.io.*; - -import java.net.*; - -import java.security.*; - -import java.text.*; - -import java.util.ArrayList; -import java.util.Date; -import java.util.HashMap; -import java.util.HashSet; -import java.util.TreeSet; -import java.util.Map; -import java.util.Set; -import java.util.StringTokenizer; -import java.util.Iterator; -import java.util.LinkedHashSet; -import java.util.LinkedHashMap; -import java.util.WeakHashMap; -import java.util.Collections; -import java.util.Arrays; - -import javax.swing.*; -import javax.swing.border.*; -import javax.swing.event.*; -import javax.swing.text.*; -import javax.swing.tree.*; - -import com.gentlyweb.properties.*; - -import com.gentlyweb.utils.*; - -import com.jgoodies.forms.builder.*; -import com.jgoodies.forms.factories.*; -import com.jgoodies.forms.layout.*; - -import com.quollwriter.*; - -import com.quollwriter.data.*; - -import com.quollwriter.data.editors.*; -import com.quollwriter.db.*; - -import com.quollwriter.events.*; -import com.quollwriter.data.comparators.*; -import com.quollwriter.text.*; -import com.quollwriter.ui.sidebars.*; -import com.quollwriter.ui.panels.*; - -import com.quollwriter.ui.actionHandlers.*; -import com.quollwriter.ui.components.*; -import com.quollwriter.ui.events.*; -import com.quollwriter.ui.renderers.*; -import com.quollwriter.editors.*; -import com.quollwriter.editors.ui.*; -import com.quollwriter.editors.ui.panels.*; -import com.quollwriter.editors.ui.sidebars.*; - -import com.quollwriter.text.*; - -import static com.quollwriter.LanguageStrings.*; -import static com.quollwriter.Environment.getUIString; - -public class ProjectViewer extends AbstractProjectViewer implements DocumentListener, ProjectEventListener -{ - - public static final String IDEA_BOARD_HEADER_CONTROL_ID = "ideaBoard"; - - public static final String TAB_OBJECT_TYPE = "tab"; - public static final int NEW_CHAPTER_ACTION = 102; // "newChapter"; - public static final int NEW_NOTE_ACTION = 103; // "newNote"; - public static final int VIEW_CHAPTER_INFO_ACTION = 105; // "viewChapterInfo"; - - // public static final int DELETE_CHAPTER_ACTION = 106; - public static final int NEW_BOOK_ACTION = 108; // "newBook"; - public static final int NEW_PLOT_OUTLINE_ITEM_ACTION = 116; // "newPlotOutlineItem"; - public static final int NEW_PLOT_OUTLINE_ITEM_BELOW_ACTION = 117; // "newPlotOutlineItemBelow"; - public static final int DELETE_PLOT_OUTLINE_ITEM_ACTION = 118; // "deletePlotOutlineItem"; - public static final int EDIT_PLOT_OUTLINE_ITEM_ACTION = 119; // "editPlotOutlineItem"; - public static final int DELETE_NOTE_ACTION = 120; // "deleteNote"; - public static final int EDIT_NOTE_ACTION = 121; // "editNote"; - //public static final int NEW_SCENE_ACTION = 122; // "newScene"; - public static final int NEW_SCENE_BELOW_ACTION = 123; // "newSceneBelow"; - public static final int DELETE_SCENE_ACTION = 124; // "deleteScene"; - public static final int EDIT_SCENE_ACTION = 125; // "editScene"; - public static final int MANAGE_NOTE_TYPES_ACTION = 126; // "manageNoteTypes" - public static final int NEW_NOTE_TYPE_ACTION = 127; // "newNoteType" - //public static final int MANAGE_ITEM_TYPES_ACTION = 128; // "manageItemTypes" - //public static final int NEW_ITEM_TYPE_ACTION = 129; // "newItemType" - - private Date sessionStart = new Date (); - private ProjectSideBar sideBar = null; - private ChapterItemViewPopupProvider chapterItemViewPopupProvider = null; - private IconProvider iconProvider = null; - private ImportTransferHandlerOverlay importOverlay = null; - private PropertyChangedListener objectTypePropChangedListener = null; - private PropertyChangedListener noteTypePropChangedListener = null; - private Map chapterDocumentListeners = Collections.synchronizedMap (new WeakHashMap ()); - private static final Object listenerFillObj = new Object (); - private ProblemFinderSideBar problemFinderSideBar = null; - private ProblemFinderRuleConfig problemFinderRuleConfig = null; - - public ProjectViewer () - { - - final ProjectViewer _this = this; - - this.iconProvider = new DefaultIconProvider (); - this.chapterItemViewPopupProvider = new DefaultChapterItemViewPopupProvider (); - - Environment.addUserProjectEventListener (this); - - this.problemFinderRuleConfig = new ProblemFinderRuleConfig (this); - - InputMap im = this.getInputMap (JComponent.WHEN_IN_FOCUSED_WINDOW); - ActionMap actions = this.getActionMap (); - - ProjectViewer.addAssetActionMappings (this, - im, - actions); - - im.put (KeyStroke.getKeyStroke ("ctrl shift H"), - "new" + Chapter.OBJECT_TYPE); - - actions.put ("new" + Chapter.OBJECT_TYPE, - new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - Chapter ch = _this.getChapterCurrentlyEdited (); - - NamedObject o = ch; - - if (ch == null) - { - - // Get the last chapter. - Book b = _this.proj.getBooks ().get (0); - - ch = b.getLastChapter (); - - o = ch; - - if (ch == null) - { - - o = b; - - } - - } - - Action a = _this.getAction (ProjectViewer.NEW_CHAPTER_ACTION, - o); - - if (a != null) - { - - a.actionPerformed (ev); - - } - - } - - }); - - this.sideBar = new ProjectSideBar (this); - - this.importOverlay = new ImportTransferHandlerOverlay (); - - this.importOverlay.addMouseListener (new MouseEventHandler () - { - - public void handlePress (MouseEvent ev) - { - - _this.importOverlay.setVisible (false); - - _this.validate (); - _this.repaint (); - - } - - }); - - /* - * Disabled for now, drag-n-drop importing throws a bizarre exception: - * - * Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException - * at javax.swing.TransferHandler$DropHandler.drop(TransferHandler.java:1521) - * at java.awt.dnd.DropTarget.drop(DropTarget.java:455) - * at javax.swing.TransferHandler$SwingDropTarget.drop(TransferHandler.java:1282) - * at sun.awt.dnd.SunDropTargetContextPeer.processDropMessage(SunDropTargetContextPeer.java:538) - * - * This problem seems to have been introduced in Java8, it definitely worked in Java7, grr... - * - this.setTransferHandler (new ImportTransferHandler (new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.importOverlay.setDisplayText ("Drop the file to begin the import"); - - File f = (File) ev.getSource (); - - QuollPanel qp = _this.getCurrentlyVisibleTab (); - - if (qp instanceof ProjectObjectQuollPanel) - { - - ProjectObjectQuollPanel pqp = (ProjectObjectQuollPanel) qp; - - if (pqp.getForObject () instanceof Asset) - { - - _this.importOverlay.setDisplayText (String.format ("Drop the file to add it to %s's {documents}.", - pqp.getForObject ().getName ())); - - } - - } - - _this.importOverlay.setFile (f); - - _this.setGlassPane (_this.importOverlay); - - _this.importOverlay.setVisible (true); - _this.validate (); - _this.repaint (); - - } - - }, - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.importOverlay.setVisible (false); - _this.validate (); - _this.repaint (); - - File f = (File) ev.getSource (); - - QuollPanel qp = _this.getCurrentlyVisibleTab (); - - if (qp instanceof AssetViewPanel) - { - - AssetViewPanel vp = (AssetViewPanel) qp; - - vp.getObjectDocumentsEditPanel ().addFile (f, - false); - - } else { - - _this.showImportProject (f); - - } - - } - - }, - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.importOverlay.setVisible (false); - _this.validate (); - _this.repaint (); - - } - - }, - new FileFilter () - { - - @Override - public boolean accept (File f) - { - - QuollPanel qp = _this.getCurrentlyVisibleTab (); - - if (qp instanceof ProjectObjectQuollPanel) - { - - ProjectObjectQuollPanel pqp = (ProjectObjectQuollPanel) qp; - - if (pqp.getForObject () instanceof Asset) - { - - return true; - - } - - } - - return ImportProject.isSupportedFileType (f); - - } - - })); - - this.importOverlay.setTransferHandler (this.getTransferHandler ()); - */ - } - - public IconProvider getIconProvider () - { - - return this.iconProvider; - - } - - public ChapterItemViewPopupProvider getChapterItemViewPopupProvider () - { - - return this.chapterItemViewPopupProvider; - - } - - public void initActionMappings (ActionMap am) - { - - final ProjectViewer _this = this; - - super.initActionMappings (am); - - am.put ("ideaboard-show", - new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.viewIdeaBoard (); - - } - - }); - - } - - public void initKeyMappings (InputMap im) - { - - super.initKeyMappings (im); - - im.put (KeyStroke.getKeyStroke (KeyEvent.VK_F2, - 0), - "ideaboard-show"); - - } - - public AbstractSideBar getMainSideBar () - { - - return this.sideBar; - - } -/* - private static Action getAddAssetActionListener (final UserConfigurableObjectType type, - final ProjectViewer pv) - { - - return new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - Asset as = null; - - try - { - - as = Asset.createAsset (type); - - } catch (Exception e) { - - Environment.logError ("Unable to create new asset of type: " + - type, - e); - - UIUtils.showErrorMessage (pv, - String.format ("Unable to create new %s.", - type.getObjectTypeName ())); - - return; - - } - - String addAsset = UserProperties.get (Constants.ADD_ASSETS_PROPERTY_NAME); - - // Should we use a popup? - if (((addAsset.equals ("trypopup")) - && - (type.getNonCoreFieldCount () == 0) - ) - || - (addAsset.equals ("popup")) - ) - { - - AssetActionHandler aah = new AssetActionHandler (as, - pv); - - aah.setPopupOver (pv); - - aah.actionPerformed (ev); - - return; - - } - - pv.showAddAsset (as, - null); - - } - - }; - - } - */ -/* - public TypesHandler getObjectTypesHandler (String objType) - { - - if (objType.equals (Note.OBJECT_TYPE)) - { - - return this.noteTypeHandler; - - } - - if (objType.equals (QObject.OBJECT_TYPE)) - { - - return this.itemTypeHandler; - - } - - return null; - - } - */ - public static void addAssetActionMappings (final PopupsSupported parent, - InputMap im, - ActionMap actions) - { - - ProjectViewer pv = null; - PopupsSupported ps = null; - - if (parent instanceof ProjectViewer) - { - - pv = (ProjectViewer) parent; - - } - - if (parent instanceof QuollPanel) - { - - AbstractViewer v = ((QuollPanel) parent).getViewer (); - - if (v instanceof ProjectViewer) - { - - pv = (ProjectViewer) v; - - } - - } - - if (parent instanceof FullScreenFrame) - { - - // TODO: A little dangerous to do this, fix in future. - pv = (ProjectViewer) ((FullScreenFrame) parent).getProjectViewer (); - - } - - final ProjectViewer ppv = pv; - - Set assetObjTypes = Environment.getAssetUserConfigurableObjectTypes (true); - - for (UserConfigurableObjectType type : assetObjTypes) - { - - if (type.getCreateShortcutKeyStroke () != null) - { - - String id = "newuserobject" + type.getKey (); - - im.put (type.getCreateShortcutKeyStroke (), - id); - actions.put (id, - UIUtils.createAddAssetActionListener (type, - pv, - null, - null)); -/* - ProjectViewer.getAddAssetActionListener (type, - ppv)); -*/ - } - - } - - } - - public void fillFullScreenTitleToolbar (JToolBar toolbar) - { - - final ProjectViewer _this = this; - - toolbar.add (UIUtils.createButton (Constants.IDEA_ICON_NAME, - Constants.ICON_TITLE_ACTION, - getUIString (fullscreen,title, LanguageStrings.toolbar,buttons,ideaboard,tooltip), - //"Click to open the Idea Board", - new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.viewIdeaBoard (); - - } - - })); - - WordCountTimerBox b = new WordCountTimerBox (this.getFullScreenFrame (), - Constants.ICON_FULL_SCREEN_ACTION, - this.getWordCountTimer ()); - - b.setBarHeight (20); - - toolbar.add (b); - - } - - public void fillSettingsPopup (JPopupMenu titlePopup) - { - - final ProjectViewer _this = this; - - java.util.List prefix = Arrays.asList (project,settingsmenu,items); - - JMenuItem mi = null; - - // Open project. - titlePopup.add (this.createMenuItem (getUIString (prefix,openproject), - //"Open {Project}", - Constants.OPEN_PROJECT_ICON_NAME, - ProjectViewer.OPEN_PROJECT_ACTION)); - - titlePopup.add (this.createMenuItem (getUIString (prefix,newproject), - //"New {Project}", - Constants.NEW_ICON_NAME, - ProjectViewer.NEW_PROJECT_ACTION)); - - titlePopup.addSeparator (); - - // Rename project - titlePopup.add (this.createMenuItem (getUIString (prefix,renameproject), - //"Rename this {Project}", - Constants.RENAME_ICON_NAME, - ProjectViewer.RENAME_PROJECT_ACTION)); - - titlePopup.add (this.createMenuItem (getUIString (prefix,statistics), - //"Statistics", - Constants.CHART_ICON_NAME, - AbstractProjectViewer.SHOW_STATISTICS_ACTION)); - - titlePopup.add (this.createMenuItem (getUIString (prefix,targets), - //"Targets", - Constants.TARGET_ICON_NAME, - ProjectViewer.SHOW_TARGETS_ACTION)); - - // Create Project Snapshot - titlePopup.add (this.createMenuItem (getUIString (prefix,createbackup), - //"Create a Backup", - Constants.SNAPSHOT_ICON_NAME, - ProjectViewer.CREATE_PROJECT_SNAPSHOT_ACTION)); - - // Close Project - titlePopup.add (this.createMenuItem (getUIString (prefix,closeproject), - //"Close {Project}", - Constants.CLOSE_ICON_NAME, - ProjectViewer.CLOSE_PROJECT_ACTION)); - - // Delete Project - titlePopup.add (this.createMenuItem (getUIString (prefix,deleteproject), - //"Delete {Project}", - Constants.DELETE_ICON_NAME, - ProjectViewer.DELETE_PROJECT_ACTION)); - - titlePopup.addSeparator (); - - // Idea Board - titlePopup.add (this.createMenuItem (getUIString (prefix,ideaboard), - //"Idea Board", - Constants.IDEA_ICON_NAME, - new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.viewIdeaBoard (); - - } - - })); - - // Do a Warm-up Exercise - titlePopup.add (this.createMenuItem (getUIString (prefix,dowarmup), - //String.format ("Do a {Warmup} Exercise", Warmup.OBJECT_TYPE), - Constants.WARMUPS_ICON_NAME, - AbstractProjectViewer.WARMUP_EXERCISE_ACTION)); - - titlePopup.addSeparator (); - - // Import File - titlePopup.add (this.createMenuItem (Environment.getUIString (prefix, - LanguageStrings.importfileorproject), - //"Import File/{Project}", - Constants.PROJECT_IMPORT_ICON_NAME, - new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.showImportProject (); - - } - - })); - - // Export Project - titlePopup.add (this.createMenuItem (Environment.getUIString (prefix, - LanguageStrings.exportproject), - //String.format ("Export {Project}", Project.OBJECT_TYPE), - Constants.PROJECT_EXPORT_ICON_NAME, - new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.showExportProject (); - - } - - })); - - } - - public void showExportProject () - { - - QPopup popup = UIUtils.createWizardPopup (Environment.getUIString (LanguageStrings.exportproject, - LanguageStrings.popup, - LanguageStrings.title), - //"Export {Project}", - Constants.PROJECT_EXPORT_ICON_NAME, - null, - new ExportProject (this)); - - popup.setDraggable (this); - - popup.resize (); - this.showPopupAt (popup, - UIUtils.getCenterShowPosition (this, - popup), - false); - - } - - public void showImportProject () - { - - this.showImportProject (null); - - } - - public void showImportProject (File f) - { - - this.removeNamedPopup ("import-project"); - - try - { - - ImportProject im = new ImportProject (this); - - if (f != null) - { - - im.setFile (f); - im.setAddToProjectOnly (true); - - } - - QPopup popup = UIUtils.createWizardPopup (Environment.getUIString (LanguageStrings.importproject, - LanguageStrings.popup, - LanguageStrings.title), - //"Import a File or {Project}", - Constants.PROJECT_IMPORT_ICON_NAME, - null, - im); - - popup.setDraggable (this); - - popup.resize (); - this.showPopupAt (popup, - UIUtils.getCenterShowPosition (this, - popup), - false); - - this.addNamedPopup ("import-project", - popup); - - } catch (Exception e) { - - Environment.logError ("Unable to show import project for file: " + - f, - e); - - UIUtils.showErrorMessage (this, - Environment.getUIString (LanguageStrings.importproject, - LanguageStrings.actionerror)); - //"Unable to show import project wizard, please contact Quoll Writer support for assistance."); - - } - - } - - public Action getAction (int name, - final NamedObject other) - { - - Action a = super.getAction (name, - other); - - if (a != null) - { - - return a; - - } - - final ProjectViewer pv = this; - - if (name == ProjectViewer.VIEW_CHAPTER_INFO_ACTION) - { - - return new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - try - { - - pv.viewChapterInformation ((Chapter) other); - - } catch (Exception e) { - - Environment.logError ("Unable to view chapter information for chapter: " + - other, - e); - - UIUtils.showErrorMessage (pv, - Environment.getUIString (LanguageStrings.project, - LanguageStrings.actions, - LanguageStrings.viewchapterinformation, - LanguageStrings.actionerror)); - //"Unable to view chapter information."); - - } - - } - - }; - - } - - if (name == ProjectViewer.NEW_NOTE_TYPE_ACTION) - { - - return new AddNewNoteTypeActionHandler (this); - - } - - if (name == ProjectViewer.MANAGE_NOTE_TYPES_ACTION) - { - - return new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - pv.showEditNoteTypes (); - - } - - }; - - } -/* - if (name == ProjectViewer.MANAGE_ITEM_TYPES_ACTION) - { - - return new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - pv.showEditItemTypes (); - - } - - }; - - } -*/ - if (name == ProjectViewer.NEW_CHAPTER_ACTION) - { - - if (other instanceof Chapter) - { - - Chapter c = (Chapter) other; - - return new AddChapterActionHandler (c.getBook (), - c, - pv); - - } - - if (other instanceof Book) - { - - return new AddChapterActionHandler ((Book) other, - null, - pv); - - } - - } - - if (name == ProjectViewer.EDIT_PLOT_OUTLINE_ITEM_ACTION) - { - - return new ActionAdapter () - { - - public void actionPerformed (final ActionEvent ev) - { - - final Chapter c = ((ChapterItem) other).getChapter (); - - pv.viewObject (c, - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - QuollEditorPanel qep = (QuollEditorPanel) pv.getEditorForChapter (c); - - qep.editOutlineItem ((OutlineItem) other); - - } - - }); - - } - - }; - - } - - if (name == ProjectViewer.EDIT_NOTE_ACTION) - { - - return new ActionAdapter () - { - - public void actionPerformed (final ActionEvent ev) - { - - final Chapter c = ((Note) other).getChapter (); - - pv.viewObject (c, - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - QuollEditorPanel qep = (QuollEditorPanel) pv.getEditorForChapter (c); - - qep.editNote ((Note) other); - - } - - }); - - } - - }; - - } - - if (name == ProjectViewer.EDIT_SCENE_ACTION) - { - - return new ActionAdapter () - { - - public void actionPerformed (final ActionEvent ev) - { - - final Chapter c = ((ChapterItem) other).getChapter (); - - pv.viewObject (c, - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - QuollEditorPanel qep = (QuollEditorPanel) pv.getEditorForChapter (c); - - qep.editScene ((Scene) other); - - } - - }); - - } - - }; - - } - - if (name == ProjectViewer.DELETE_PLOT_OUTLINE_ITEM_ACTION) - { - - return new DeleteChapterItemActionHandler ((OutlineItem) other, - this, - false); - - } - - if (name == ProjectViewer.DELETE_SCENE_ACTION) - { - - return new DeleteChapterItemActionHandler ((Scene) other, - this, - false); - - } - - if (name == ProjectViewer.DELETE_NOTE_ACTION) - { - - return new DeleteChapterItemActionHandler ((Note) other, - this, - false); - - } - - if (name == ProjectViewer.NEW_PLOT_OUTLINE_ITEM_ACTION) - { - - return new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - Chapter c = (Chapter) other; - - QuollEditorPanel qep = (QuollEditorPanel) pv.getEditorForChapter (c); - - String text = qep.getEditor ().getText (); - - int pos = 0; - - if (text != null) - { - - pos = text.length (); - - } - - pv.scrollTo (c, - pos); - - OutlineItem o = new OutlineItem (-1, - c); - - new ChapterItemActionHandler (o, - qep, - AbstractFormPopup.ADD, - pos).actionPerformed (ev); - - } - - }; - - } - - /* - if (name == ProjectViewer.NEW_SCENE_ACTION) - { - - return new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - Chapter c = (Chapter) other; - - QuollEditorPanel qep = (QuollEditorPanel) pv.getEditorForChapter (c); - - String text = qep.getEditor ().getText (); - - int pos = 0; - - if (text != null) - { - - pos = text.length (); - - } - - pv.scrollTo (c, - pos); - - Scene s = new Scene (-1, - c); - - new ChapterItemActionHandler (s, - qep, - AbstractFormPopup.ADD, - pos).actionPerformed (ev); - - } - - }; - - } -*/ - if (name == ProjectViewer.NEW_SCENE_BELOW_ACTION) - { - - return new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - Chapter c = (Chapter) other; - - QuollEditorPanel qep = (QuollEditorPanel) pv.getEditorForChapter (c); - - String text = qep.getEditor ().getText (); - - int pos = 0; - - if (text != null) - { - - pos = text.length (); - - } - - pv.scrollTo (c, - pos); - - Scene s = new Scene (-1, - c); - - new ChapterItemActionHandler (s, - qep, - AbstractFormPopup.ADD, - pos).actionPerformed (ev); - - } - - }; - - } - - if (name == ProjectViewer.NEW_NOTE_ACTION) - { - - return new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - Chapter c = (Chapter) other; - - QuollEditorPanel qep = pv.getEditorForChapter (c); - - String text = qep.getEditor ().getText (); - - int pos = 0; - - if (text != null) - { - - pos = text.length (); - - } - - pv.scrollTo (c, - pos); - - new NoteActionHandler (c, - qep, - pos).actionPerformed (ev); - - } - - }; - - } - - if (name == ProjectViewer.NEW_PLOT_OUTLINE_ITEM_BELOW_ACTION) - { - - Chapter c = (Chapter) other; - - OutlineItem o = new OutlineItem (-1, - c); - - return new ChapterItemActionHandler (o, - this.getEditorForChapter (c), - AbstractFormPopup.ADD, - 0); - - } - - if (name == ProjectViewer.NEW_BOOK_ACTION) - { - - //return UIUtils.getComingSoonAction (pv); - - /* - return new AddBookActionHandler ((Book) other, - pv); - */ - } - - throw new IllegalArgumentException ("Action: " + - name + - " not known."); - - } - - public void handleNewProject () - throws Exception - { - - Book b = this.proj.getBooks ().get (0); - - Chapter c = b.getFirstChapter (); - - // Create a new chapter for the book. - if (c == null) - { - - c = new Chapter (b, - Environment.getDefaultChapterName ()); - - b.addChapter (c); - - } - - this.saveObject (c, - true); - - // Refresh the chapter tree. - this.reloadTreeForObjectType (c.getObjectType ()); - - this.handleOpenProject (); - - this.editChapter (c); - - } - - @Override - public void saveObject (NamedObject o, - boolean doInTransaction) - throws GeneralException - { - - super.saveObject (o, - doInTransaction); - - this.scheduleUpdateAppearsInChaptersTree (); - - } - - public String getViewerIcon () - { - - return Project.OBJECT_TYPE; - - //return this.proj.getObjectType (); - - } - - public String getViewerTitle () - { - - return String.format (getUIString (project,viewertitle), - this.proj.getName ()); - - } - - public void handleHTMLPanelAction (String v) - { - - StringTokenizer t = new StringTokenizer (v, - ",;"); - - if (t.countTokens () > 1) - { - - while (t.hasMoreTokens ()) - { - - String tok = t.nextToken ().trim (); - - this.handleHTMLPanelAction (tok); - - } - - return; - - } - - if (v.equals ("import")) - { - - this.showImportProject (); - - return; - - } - - if (v.equals ("export")) - { - - this.showExportProject (); - - return; - - } - - if (v.equals ("problemfinder")) - { - - QuollPanel qp = this.getCurrentlyVisibleTab (); - - if (qp instanceof QuollEditorPanel) - { - - ((QuollEditorPanel) qp).showProblemFinder (); - - } - - return; - - } - - if (v.equals ("problemfinderconfig")) - { - - this.showProblemFinderRuleConfig (); - - return; - - } - - if (v.equals ("ideaboard")) - { - - this.viewIdeaBoard (); - - return; - - } - - super.handleHTMLPanelAction (v); - - } - - public void handleOpenProject () - { - - //this.initProjectItemBoxes (); - - final ProjectViewer _this = this; - - /** - *TODO: CHECK if needed still - this.objectTypePropChangedListener = new PropertyChangedListener () - { - - @Override - public void propertyChanged (PropertyChangedEvent ev) - { - - if (ev.getChangeType ().equals (UserPropertyHandler.VALUE_CHANGED)) - { - - java.util.List toSave = new ArrayList (); - - java.util.List objs = _this.getProject ().getQObjects (); - - for (QObject o : objs) - { - - if (o.getType ().equals ((String) ev.getOldValue ())) - { - - o.setType ((String) ev.getNewValue ()); - - toSave.add (o); - - } - - if (toSave.size () > 0) - { - - try - { - - _this.saveObjects (toSave, - true); - - } catch (Exception e) - { - - Environment.logError ("Unable to save qobjects: " + - toSave + - " with new type: " + - ev.getNewValue (), - e); - - UIUtils.showErrorMessage (_this, - "Unable to change type"); - - } - - } - - } - - } - - } - - }; - - Environment.getUserPropertyHandler (Constants.OBJECT_TYPES_PROPERTY_NAME).addPropertyChangedListener (this.objectTypePropChangedListener); - */ - - // Called whenever a note type is changed. - this.noteTypePropChangedListener = new PropertyChangedListener () - { - - @Override - public void propertyChanged (PropertyChangedEvent ev) - { - - if (ev.getChangeType ().equals (UserPropertyHandler.VALUE_CHANGED)) - { - - java.util.List toSave = new ArrayList (); - - Set objs = _this.getAllNotes (); - - for (Note o : objs) - { - - if (o.getType ().equals ((String) ev.getOldValue ())) - { - - o.setType ((String) ev.getNewValue ()); - - toSave.add (o); - - } - - if (toSave.size () > 0) - { - - try - { - - _this.saveObjects (toSave, - true); - - } catch (Exception e) - { - - Environment.logError ("Unable to save notes: " + - toSave + - " with new type: " + - ev.getNewValue (), - e); -// TODO: Language string - UIUtils.showErrorMessage (_this, - "Unable to change type"); - - } - - } - - } - - _this.reloadTreeForObjectType (Note.OBJECT_TYPE); - - } - - } - - }; - - Environment.getUserPropertyHandler (Constants.NOTE_TYPES_PROPERTY_NAME).addPropertyChangedListener (this.noteTypePropChangedListener); - - this.scheduleUpdateAppearsInChaptersTree (); - - } - - /* - private void initProjectItemBoxes () - { - - String openTypes = this.proj.getProperty (Constants.ASSETS_TREE_OPEN_TYPES_PROPERTY_NAME); - - Set open = new HashSet (); - - if (openTypes != null) - { - - // Split on : - StringTokenizer t = new StringTokenizer (openTypes, - "|"); - - while (t.hasMoreTokens ()) - { - - String tok = t.nextToken ().trim (); - - open.add (tok); - - } - - } - - this.sideBar.initOpenObjectTypes (open); - - } -*/ - public void handleItemChangedEvent (ItemChangedEvent ev) - { - - Object o = ev.getChangedObject (); - - if (o instanceof DataObject) - { - - if (ev.getChangedObject () instanceof Chapter) - { - - this.reloadTreeForObjectType (((DataObject) o).getObjectType ()); - - } - - } - /* - if (ev.getChangedObject () instanceof Chapter) - { - - this.reloadTreeForObjectType (Chapter.OBJECT_TYPE); - - } - - if (ev.getChangedObject () instanceof Note) - { - - this.reloadTreeForObjectType (Note.OBJECT_TYPE); - - } - */ - } - - public void showObjectInTree (String treeObjType, - NamedObject obj) - { - - this.sideBar.showObjectInTree (treeObjType, - obj); - - } - - public void reloadTreeForObjectType (String objType) - { - - this.sideBar.reloadTreeForObjectType (objType); - - } - - public void reloadTreeForObjectType (NamedObject obj) - { - - this.sideBar.reloadTreeForObjectType (obj.getObjectType ()); - - } - - public void reloadNoteTree () - { - - this.reloadTreeForObjectType (Note.OBJECT_TYPE); - - } - - public void reloadChapterTree () - { - - this.reloadTreeForObjectType (Chapter.OBJECT_TYPE); - - } - - @Override - public void doSaveState () - { - - } - - public QuollEditorPanel getEditorForChapter (Chapter c) - { - - for (QuollPanel qp : this.getAllQuollPanelsForObject (c)) - { - - if (qp instanceof FullScreenQuollPanel) - { - - qp = ((FullScreenQuollPanel) qp).getChild (); - - } - - if (qp instanceof QuollEditorPanel) - { - - return (QuollEditorPanel) qp; - - } - - } - - return null; - - } - - public boolean viewTimeline () - { - - final ProjectViewer _this = this; - - Timeline tp = null; - - try - { - - tp = new Timeline (this); - - tp.init (); - - } catch (Exception e) { - - Environment.logError ("Unable to init timeline", - e); - - UIUtils.showErrorMessage (_this, - "Unable to show timeline"); - - return false; - - } - - final TabHeader th = this.addPanel (tp); - - this.setPanelVisible (tp); - - return true; - - } - - public boolean editChapter (Chapter c) - { - - return this.editChapter (c, - null); - - } - - public boolean closePanel (QuollPanel qp) - { - - if (qp instanceof QuollEditorPanel) - { - - ((QuollEditorPanel) qp).getEditor ().getDocument ().removeDocumentListener (this); - - } - - return super.closePanel (qp); - - } - - @Override - public void insertUpdate (DocumentEvent ev) - { - - this.fireChaperDocumentChangedEvent (ev); - - } - - @Override - public void changedUpdate (DocumentEvent ev) - { - - this.fireChaperDocumentChangedEvent (ev); - - } - - @Override - public void removeUpdate (DocumentEvent ev) - { - - this.fireChaperDocumentChangedEvent (ev); - - } - - /** - * This is a top-level action so it can handle showing the user a message, it returns a boolean to indicate - * whether the chapter has been opened for editing. - */ - public boolean editChapter (final Chapter c, - final ActionListener doAfterView) - { - - // Check our tabs to see if we are already editing this chapter, if so then just switch to it instead. - QuollEditorPanel qep = (QuollEditorPanel) this.getQuollPanelForObject (c); - - if (qep != null) - { - - this.setPanelVisible (qep); - - this.getEditorForChapter (c).getEditor ().grabFocus (); - - this.getEditorForChapter (c).getEditor ().getDocument ().addDocumentListener (this); - - if (doAfterView != null) - { - - UIUtils.doActionWhenPanelIsReady (qep, - doAfterView, - c, - "afterview"); - - } - - return true; - - } - - final ProjectViewer _this = this; - - try - { - - qep = new QuollEditorPanel (this, - c); - - qep.init (); - - } catch (Exception e) - { - - Environment.logError ("Unable to edit chapter: " + - c, - e); - - UIUtils.showErrorMessage (_this, - String.format (Environment.getUIString (LanguageStrings.project, - LanguageStrings.actions, - LanguageStrings.editchapter, - LanguageStrings.actionerror), - c.getName ())); - //"Unable to edit {chapter}: " + - //c.getName ()); - - return false; - - } - - final TabHeader th = this.addPanel (qep); - - qep.addActionListener (new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - if (ev.getID () == QuollPanel.UNSAVED_CHANGES_ACTION_EVENT) - { - - th.setComponentChanged (true); - - } - - } - - }); - - this.addNameChangeListener (c, - qep); - - // Open the tab :) - return this.editChapter (c, - doAfterView); - - } - - public boolean viewObject (DataObject d) - { - - if (d == null) - { - - return false; - - } - - return this.viewObject (d, - null); - - } - - public boolean viewObject (final DataObject d, - final ActionListener doAfterView) - { - - final ProjectViewer _this = this; - - if (d instanceof ChapterItem) - { - - final ChapterItem ci = (ChapterItem) d; - - this.viewObject (ci.getChapter (), - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.getEditorForChapter (ci.getChapter ()).showItem (ci); - - } - - }); - - return true; - - } - - if (d.getObjectType ().equals (StatisticsPanel.OLD_WORD_COUNT_PANEL_ID)) - { - - return this.viewStatistics (); - - } - - if (d instanceof Chapter) - { - - Chapter c = (Chapter) d; - - if (d.getObjectType ().equals (Chapter.INFORMATION_OBJECT_TYPE)) - { - - try - { - - return this.viewChapterInformation (c); - - } catch (Exception e) { - - Environment.logError ("Unable to view chapter information for chapter: " + - c, - e); - - UIUtils.showErrorMessage (_this, - Environment.getUIString (LanguageStrings.project, - LanguageStrings.actions, - LanguageStrings.viewchapterinformation, - LanguageStrings.actionerror)); - //"Unable to show chapter information."); - - } - - } else - { - - return this.editChapter (c, - doAfterView); - - } - - } - - if (d instanceof Asset) - { - - return this.viewAsset ((Asset) d, - doAfterView); - - } -/* - if (d instanceof Note) - { - - this.viewNote ((Note) d); - - return true; - - } - */ -/* - if (d instanceof OutlineItem) - { - - this.viewOutlineItem ((OutlineItem) d); - - return true; - - } -*/ - // Record the error, then ignore. - Environment.logError ("Unable to open object: " + d); - - return false; - - } - /* - public void viewNote (Note n) - { - - try - { - - // Need to change this. - if (n.getObject () instanceof Chapter) - { - - Chapter c = (Chapter) n.getObject (); - - this.editChapter (c); - - QuollEditorPanel qep = this.getEditorForChapter (c); - - qep.showNote (n); - - return; - - } - - } catch (Exception e) - { - - Environment.logError ("Unable to show note: " + - n, - e); - - UIUtils.showErrorMessage (this, - "Unable to show " + Environment.getObjectTypeName (n).toLowerCase () + "."); - - } - - } - */ -/* - public void viewOutlineItem (OutlineItem n) - { - - try - { - - this.editChapter (n.getChapter ()); - - QuollEditorPanel qep = this.getEditorForChapter (n.getChapter ()); - - qep.showOutlineItem (n); - - } catch (Exception e) - { - - Environment.logError ("Unable to show outline item: " + - n, - e); - - UIUtils.showErrorMessage (this, - "Unable to show " + Environment.getObjectTypeName (n).toLowerCase ()); - - } - - } -*/ - public boolean openPanel (String id) - { - - if (id.equals (IdeaBoard.PANEL_ID)) - { - - return this.viewIdeaBoard (); - - } - - if (id.equals (Timeline.PANEL_ID)) - { - - return this.viewTimeline (); - - } - - return false; - - } - - public boolean showAdvertiseProjectPanel () - { - - AdvertiseProjectPanel ap = (AdvertiseProjectPanel) this.getQuollPanel (AdvertiseProjectPanel.PANEL_ID); - - if (ap == null) - { - - try - { - - ap = new AdvertiseProjectPanel (this); - - ap.init (); - - } catch (Exception e) - { - - Environment.logError ("Unable to view the advertise project panel", - e); - - UIUtils.showErrorMessage (this, - "Unable to open panel"); - - return false; - - } - - this.addPanel (ap); - - } - - this.setPanelVisible (ap); - - return true; - - - } -/* - public boolean showRegisterAsAnEditorPanel () - { - - RegisterAsAnEditorPanel ap = (RegisterAsAnEditorPanel) this.getQuollPanel (RegisterAsAnEditorPanel.PANEL_ID); - - if (ap == null) - { - - try - { - - ap = new RegisterAsAnEditorPanel (this); - - ap.init (); - - } catch (Exception e) - { - - Environment.logError ("Unable to view the register as an editor panel", - e); - - UIUtils.showErrorMessage (this, - "Unable to open panel"); - - return false; - - } - - this.addPanel (ap); - - } - - this.setPanelVisible (ap); - - return true; - - - } -*/ - public boolean viewIdeaBoard () - { - - IdeaBoard avp = (IdeaBoard) this.getQuollPanel (IdeaBoard.PANEL_ID); - - if (avp == null) - { - - try - { - - avp = new IdeaBoard (this); - - avp.init (); - - } catch (Exception e) - { - - Environment.logError ("Unable to view idea board", - e); - - UIUtils.showErrorMessage (this, - Environment.getUIString (LanguageStrings.ideaboard, - LanguageStrings.actionerror)); - //"Unable to view idea board"); - - return false; - - } - - this.addPanel (avp); - - } - - this.setPanelVisible (avp); - - return true; - - } - - public boolean viewAsset (Asset a) - { - - return this.viewAsset (a, - null); - - } - - /** - * Add an asset in a tab. - * - * @param a The asset to add, if it already has a key then an exception is thrown. - */ - public void showAddAsset (final Asset a, - final ActionListener doAfterAdd) - { - - if (a.getKey () != null) - { - - throw new IllegalStateException ("Asset already has a key."); - - } - - AddAssetPanel avp = null; - - try - { - - avp = new AddAssetPanel (this, - a); - - avp.init (); - - } catch (Exception e) - { - - Environment.logError ("Unable to add asset: " + - a, - e); - - UIUtils.showErrorMessage (this, - String.format (Environment.getUIString (LanguageStrings.project, - LanguageStrings.actions, - LanguageStrings.viewaddasset, - LanguageStrings.actionerror), - a.getObjectTypeName ())); - //"Unable to add " + - //a.getObjectTypeName ()); - - return; - - } - - this.addPanel (avp); - - this.setPanelVisible (avp); - - if (doAfterAdd != null) - { - - UIUtils.doActionWhenPanelIsReady (avp, - doAfterAdd, - a, - "afterview"); - - } - - } - - public void editAsset (final Asset a, - final ActionListener doAfterEdit) - { - - final ProjectViewer _this = this; - - // Display the object then edit it. - this.viewAsset (a, - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - AssetViewPanel p = (AssetViewPanel) _this.getQuollPanelForObject (a); - - if (p == null) - { - - Environment.logError ("Unable to edit asset: " + - a); - - UIUtils.showErrorMessage (_this, - String.format (Environment.getUIString (LanguageStrings.assets, - LanguageStrings.edit, - LanguageStrings.actionerror), - a.getObjectTypeName (), - a.getName ())); - //Environment.replaceObjectNames (String.format ("Unable to edit %s", - // a.getObjectTypeName ()))); - - return; - - } - - p.editObject (); - - if (doAfterEdit != null) - { - - UIUtils.doLater (doAfterEdit); - - } - - } - - }); - - } - - /** - * This is a top-level action so it can handle showing the user a message, it returns a boolean to indicate - * whether the asset is viewed. - */ - public boolean viewAsset (final Asset a, - final ActionListener doAfterView) - { - - ProjectObjectQuollPanel p = this.getQuollPanelForObject (a); - - if (p != null) - { - - this.setPanelVisible (p); - - if (doAfterView != null) - { - - UIUtils.doActionWhenPanelIsReady (p, - doAfterView, - a, - "afterview"); - - } - - return true; - - } - - final ProjectViewer _this = this; - - AssetViewPanel avp = null; - - try - { - - avp = new AssetViewPanel (this, - a); - - avp.init (); - - } catch (Exception e) - { - - Environment.logError ("Unable to view asset: " + - a, - e); - - UIUtils.showErrorMessage (_this, - String.format (Environment.getUIString (LanguageStrings.assets, - LanguageStrings.view, - LanguageStrings.actionerror), - a.getObjectTypeName (), - a.getName ())); - - return false; - - } - - this.addPanel (avp); - - this.addNameChangeListener (a, - avp); - - // Open the tab :) - return this.viewAsset (a, - doAfterView); - - } - - protected void addNameChangeListener (final NamedObject n, - final ProjectObjectQuollPanel qp) - { - - final ProjectViewer _this = this; - - qp.addObjectPropertyChangedListener (new PropertyChangedListener () - { - - @Override - public void propertyChanged (PropertyChangedEvent ev) - { - - if (ev.getChangeType ().equals (NamedObject.NAME)) - { - - _this.setTabHeaderTitle (qp, - qp.getTitle ()); - - _this.informTreeOfNodeChange (n, - _this.getTreeForObjectType (n.getObjectType ())); - - } - - } - - }); - - } - - public void viewWordCloud () - { - - WordCloudPanel wp = (WordCloudPanel) this.getQuollPanel (WordCloudPanel.PANEL_ID); - - if (wp != null) - { - - this.setPanelVisible (wp); - - return; - - } - - try - { - - wp = new WordCloudPanel (this); - - wp.init (); - - } catch (Exception e) - { - - Environment.logError ("Unable to show word cloud panel", - e); - - UIUtils.showErrorMessage (this, - "Unable to show word cloud panel"); - - return; - - } - - this.addPanel (wp); - - // Open the tab :) - this.viewWordCloud (); - - } - - /** - * This is a top-level action so it can handle showing the user a message, it returns a boolean to indicate - * whether the chapter information is viewed. - */ - public boolean viewChapterInformation (final Chapter c) - throws GeneralException - { - - ChapterInformationSideBar cb = new ChapterInformationSideBar (this, - c); - - this.addSideBar (cb); - - this.showSideBar (cb.getId ()); - - return true; - - } - - public JTree getTreeForObjectType (String objType) - { - - return this.sideBar.getTreeForObjectType (objType); - - } - - public void openObjectSection (Asset a) - { - - this.sideBar.setObjectsOpen (a.getUserConfigurableObjectType ().getObjectTypeId ()); - - } - - public void openObjectSection (String objType) - { - - this.sideBar.setObjectsOpen (objType); - - } - - public void addChapterToTreeAfter (Chapter newChapter, - Chapter addAfter) - { - - DefaultTreeModel model = (DefaultTreeModel) this.getChapterTree ().getModel (); - - DefaultMutableTreeNode cNode = new DefaultMutableTreeNode (newChapter); - - if (addAfter == null) - { - - // Get the book node. - TreePath tp = UIUtils.getTreePathForUserObject ((DefaultMutableTreeNode) model.getRoot (), - newChapter.getBook ()); - - if (tp != null) - { - - DefaultMutableTreeNode node = (DefaultMutableTreeNode) tp.getLastPathComponent (); - - model.insertNodeInto (cNode, - (MutableTreeNode) node, - 0); - - } else - { - - DefaultMutableTreeNode root = (DefaultMutableTreeNode) model.getRoot (); - - model.insertNodeInto (cNode, - root, - root.getChildCount ()); - - } - - } else - { - - // Get the "addAfter" node. - DefaultMutableTreeNode node = (DefaultMutableTreeNode) UIUtils.getTreePathForUserObject ((DefaultMutableTreeNode) model.getRoot (), - addAfter).getLastPathComponent (); - - model.insertNodeInto (cNode, - (MutableTreeNode) node.getParent (), - node.getParent ().getIndex (node) + 1); - - } - - this.getChapterTree ().setSelectionPath (new TreePath (cNode.getPath ())); - - } - - public JTree getNoteTree () - { - - return this.getTreeForObjectType (Note.OBJECT_TYPE); - - } - - public JTree getChapterTree () - { - - return this.getTreeForObjectType (Chapter.OBJECT_TYPE); - - } - - public boolean deleteIdeaType (IdeaType it) - { - - try - { - - this.dBMan.deleteObject (it, - false, - null); - - this.proj.removeObject (it); - - this.fireProjectEvent (it.getObjectType (), - ProjectEvent.DELETE, - it); - - return true; - - } catch (Exception e) - { - - Environment.logError ("Unable to delete idea type: " + it, - e); - - UIUtils.showErrorMessage (this, - Environment.getUIString (LanguageStrings.ideaboard, - LanguageStrings.ideatypes, - LanguageStrings.delete, - LanguageStrings.actionerror)); - //"Unable to delete Idea Type"); - - return false; - - } - - } - - public boolean deleteIdea (Idea i) - { - - try - { - - this.dBMan.deleteObject (i, - false, - null); - - this.fireProjectEvent (i.getObjectType (), - ProjectEvent.DELETE, - i); - - return true; - - } catch (Exception e) - { - - Environment.logError ("Unable to delete idea: " + i, - e); - - UIUtils.showErrorMessage (this, - Environment.getUIString (LanguageStrings.ideaboard, - LanguageStrings.ideas, - LanguageStrings.delete, - LanguageStrings.actionerror)); - //"Unable to delete Idea"); - - return false; - - } - - } - - public boolean updateIdeaType (IdeaType it) - { - - try - { - - this.dBMan.saveObject (it, - null); - - this.fireProjectEvent (it.getObjectType (), - ProjectEvent.EDIT, - it); - - return true; - - } catch (Exception e) - { - - Environment.logError ("Unable to save idea type: " + it, - e); - - UIUtils.showErrorMessage (this, - Environment.getUIString (LanguageStrings.ideaboard, - LanguageStrings.ideatypes, - LanguageStrings.edit, - LanguageStrings.actionerror)); - //"Unable to save Idea Type"); - - return false; - - } - - } - - public void deleteChapter (Chapter c) - { - - try - { - - // Remove the chapter from the book. - java.util.Set otherObjects = c.getOtherObjectsInLinks (); - - this.dBMan.deleteObject (c, - false, - null); - - Book b = c.getBook (); - - b.removeChapter (c); - - this.refreshObjectPanels (otherObjects); - - // See if there is a chapter information sidebar. - this.removeSideBar ("chapterinfo-" + c.getKey ()); - - this.fireProjectEvent (c.getObjectType (), - ProjectEvent.DELETE, - c); - - } catch (Exception e) - { - - Environment.logError ("Unable to delete chapter: " + c, - e); - - UIUtils.showErrorMessage (this, - String.format (Environment.getUIString (LanguageStrings.project, - LanguageStrings.actions, - LanguageStrings.deletechapter, - LanguageStrings.actionerror), - c.getName ())); - //"Unable to delete " + - //Environment.getObjectTypeName (c)); - - return; - - } - - // Inform the chapter tree about the change. - this.reloadTreeForObjectType (c.getObjectType ()); - - this.removeAllSideBarsForObject (c); - - // Remove the tab (if present). - this.removeAllPanelsForObject (c); - - // Notify the note tree about the change. - // We get a copy of the notes here to allow iteration. - Set _notes = new LinkedHashSet (c.getNotes ()); - for (Note n : _notes) - { - - try - { - - this.deleteNote (n, - false); - - } catch (Exception e) - { - - Environment.logError ("Unable to delete note: " + n, - e); - - } - - } - - } - - public void deleteAllAssetsOfType (UserConfigurableObjectType type) - { - - Set assets = this.proj.getAssets (type); - - if (assets == null) - { - - return; - - } - - Set nassets = new LinkedHashSet<> (assets); - - for (Asset a : nassets) - { - - this.deleteAsset (a); - - } - - } - - public void deleteAsset (Asset a) - { - - final ProjectViewer _this = this; - - // Remove the links. - try - { - - // Capture a list of all the object objects in the links, we then need to message - // the linked to panel of any of those. - java.util.Set otherObjects = a.getOtherObjectsInLinks (); - - this.dBMan.deleteObject (a, - false, - null); - - this.proj.removeObject (a); - - this.removeWordFromDictionary (a.getName ()); - //"project"); - //this.removeWordFromDictionary (a.getName () + "'s", - // "project"); - - this.refreshObjectPanels (otherObjects); - - this.fireProjectEvent (a.getObjectType (), - ProjectEvent.DELETE, - a); - - } catch (Exception e) - { - - Environment.logError ("Unable to remove links: " + - a, - e); - - UIUtils.showErrorMessage (this, - String.format (Environment.getUIString (LanguageStrings.assets, - LanguageStrings.delete, - LanguageStrings.actionerror), - a.getObjectTypeName (), - a.getName ())); - //"Unable to remove " + Environment.getObjectTypeName (a)); - - return; - - } - - this.reloadTreeForObjectType (a.getObjectType ()); - - this.removeAllSideBarsForObject (a); - - this.removePanel (a); - - } - - public void addNewIdeaType (IdeaType it) - throws GeneralException - { - - this.dBMan.saveObject (it, - null); - - this.fireProjectEvent (it.getObjectType (), - ProjectEvent.NEW, - it); - - } - - public void addNewIdea (Idea i) - throws GeneralException - { - - this.dBMan.saveObject (i, - null); - - i.getType ().addIdea (i); - - this.fireProjectEvent (i.getObjectType (), - ProjectEvent.NEW, - i); - - } - - public void deleteOutlineItem (OutlineItem it, - boolean doInTransaction) - throws GeneralException - { - - java.util.Set otherObjects = it.getOtherObjectsInLinks (); - - // Get the editor panel for the item. - Chapter c = it.getChapter (); - - this.dBMan.deleteObject (it, - false, - null); - - c.removeOutlineItem (it); - - this.fireProjectEvent (it.getObjectType (), - ProjectEvent.DELETE, - it); - - if (it.getScene () != null) - { - - it.getScene ().removeOutlineItem (it); - - } - - this.refreshObjectPanels (otherObjects); - - QuollEditorPanel qep = this.getEditorForChapter (c); - - if (qep != null) - { - - qep.removeItem (it); - - } - - this.reloadChapterTree (); - - } - - public void deleteObject (NamedObject o, - boolean deleteChildObjects) - throws GeneralException - { - - if (o instanceof ChapterItem) - { - - this.deleteChapterItem ((ChapterItem) o, - deleteChildObjects, - true); - - return; - - } - - this.deleteObject (o); - - } - - public void deleteObject (NamedObject o) - throws GeneralException - { - - if (o instanceof Asset) - { - - this.deleteAsset ((Asset) o); - - } - - if (o instanceof Chapter) - { - - this.deleteChapter ((Chapter) o); - - } - - if (o instanceof ChapterItem) - { - - this.deleteChapterItem ((ChapterItem) o, - true, - true); - - } - - } - - public void deleteChapterItem (ChapterItem ci, - boolean deleteChildObjects, - boolean doInTransaction) - throws GeneralException - { - - if (ci.getObjectType ().equals (Scene.OBJECT_TYPE)) - { - - this.deleteScene ((Scene) ci, - deleteChildObjects, - doInTransaction); - - } - - if (ci.getObjectType ().equals (OutlineItem.OBJECT_TYPE)) - { - - this.deleteOutlineItem ((OutlineItem) ci, - doInTransaction); - - } - - if (ci.getObjectType ().equals (Note.OBJECT_TYPE)) - { - - this.deleteNote ((Note) ci, - doInTransaction); - - } - - } - - public void deleteScene (Scene s, - boolean deleteOutlineItems, - boolean doInTransaction) - throws GeneralException - { - - java.util.Set otherObjects = s.getOtherObjectsInLinks (); - - java.util.List outlineItems = new ArrayList (s.getOutlineItems ()); - - // Get the editor panel for the item. - Chapter c = s.getChapter (); - - this.dBMan.deleteObject (s, - deleteOutlineItems, - null); - - c.removeScene (s); - - this.fireProjectEvent (s.getObjectType (), - ProjectEvent.DELETE, - s); - - this.refreshObjectPanels (otherObjects); - - QuollEditorPanel qep = this.getEditorForChapter (c); - - if (qep != null) - { - - for (OutlineItem oi : outlineItems) - { - - if (deleteOutlineItems) - { - - qep.removeItem (oi); - - } else { - - // Add the item back into the chapter. - c.addChapterItem (oi); - - } - - } - - qep.removeItem (s); - - } - - this.reloadChapterTree (); - - } - - public void reloadAssetTree (Asset a) - { - - this.reloadTreeForObjectType (a.getObjectType ()); - - } - - public void deleteNote (Note n, - boolean doInTransaction) - throws GeneralException - { - - java.util.Set otherObjects = n.getOtherObjectsInLinks (); - - NamedObject obj = n.getObject (); - - // Need to get the links, they may not be setup. - this.setLinks (n); - - this.dBMan.deleteObject (n, - false, - null); - - obj.removeNote (n); - - this.fireProjectEvent (n.getObjectType (), - ProjectEvent.DELETE, - n); - - this.refreshObjectPanels (otherObjects); - - if (obj instanceof Chapter) - { - - QuollEditorPanel qep = this.getEditorForChapter ((Chapter) obj); - - if (qep != null) - { - - qep.removeItem (n); - - } - - } - - this.reloadNoteTree (); - - this.reloadChapterTree (); - - } - - public JTree getAssetTree (Asset a) - { - - return this.getTreeForObjectType (a.getObjectType ()); - - } - /* - public void addToAssetTree (Asset a) - { - - DefaultTreeModel model = (DefaultTreeModel) this.getAssetTree (a).getModel (); - - DefaultMutableTreeNode node = (DefaultMutableTreeNode) model.getRoot (); - - int ind = 0; - - // Now work out where it should go. - en = node.children (); - - while (en.hasMoreElements ()) - { - - DefaultMutableTreeNode ccNode = en.nextElement (); - - Asset ast = (Asset) ccNode.getUserObject (); - - if (a.getName ().toLowerCase ().compareTo (ast.getName ().toLowerCase ()) < 0) - { - - break; - - } - - ind++; - - } - - this.sideBar.reloadTreeForObjectType (a.getObjectType ()); - - this.getAssetTree (a).setSelectionPath (new TreePath (cNode.getPath ())); - - } -*/ - public void chapterTreeChanged (DataObject d) - { - - DefaultTreeModel model = (DefaultTreeModel) this.getChapterTree ().getModel (); - - DefaultMutableTreeNode node = (DefaultMutableTreeNode) UIUtils.getTreePathForUserObject ((DefaultMutableTreeNode) model.getRoot (), - d).getLastPathComponent (); - - model.nodeStructureChanged (node); - - } - - public Set getNotesForType (String t) - { - - Set notes = this.getAllNotes (); - - Set ret = new TreeSet (new ChapterItemSorter ()); - - for (Note n : notes) - { - - if (n.getType ().equals (t)) - { - - ret.add (n); - - } - - } - - return ret; - - } - - public Set getAllNotes () - { - - Set notes = new HashSet (); - - Book b = this.proj.getBooks ().get (0); - - java.util.List chapters = b.getChapters (); - - for (Chapter c : chapters) - { - - notes.addAll (c.getNotes ()); - - } - - return notes; - - } - - @Override - public String getChapterObjectName () - { - - return getUIString (objectnames,plural, Chapter.OBJECT_TYPE); - - } - - public void updateChapterIndexes (Book b) - throws GeneralException - { - - this.dBMan.updateChapterIndexes (b); - - } - - public void saveProblemFinderIgnores (Chapter c) - throws GeneralException - { - - ChapterDataHandler dh = (ChapterDataHandler) this.getDataHandler (Chapter.class); - - dh.saveProblemFinderIgnores (c, - null); - - } - - public Set getProblemFinderIgnores (Rule r) - throws GeneralException - { - - Set ignores = new HashSet (); - - for (Chapter c : this.getProject ().getBook (0).getChapters ()) - { - - Set ignored = c.getProblemFinderIgnores (); - - for (Issue i : ignored) - { - - if (i.getRuleId ().equals (r.getId ())) - { - - ignores.add (i); - - } - - } - - } - - return ignores; - - } - - @Override - public Set findText (String t) - { - - Set res = new LinkedHashSet (); - - // Get the snippets. - Map> snippets = this.getTextSnippets (t); - - if (snippets.size () > 0) - { - - res.add (new ChapterFindResultsBox (getUIString (objectnames,plural, Chapter.OBJECT_TYPE), - Chapter.OBJECT_TYPE, - Chapter.OBJECT_TYPE, - this, - snippets)); - - } - - Set types = Environment.getAssetUserConfigurableObjectTypes (true); - - for (UserConfigurableObjectType type : types) - { - - Set objs = this.proj.getAssetsContaining (t, - type); - - if (objs.size () > 0) - { - - res.add (new AssetFindResultsBox (type, - this, - objs)); - - } - - } - - Set notes = this.proj.getNotesContaining (t); - - if (notes.size () > 0) - { - - res.add (new NamedObjectFindResultsBox (getUIString (objectnames,plural, Note.OBJECT_TYPE), - Note.OBJECT_TYPE, - Note.OBJECT_TYPE, - this, - notes)); - - } - - Set oitems = this.proj.getOutlineItemsContaining (t); - - if (oitems.size () > 0) - { - - res.add (new NamedObjectFindResultsBox (getUIString (objectnames,plural, OutlineItem.OBJECT_TYPE), - OutlineItem.OBJECT_TYPE, - OutlineItem.OBJECT_TYPE, - this, - oitems)); - - } - - Set scenes = this.proj.getScenesContaining (t); - - if (scenes.size () > 0) - { - - res.add (new NamedObjectFindResultsBox (getUIString (objectnames,plural, Scene.OBJECT_TYPE), - Scene.OBJECT_TYPE, - Scene.OBJECT_TYPE, - this, - scenes)); - - } - - return res; - - } - - @Override - public Set getTitleHeaderControlIds () - { - - Set ids = new LinkedHashSet (); - - //ids.add ("wordcloud"); - - ids.add (IDEA_BOARD_HEADER_CONTROL_ID); - - ids.addAll (super.getTitleHeaderControlIds ()); - - return ids; - - } - - @Override - public JComponent getTitleHeaderControl (String id) - { - - if (id == null) - { - - return null; - - } - - final ProjectViewer _this = this; - - JComponent c = null; -/* - if (id.equals ("wordcloud")) - { - - return UIUtils.createButton (Constants.IDEA_ICON_NAME, - Constants.ICON_TITLE_ACTION, - "Click to open the Idea Board", - new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.viewWordCloud (); - - } - - }); - - } -*/ - if (id.equals (IDEA_BOARD_HEADER_CONTROL_ID)) - { - - return UIUtils.createButton (Constants.IDEA_ICON_NAME, - Constants.ICON_TITLE_ACTION, - Environment.getUIString (LanguageStrings.project, - LanguageStrings.title, - LanguageStrings.toolbar, - LanguageStrings.buttons, - LanguageStrings.ideaboard, - LanguageStrings.tooltip), - //"Click to open the Idea Board", - new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.viewIdeaBoard (); - - } - - }); - - } - - return super.getTitleHeaderControl (id); - - } - - public Set getNoteTypes () - { - - Set notes = this.getAllNotes (); - - Set types = new TreeSet (); - - for (Note nn : notes) - { - - types.add (nn.getType ()); - - } - - return types; - - } - - public Map> getNotesAgainstTypes () - { - - // The implementation here is pretty inefficient but we can get away with it due to the generally - // low number of types and notes. - - // Might be worthwhile putting a josql wrapper around this for the grouping. - - Map> ret = new LinkedHashMap (); - - Set notes = this.getAllNotes (); - - Set types = this.getNoteTypes (); - - for (String type : types) - { - - for (Note n : notes) - { - - String t = n.getType (); - - if (t.equals (type)) - { - - Set retNotes = ret.get (t); - - if (retNotes == null) - { - - retNotes = new TreeSet (new ChapterItemSorter ()); - - ret.put (t, - retNotes); - - } - - retNotes.add (n); - - } - - } - - } - - return ret; - - } - - private void scheduleUpdateAppearsInChaptersTree () - { - - final ProjectViewer _this = this; - - this.schedule (new Runnable () - { - - @Override - public void run () - { - - try - { - - _this.doForSideBars (AppearsInChaptersSideBar.class, - new QuollSideBarAction () - { - - public void doAction (final AppearsInChaptersSideBar sb) - { - - final NamedObject n = sb.getForObject (); - - try - { - - final Map> snippets = UIUtils.getObjectSnippets (n, - _this); - - UIUtils.doLater (new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - try - { - - sb.updateSnippets (snippets); - - } catch (Exception e) { - - Environment.logError ("Unable to update appears in chapters sidebar for object: " + - n, - e); - - } - - } - - }); - - } catch (Exception e) { - - Environment.logError ("Unable to update appears in chapters sidebar for object: " + - n, - e); - - } - - } - - }); - - _this.doForPanels (AssetViewPanel.class, - new QuollPanelAction () - { - - public void doAction (final AssetViewPanel vp) - { - - final NamedObject n = vp.getForObject (); - - final AppearsInChaptersEditPanel p = vp.getAppearsInChaptersEditPanel (); - - try - { - - final Map> snippets = UIUtils.getObjectSnippets (n, - _this); - - UIUtils.doLater (new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - try - { - - p.updateChapterTree (snippets); - - } catch (Exception e) { - - Environment.logError ("Unable to update appears in chapters tree(2) for object: " + - n, - e); - - } - - } - - }); - - } catch (Exception e) { - - Environment.logError ("Unable to update appears in chapters tree for object: " + - n, - e); - - } - - } - - }, - false); - - } catch (Exception e) { - - Environment.logError ("Unable to update sidebars/panels", - e); - - } - - } - - }, - // Start in 5s. - 1000, //5 * 1000, - // Run every 30s. - -1); //30 * 1000); - - } - - private void fireChaperDocumentChangedEvent (final DocumentEvent dev) - { - - final ProjectViewer _this = this; - - UIUtils.doActionLater (new ActionListener () - { - - public void actionPerformed (ActionEvent aev) - { - - Set ls = null; - - // Get a copy of the current valid listeners. - synchronized (_this.chapterDocumentListeners) - { - - ls = new LinkedHashSet (_this.chapterDocumentListeners.keySet ()); - - } - - for (DocumentListener l : ls) - { - - // Is this the right way to do this? - // TODO: Find a better way - if (dev.getType () == DocumentEvent.EventType.INSERT) - { - - l.insertUpdate (dev); - - } - - if (dev.getType () == DocumentEvent.EventType.CHANGE) - { - - l.changedUpdate (dev); - - } - - if (dev.getType () == DocumentEvent.EventType.REMOVE) - { - - l.removeUpdate (dev); - - } - - } - - } - - }); - - } - - public void removeChapterDocumentListener (DocumentListener l) - { - - this.chapterDocumentListeners.remove (l); - - } - - /** - * This provides a mechanism for classes to listen to document events from the chapter editors - * without having to explicitly add/remove themselves from the document. This class listens - * for events and will fire to registered listeners. A weak map is used so that listeners - * can fall out of scope without having to worry about removing themselves as listeners (but they - * should if they can to prevent possible leaks). - * - * @param l The listener. - */ - public void addChapterDocumentListener (DocumentListener l) - { - - this.chapterDocumentListeners.put (l, - ProjectViewer.listenerFillObj); - - } - - public ProblemFinderSideBar getProblemFinderSideBar () - { - - return this.problemFinderSideBar; - - } - - public void showProblemFinderRuleSideBar (Rule rule) - { - - try - { - - if (this.problemFinderSideBar == null) - { - - this.problemFinderSideBar = new ProblemFinderSideBar (this, - rule); - - this.addSideBar (this.problemFinderSideBar); - - } else { - - this.problemFinderSideBar.setRule (rule); - - } - - this.showSideBar (ProblemFinderSideBar.ID); - - } catch (Exception e) { - - Environment.logError ("Unable to create/init problem finder sidebar for rule: " + - rule, - e); - - UIUtils.showErrorMessage (this, - Environment.getUIString (LanguageStrings.project, - LanguageStrings.actions, - LanguageStrings.viewproblemfindersidebar, - LanguageStrings.actionerror)); - //"Unable to show problem finder sidebar."); - - } - - } - - public ProblemFinderRuleConfig getProblemFinderRuleConfig () - { - - return this.problemFinderRuleConfig; - - } - - public void showProblemFinderRuleConfig () - { - - String popupName = "problemfinderruleconfig"; - QPopup popup = this.getNamedPopup (popupName); - - if (popup == null) - { - - popup = UIUtils.createClosablePopup (Environment.getUIString (LanguageStrings.problemfinder, - LanguageStrings.config, - LanguageStrings.popup, - LanguageStrings.title), - //"Configure the Problem Finder rules", - Environment.getIcon (Constants.CONFIG_ICON_NAME, - Constants.ICON_POPUP), - null); - - popup.setPopupName (popupName); - - this.addNamedPopup (popupName, - popup); - - this.problemFinderRuleConfig.init (); - - this.problemFinderRuleConfig.setSize (new Dimension (UIUtils.getPopupWidth () - 20, - this.problemFinderRuleConfig.getPreferredSize ().height)); - this.problemFinderRuleConfig.setBorder (UIUtils.createPadding (10, 10, 10, 10)); - - popup.setContent (this.problemFinderRuleConfig); - - popup.setDraggable (this); - - popup.resize (); - this.showPopupAt (popup, - UIUtils.getCenterShowPosition (this, - popup), - false); - - } else { - - popup.setVisible (true); - - } - - this.fireProjectEvent (ProjectEvent.PROBLEM_FINDER_RULE_CONFIG, - ProjectEvent.SHOW); - - } - - public void showUserConfigurableObjectType (UserConfigurableObjectType type) - { - - this.sideBar.addAccordionItem (this.sideBar.createAssetAccordionItem (type)); - - } - - @Override - public void eventOccurred (ProjectEvent ev) - { - - if (ev.getType ().equals (ProjectEvent.TAG)) - { - - if (ev.getAction ().equals (ProjectEvent.DELETE)) - { - - Tag tag = (Tag) ev.getSource (); - - this.removeTag (tag); - - } - - } - - if (ev.getType ().equals (ProjectEvent.USER_OBJECT_TYPE)) - { - - UserConfigurableObjectType type = (UserConfigurableObjectType) ev.getSource (); - - if (ev.getAction ().equals (ProjectEvent.NEW)) - { - - this.sideBar.addAccordionItem (this.sideBar.createAssetAccordionItem (type)); - - return; - - } - - if (ev.getAction ().equals (ProjectEvent.DELETE)) - { - - // Removing an object type. - // Remove it from the project sidebar. - // Remove any tabs for objects of that type. - this.sideBar.removeSection (type); - - if (type.isAssetObjectType ()) - { - - this.removeAssetsOfType (type); - - } - - } - - } - - } - - private void removeAssetsOfType (UserConfigurableObjectType type) - { - - Set assets = this.proj.getAssets (type); - - if (assets == null) - { - - return; - - } - - assets = new HashSet (assets); - - for (Asset a : assets) - { - - this.deleteAsset (a); - - } - - } - - /** - * Remove the specified tag from all objects in this project. - * - * @param tag The tag. - */ - public void removeTag (Tag tag) - { - - try - { - - // Get all objects with the tag, remove the tag. - Set objs = this.proj.getAllObjectsWithTag (tag); - - for (NamedObject o : objs) - { - - o.removeTag (tag); - - } - - this.saveObjects (new ArrayList (objs), - true); - - this.sideBar.removeTagSection (tag); - - } catch (Exception e) { - - Environment.logError ("Unable to remove tag: " + - tag, - e); - - UIUtils.showErrorMessage (this, - Environment.getUIString (LanguageStrings.project, - LanguageStrings.actions, - LanguageStrings.removetag, - LanguageStrings.actionerror)); - //"Unable to remove tag."); - - } - - } - -} diff --git a/src/com/quollwriter/ui/QuollPanel.java b/src/com/quollwriter/ui/QuollPanel.java deleted file mode 100644 index 584cce28..00000000 --- a/src/com/quollwriter/ui/QuollPanel.java +++ /dev/null @@ -1,735 +0,0 @@ -package com.quollwriter.ui; - -import java.awt.*; -import java.awt.event.*; - -import java.io.*; - -import java.text.*; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -import javax.swing.plaf.LayerUI; -import javax.swing.*; -import javax.swing.border.*; -import javax.swing.event.*; - -import com.gentlyweb.properties.*; - -import com.jgoodies.forms.builder.*; -import com.jgoodies.forms.factories.*; -import com.jgoodies.forms.layout.*; - -import com.quollwriter.*; - -import com.quollwriter.data.*; - -import com.quollwriter.events.*; - -import com.quollwriter.ui.actionHandlers.*; - -public abstract class QuollPanel extends JRootPane implements Stateful, - PopupsSupported -{ - - public static final int UNSAVED_CHANGES_ACTION_EVENT = 0; - - //public static final int SAVED = 1; - - //public static final String HAS_CHANGES_COMMAND = "hasChanges"; - //public static final String NO_CHANGES_COMMAND = "noChanges"; - - protected E viewer = null; - - protected Box content = null; - private java.util.List actionListeners = new ArrayList (); - private JToolBar toolBar = null; - private boolean readyForUse = false; - private MouseEventHandler mouseEventHandler = null; - - public QuollPanel (E viewer) - { - - this.viewer = viewer; - - this.setOpaque (false); - this.setBackground (null); - - this.content = new Box (BoxLayout.Y_AXIS); - this.content.setBackground (UIUtils.getComponentColor ()); - - this.getContentPane ().setBackground (UIUtils.getComponentColor ()); - - this.getContentPane ().add (this.content); - - final QuollPanel _this = this; - - this.mouseEventHandler = this.getDefaultMouseEventHandler (); - - this.getContentPane ().add (new JLayer (this.content, new LayerUI () - { - - @Override - public void installUI(JComponent c) { - super.installUI(c); - // enable mouse motion events for the layer's subcomponents - ((JLayer) c).setLayerEventMask(AWTEvent.MOUSE_EVENT_MASK|AWTEvent.MOUSE_MOTION_EVENT_MASK); - } - - @Override - public void uninstallUI(JComponent c) { - super.uninstallUI(c); - // reset the layer event mask - ((JLayer) c).setLayerEventMask(0); - } - - @Override - public void processMouseEvent (MouseEvent ev, - JLayer l) - { - - if (_this.mouseEventHandler == null) - { - - return; - - } - - if (ev.getID () == MouseEvent.MOUSE_MOVED) - { - - _this.mouseEventHandler.mouseMoved (ev); - - return; - - } - - if (ev.getID () == MouseEvent.MOUSE_RELEASED) - { - - _this.mouseEventHandler.mouseReleased (ev); - - return; - - } - - if (ev.getID () == MouseEvent.MOUSE_PRESSED) - { - - _this.mouseEventHandler.mousePressed (ev); - - return; - - } - - if (ev.getID () == MouseEvent.MOUSE_DRAGGED) - { - - _this.mouseEventHandler.mousePressed (ev); - - return; - - } - - if (ev.getID () == MouseEvent.MOUSE_ENTERED) - { - - _this.mouseEventHandler.mouseEntered (ev); - - return; - - } - - if (ev.getID () == MouseEvent.MOUSE_EXITED) - { - - _this.mouseEventHandler.mouseExited (ev); - - return; - - } - - if (ev.getID () == MouseEvent.MOUSE_CLICKED) - { - - _this.mouseEventHandler.mouseClicked (ev); - - return; - - } - - } - - })); - - } - - /** - * Set a mouse event handler for the panel, mouse events are forwarded to the handler - * which should makes it's own checks to determine what event should be handled. - * - * Set to null to prevent the default behavior which is to fill the popup menu. - * - * @param m The mouse event handler. - */ - public void setMouseEventHandler (MouseEventHandler m) - { - - this.mouseEventHandler = m; - - } - - /** - * Get the current mouse event handler. - * - * @return The current mouse event handler. - */ - public MouseEventHandler getMouseEventHandler () - { - - return this.mouseEventHandler; - - } - - /** - * Creates a default mouse event handler that just fills the popup menu for the panel by calling - * this.fillPopupMenu. - * - * @return A default mouse event handler. - */ - public MouseEventHandler getDefaultMouseEventHandler () - { - - final QuollPanel _this = this; - - return new MouseEventHandler () - { - - @Override - public void fillPopup (JPopupMenu m, - MouseEvent ev) - { - - _this.fillPopupMenu (ev, - m); - - } - - }; - - } - - public E getViewer () - { - - return this.viewer; - - } - - public boolean isReadyForUse () - { - - return this.readyForUse; - - } - - public void setReadyForUse (boolean v) - { - - this.readyForUse = true; - - } - - public abstract String getPanelId (); - - public abstract void close (); - - public abstract void init () - throws GeneralException; - - public abstract void getState (Map s); - - public abstract void setState (Map s, - boolean hasFocus); - - public abstract ImageIcon getIcon (int type); - - //public abstract String getIconType (); - - public abstract String getTitle (); - - public abstract void fillToolBar (JToolBar toolBar, - boolean fullScreen); - - public abstract void fillPopupMenu (MouseEvent ev, - JPopupMenu popup); - - public abstract List getTopLevelComponents (); - - //public abstract void refresh (T n); - - @Override - public void remove (Component c) - { - - this.content.remove (c); - - } - - @Override - public Component add (Component c) - { - - if (this.content == null) - { - - super.add (c); - - return c; - - } - - if (c instanceof JComponent) - { - - ((JComponent) c).setAlignmentX (Component.LEFT_ALIGNMENT); - - } - - this.content.add (c); - - return c; - - } - - @Override - public Component add (Component c, - int index) - { - - if (this.content == null) - { - - super.add (c, - index); - - return c; - - } - - if (c instanceof JComponent) - { - - ((JComponent) c).setAlignmentX (Component.LEFT_ALIGNMENT); - - } - - // Add to the content box. - this.content.add (c, - index); - - return c; - - } - - public void performAction (ActionEvent ev) - { - - Action aa = (Action) this.getActionMap ().get (ev.getActionCommand ()); - - if (aa != null) - { - - aa.actionPerformed (ev); - - } - - } - - public void removeActionListener (ActionListener a) - { - - this.actionListeners.remove (a); - - } - - public void addActionListener (ActionListener a) - { - - this.actionListeners.add (a); - - } - - protected void fireActionEvent (ActionEvent ev) - { - - for (int i = 0; i < this.actionListeners.size (); i++) - { - - ActionListener a = (ActionListener) this.actionListeners.get (i); - - a.actionPerformed (ev); - - } - - } - - private JToolBar createToolBar () - { - - JToolBar t = new JToolBar (); - t.setFloatable (false); - t.setOpaque (false); - t.setRollover (true); - t.setAlignmentX (Component.LEFT_ALIGNMENT); - - return t; - - } - - public JToolBar getToolBar (boolean fullScreen) - { - - JToolBar tb = this.createToolBar (); - - this.fillToolBar (tb, - fullScreen); - - this.toolBar = tb; - - return tb; - - } - - public void setToolBarButtonIcon (String actionCommand, - String toolTipText, - String icon) - { - - AbstractButton ab = this.getToolBarButton (actionCommand); - - if (ab == null) - { - - return; - - } - - ab.setToolTipText (toolTipText); - - ab.setIcon (Environment.getIcon (icon, - Constants.ICON_TOOLBAR)); /* was false */ - - this.toolBar.repaint (); - - } - - public AbstractButton getToolBarButton (String actionCommand) - { - - Component[] comps = this.toolBar.getComponents (); - - for (int i = 0; i < comps.length; i++) - { - - Component c = comps[i]; - - if (c instanceof AbstractButton) - { - - AbstractButton ab = (AbstractButton) c; - - if ((ab.getActionCommand () != null) && - (ab.getActionCommand ().equals (actionCommand))) - { - - return ab; - - } - - } - - } - - return null; - - } - - @Override - public void removePopup (Component c) - { - - c.setVisible (false); - - this.getLayeredPane ().remove (c); - - this.getLayeredPane ().validate (); - - this.getLayeredPane ().repaint (); - - // this.content.remove (c); - - // this.content.repaint (); - - } - - public void addPopup (Component c, - boolean hideOnParentClick) - { - - this.addPopup (c, - hideOnParentClick, - false); - - } - - @Override - public void showPopupAt (Component popup, - Component showAt, - boolean hideOnParentClick) - { - - Point po = SwingUtilities.convertPoint (showAt, - 0, - 0, - this.getContentPane ()); - - this.showPopupAt (popup, - po, - hideOnParentClick); - - - } - - @Override - public void showPopupAt (Component c, - Point p, - boolean hideOnParentClick) - { - - Insets ins = this.getInsets (); - - if ((c.getParent () == null) - && - (c.getParent () != this.getLayeredPane ()) - ) - { - - this.addPopup (c, - hideOnParentClick, - false); - - } - - Dimension cp = c.getPreferredSize (); - - if ((p.y + cp.height) > (this.getBounds ().height - ins.top - ins.bottom)) - { - - p = new Point (p.x, - p.y); - - p.y = p.y - (cp.height - c.getBounds ().height); - - } - - if (p.y < 0) - { - - p = new Point (p.x, - p.y); - - p.y = 10; - - } - - if ((p.x + cp.width) > (this.getBounds ().width - ins.left - ins.right)) - { - - p = new Point (p.x, - p.y); - - p.x = p.x - cp.width; - - } - - if (p.x < 0) - { - - p = new Point (p.x, - p.y); - - p.x = 10; - - } - - c.setBounds (p.x, - p.y, - c.getPreferredSize ().width, - c.getPreferredSize ().height); - - c.setVisible (true); - this.validate (); - this.repaint (); - - } - - public void showPopupAt (Component c, - Point p, - String where, - boolean hideOnParentClick) - { - - this.showPopupAt (c, - new Rectangle (p, - c.getPreferredSize ()), - where, - hideOnParentClick); - - } - - public void showPopupAt (Component c, - Rectangle r, - String where, - boolean hideOnParentClick) - { - - Dimension s = c.getPreferredSize (); - - int x = r.x; - int y = r.y; - - if (where == null) - { - - where = "below"; - - } - - if (where.equals ("below")) - { - - y = y + r.height; - - } - - if (where.equals ("above")) - { - - y = y - s.height; - - } - - if (y < 0) - { - - y = r.y + r.height; - - } - - if ((x + s.width) > (this.getWidth ())) - { - - x = this.getWidth () - 20 - s.width; - - } - - if (x < 0) - { - - x = 5; - - } - - this.showPopupAt (c, - new Point (x, - y), - hideOnParentClick); - - } - - @Override - public void addPopup (final Component c, - boolean hideOnClick, - boolean hideViaVisibility) - { - - if (c.getParent () != null) - { - - c.getParent ().remove (c); - - } - - this.getLayeredPane ().add (c, - JLayeredPane.POPUP_LAYER); - - this.getLayeredPane ().moveToFront (c); - - if (hideOnClick) - { - - final QuollPanel _this = this; - final boolean hideVia = hideViaVisibility; - - // Need to do it this way because mouse events aren't being forwarded/delivered. - MouseEventHandler m = new MouseEventHandler () - { - - @Override - public void mouseReleased (MouseEvent ev) - { - - c.setVisible (false); - - if (hideVia) - { - - c.setVisible (false); - - } else - { - - _this.removePopup (c); - - List comps = _this.getTopLevelComponents (); - - if (comps != null) - { - - for (int i = 0; i < comps.size (); i++) - { - - comps.get (i).removeMouseListener (this); - - } - - } - - } - - } - - }; - - List comps = this.getTopLevelComponents (); - - if (comps != null) - { - - for (int i = 0; i < comps.size (); i++) - { - - comps.get (i).addMouseListener (m); - - } - - } - - } - - } - -} diff --git a/src/com/quollwriter/ui/Tips.java b/src/com/quollwriter/ui/Tips.java deleted file mode 100644 index caa51ff2..00000000 --- a/src/com/quollwriter/ui/Tips.java +++ /dev/null @@ -1,339 +0,0 @@ -package com.quollwriter.ui; - -import java.util.*; - -import org.jdom.*; - -import com.gentlyweb.xml.*; - -import com.quollwriter.*; -import com.quollwriter.ui.panels.*; -import com.quollwriter.data.*; - -public class Tips -{ - - public class XMLConstants - { - - public static final String tip = "tip"; - public static final String id = "id"; - - } - - private List baseTips = new ArrayList (); - private List tips = new ArrayList (); - private Random ind = new Random (); - private int lastInd = 0; - private AbstractViewer viewer = null; - - public Tips (AbstractViewer viewer) - throws Exception - { - - this.viewer = viewer; - - String tipsXML = Environment.getResourceFileAsString (Constants.TIPS_FILE); - - Element root = JDOMUtils.getStringAsElement (tipsXML); - - List tipEls = JDOMUtils.getChildElements (root, - XMLConstants.tip, - false); - - for (int i = 0; i < tipEls.size (); i++) - { - - Element el = (Element) tipEls.get (i); - - this.baseTips.add (new Tip (el)); - - } - - this.tips = new ArrayList (this.baseTips); - - } - - public String getNextTip () - { - - if (this.tips.size () == 0) - { - - this.tips = new ArrayList (this.baseTips); - - } - - int n = this.ind.nextInt (this.tips.size ()); - - if ((n == this.lastInd) - && - (this.tips.size () > 1) - ) - { - - return this.getNextTip (); - - } - - this.lastInd = n; - - Tip t = this.tips.remove (n); - - // See if there is a condition. - String text = t.getText (this.viewer); - - if (text == null) - { - - return this.getNextTip (); - - } - - return text; - - } - - private class Tip - { - - public class XMLConstants - { - - public static final String id = "id"; - public static final String item = "item"; - - } - - private List items = new ArrayList (); - - public Tip (Element root) - throws JDOMException - { - - String id = JDOMUtils.getAttributeValue (root, - XMLConstants.id); - - List els = JDOMUtils.getChildElements (root, - XMLConstants.item, - false); - - for (int i = 0; i < els.size (); i++) - { - - Element el = (Element) els.get (i); - - this.items.add (new Item (id, - el)); - - } - - } - - public String getText (AbstractViewer viewer) - { - - for (Item it : this.items) - { - - if (it.shouldShow (viewer)) - { - - return it.getText (); - - } - - } - - return null; - - } - - private class Item - { - - public class XMLConstants - { - - public static final String id = "id"; - public static final String condition = "condition"; - - } - - private List conds = new ArrayList (); - private String text = null; - - public Item (String tipId, - Element root) - throws JDOMException - { - - String id = tipId; - - String iid = JDOMUtils.getAttributeValue (root, - XMLConstants.id, - false); - - if (!iid.equals ("")) - { - - id = tipId + "_" + iid; - - } - - String cs = JDOMUtils.getAttributeValue (root, - XMLConstants.condition, - false); - - if (!cs.equals ("")) - { - - StringTokenizer t = new StringTokenizer (cs, - ",;"); - - while (t.hasMoreTokens ()) - { - - this.conds.add (t.nextToken ().trim ().toLowerCase ()); - - } - - } - - this.text = Environment.getUIString (LanguageStrings.tips, - id); - - if (this.text == null) - { - - throw new JDOMException ("Unable to find language string for tip/item: " + - id); - - } - //JDOMUtils.getChildContent (root); - - } - - public String getText () - { - - return this.text; - - } - - public boolean shouldShow (AbstractViewer viewer) - { - - for (String c : this.conds) - { - - boolean not = c.startsWith ("!"); - - if (not) - { - - c = c.substring (1); - - } - - boolean v = false; - - if (c.equals ("landingviewer")) - { - - v = (viewer instanceof Landing); - - } - - if (c.equals ("projectviewer")) - { - - v = (viewer instanceof ProjectViewer); - - } - - if (c.equals ("warmupsviewer")) - { - - v = (viewer instanceof WarmupsViewer); - - } - - if (viewer instanceof AbstractProjectViewer) - { - - AbstractProjectViewer pv = (AbstractProjectViewer) viewer; - - QuollPanel qp = pv.getCurrentlyVisibleTab (); - - if (qp != null) - { - - if ((c.equals ("chaptertab")) - && - (qp instanceof ProjectObjectQuollPanel) - ) - { - - v = (((ProjectObjectQuollPanel) qp).getForObject () instanceof Chapter); - - } - - if (c.equals ("ideaboard")) - { - - v = qp.getPanelId ().equals (IdeaBoard.PANEL_ID); - - } - - } - - if (c.equals ("spellcheckon")) - { - - v = pv.isSpellCheckingEnabled (); - - } - - if (c.equals ("spellcheckoff")) - { - - v = !pv.isSpellCheckingEnabled (); - - } - - } - - if (v) - { - - if (not) - { - - return false; - - } - - } else { - - if (!not) - { - - return false; - - } - - - } - - } - - return true; - - } - - } - - } - -} diff --git a/src/com/quollwriter/ui/TreeParentNode.java b/src/com/quollwriter/ui/TreeParentNode.java deleted file mode 100644 index 8e3bc2e9..00000000 --- a/src/com/quollwriter/ui/TreeParentNode.java +++ /dev/null @@ -1,122 +0,0 @@ -package com.quollwriter.ui; - -import java.util.*; - -import com.quollwriter.data.*; - -import org.jdom.*; - - -public class TreeParentNode extends NamedObject -{ - - public static final String OBJECT_TYPE = "treeparentnode"; - - private String forObjectType = null; - private int count = -1; - - public TreeParentNode (String objType, - String name) - { - - this (objType, - name, - -1); - - } - - public TreeParentNode(String objType, - String name, - int count) - { - - super (TreeParentNode.OBJECT_TYPE + "_" + objType); - - this.forObjectType = objType; - - this.setKey ((long) name.toLowerCase ().hashCode ()); - - this.setName (name); - - this.count = count; - - } - - public void setCount (int c) - { - - this.count = c; - - } - - public int getCount () - { - - return this.count; - - } - - public void getChanges (NamedObject old, - Element root) - { - - } - - public int hashCode () - { - - int hash = 7; - hash = (31 * hash) + this.forObjectType.hashCode (); - hash = (31 * hash) + this.getName ().toLowerCase ().hashCode (); - - return hash; - - } - - public String getForObjectType () - { - - return this.forObjectType; - - } - - public boolean equals (Object o) - { - - if ((o == null) || (!(o instanceof TreeParentNode))) - { - - - return false; - - } - - TreeParentNode n = (TreeParentNode) o; - - if ((n.getName ().equalsIgnoreCase (this.getName ())) && - (n.forObjectType.equals (this.forObjectType))) - { - - return true; - - } - - return false; - - } - - public String toString () - { - - return TreeParentNode.OBJECT_TYPE + "(for: " + this.forObjectType + ", type: " + this.getName () + ")"; - - } - - public Set getAllNamedChildObjects () - { - - return new HashSet (); - - } - -} diff --git a/src/com/quollwriter/ui/UIUtils.java b/src/com/quollwriter/ui/UIUtils.java deleted file mode 100644 index 1a3f2314..00000000 --- a/src/com/quollwriter/ui/UIUtils.java +++ /dev/null @@ -1,11416 +0,0 @@ -package com.quollwriter.ui; - -import java.awt.Color; -import java.awt.Component; -import java.awt.Container; -import java.awt.Cursor; -import java.awt.Desktop; -import java.awt.Dialog; -import java.awt.Dimension; -import java.awt.Font; -import java.awt.Frame; -import java.awt.GraphicsEnvironment; -import java.awt.Insets; -import java.awt.KeyboardFocusManager; -import java.awt.Toolkit; -import java.awt.Window; -import java.awt.Graphics2D; -import java.awt.RenderingHints; -import java.awt.Graphics; -import java.awt.Point; -import java.awt.Image; -import java.awt.image.BufferedImage; -import java.awt.Rectangle; -import java.awt.GraphicsDevice; -import java.awt.GraphicsConfiguration; -import java.awt.FontMetrics; -import java.awt.datatransfer.*; -import java.awt.event.*; -import java.awt.font.*; -import java.awt.image.*; -import java.beans.*; -import javax.swing.plaf.basic.*; - -import java.util.concurrent.atomic.*; - -import java.net.*; - -import java.io.*; - -import java.text.*; - -import java.util.*; -import java.util.regex.*; - -import javax.swing.*; -import javax.swing.border.*; -import javax.swing.event.*; -import javax.swing.text.*; -import javax.swing.text.html.*; -import javax.swing.tree.*; -import javax.swing.table.*; -import javax.swing.filechooser.*; - -import javax.imageio.*; -import javax.activation.*; - -//import javafx.scene.*; -import javafx.scene.web.*; -import javafx.scene.layout.BorderPane; -import javafx.application.*; -import javafx.embed.swing.*; - -import com.gentlyweb.utils.StringUtils; - -import org.imgscalr.Scalr; - -import com.jgoodies.forms.builder.*; -import com.jgoodies.forms.factories.*; -import com.jgoodies.forms.layout.*; - -import org.josql.*; - -import com.quollwriter.*; - -import com.quollwriter.data.*; -import com.quollwriter.data.comparators.*; - -import com.quollwriter.events.*; - -import com.quollwriter.ui.actionHandlers.*; -import com.quollwriter.ui.components.*; -import com.quollwriter.ui.renderers.*; -import com.quollwriter.ui.events.*; -import com.quollwriter.ui.panels.*; -import com.quollwriter.ui.sidebars.*; -import com.quollwriter.ui.userobjects.*; -import com.quollwriter.editors.messages.*; -import com.quollwriter.editors.*; -import com.quollwriter.synonyms.*; -import com.quollwriter.db.*; -import com.quollwriter.ui.forms.Form; -import com.quollwriter.ui.forms.FormItem; - -import com.quollwriter.text.*; - -import org.jfree.chart.*; -import org.jfree.chart.axis.*; -import org.jfree.chart.labels.*; -import org.jfree.chart.plot.*; -import org.jfree.chart.renderer.xy.*; - -import org.jfree.data.time.*; - -import org.jfree.ui.*; - -import org.josql.utils.*; - -import static com.quollwriter.LanguageStrings.*; -import static com.quollwriter.Environment.getUIString; - -public class UIUtils -{ - - private static int DEFAULT_ASSUMED_SCREEN_RESOLUTION = 96; - private static int DEFAULT_POPUP_WIDTH = 450; - public static int DEFAULT_SCROLL_BY_AMOUNT = 20; - - public static final Point defaultLeftCornerShowPopupAt = new Point (10, 10); - - private static final QTextEditor wordCountPerPageEditor = new QTextEditor (null, - false); - - // Deliberately null so that the center of the window is found when the popup is shown. - public static final Point defaultCenterShowPopupAt = null; - - public static Font headerFont = null; - - public static final Border textFieldSpacing = new EmptyBorder (3, - 3, - 3, - 3); - - public static final FileNameExtensionFilter imageFileFilter = new FileNameExtensionFilter ("Image files: jpg, png, gif", - "jpg", - "jpeg", - "gif", - "png"); - - public static int getScrollByAmount () - { - - return DEFAULT_SCROLL_BY_AMOUNT; - - } - - public static int getScreenScaledWidth (int w) - { - - return Math.round ((float) w * ((float) java.awt.Toolkit.getDefaultToolkit ().getScreenResolution () / (float) DEFAULT_ASSUMED_SCREEN_RESOLUTION)); - - } - - public static int getPopupWidth () - { - - return UIUtils.getScreenScaledWidth (DEFAULT_POPUP_WIDTH); - - } - - public static Object getUserObjectForTreePath (TreePath p) - { - - if (p == null) - { - - return null; - - } - - Object[] objs = p.getPath (); - - DefaultMutableTreeNode n = (DefaultMutableTreeNode) objs[objs.length -1]; - - return n.getUserObject (); - - } - - public static TreePath getTreePathForUserObjects (DefaultMutableTreeNode node, - TreePath p) - { - - Object[] objs = p.getPath (); - - for (int i = 0; i < objs.length; i++) - { - - DefaultMutableTreeNode n = (DefaultMutableTreeNode) objs[i]; - - Object nObj = n.getUserObject (); - - TreePath tp = UIUtils.getTreePathForUserObject (node, - nObj); - - if (tp == null) - { - - continue; - - } else { - - if (i == objs.length - 1) - { - - return tp; - - } - - } - - node = (DefaultMutableTreeNode) tp.getPath ()[tp.getPath ().length - 1]; - - } - - return null; - - } - - public static TreePath getTreePathForUserObject (DefaultMutableTreeNode node, - Object o) - { - - Object nObj = node.getUserObject (); - - if (nObj instanceof SelectableDataObject) - { - - nObj = ((SelectableDataObject) nObj).obj; - - } - - if (nObj instanceof DataObject) - { - - if (nObj.equals (o)) - { - - return new TreePath (node.getPath ()); - - } - - } - - if ((nObj instanceof Segment) - && - (o instanceof Segment) - ) - { - - if (nObj.toString ().equals (o.toString ())) - { - - return new TreePath (node.getPath ()); - - } - - } - - if (nObj.equals (o)) - { - - return new TreePath (node.getPath ()); - - } - - if (nObj == o) - { - - return new TreePath (node.getPath ()); - - } - - Enumeration en = node.children (); - - while (en.hasMoreElements ()) - { - - node = (DefaultMutableTreeNode) en.nextElement (); - - TreePath tp = UIUtils.getTreePathForUserObject (node, - o); - - if (tp != null) - { - - return tp; - - } - - } - - return null; - - } - - public static void createTree (Collection items, - DefaultMutableTreeNode parent) - { - - Iterator iter = items.iterator (); - - while (iter.hasNext ()) - { - - Object v = iter.next (); - - if (v instanceof Map) - { - - UIUtils.createTree ((Map) v, - parent); - - continue; - - } - - if (v instanceof Collection) - { - - UIUtils.createTree ((Collection) v, - parent); - - continue; - - } - - DefaultMutableTreeNode n = new DefaultMutableTreeNode (v); - - parent.add (n); - - } - - } - - public static void createTree (Map items, - DefaultMutableTreeNode parent) - { - - Iterator iter = items.entrySet ().iterator (); - - while (iter.hasNext ()) - { - - Map.Entry item = (Map.Entry) iter.next (); - - Object k = item.getKey (); - - Object v = item.getValue (); - - // Add a node for the key. - DefaultMutableTreeNode key = new DefaultMutableTreeNode (k); - - parent.add (key); - - if (v instanceof Map) - { - - UIUtils.createTree ((Map) v, - key); - - } - - if (v instanceof Collection) - { - - UIUtils.createTree ((Collection) v, - key); - - } - - } - - } - - public static DefaultMutableTreeNode createAssetTree (UserConfigurableObjectType objType, - Project p) - { - - return UIUtils.createAssetTree (objType, - p, - new Comparator () - { - - @Override - public boolean equals (Object o) - { - - return this == o; - - } - - @Override - public int compare (Asset o1, - Asset o2) - { - - return NamedObjectSorter.getInstance ().compare (o1, o2); - - } - - }); - - } - - public static DefaultMutableTreeNode createAssetTree (UserConfigurableObjectType objType, - Project p, - Comparator sorter) - { - - List objs = new ArrayList (); - - Set assets = p.getAssets (objType); - - if (assets != null) - { - - objs.addAll (assets); - - } - - DefaultMutableTreeNode root = new DefaultMutableTreeNode (p); - - Collections.sort (objs, - sorter); - - for (NamedObject obj : objs) - { - - root.add (new DefaultMutableTreeNode (obj)); - - } - - return root; - - } -/* - public static DefaultMutableTreeNode createLocationsTree (Project p) - { - - DefaultMutableTreeNode root = new DefaultMutableTreeNode (p); - - Collections.sort (p.getLocations (), - new NamedObjectSorter ()); - - for (Location ll : p.getLocations ()) - { - - root.add (new DefaultMutableTreeNode (ll)); - - } - - return root; - - } - */ -/* - public static DefaultMutableTreeNode createAssetsTree (Project p) - { - - DefaultMutableTreeNode root = new DefaultMutableTreeNode (p); - - TreeParentNode c = new TreeParentNode (QCharacter.OBJECT_TYPE, - Environment.getObjectTypeNamePlural (QCharacter.OBJECT_TYPE)); - - DefaultMutableTreeNode tn = new DefaultMutableTreeNode (c); - - root.add (tn); - - Collections.sort (p.getCharacters (), - new NamedObjectSorter ()); - - for (int i = 0; i < p.getCharacters ().size (); i++) - { - - tn.add (new DefaultMutableTreeNode (p.getCharacters ().get (i))); - - } - - TreeParentNode l = new TreeParentNode (Location.OBJECT_TYPE, - Environment.getObjectTypeNamePlural (Location.OBJECT_TYPE)); - - tn = new DefaultMutableTreeNode (l); - - Collections.sort (p.getLocations (), - new NamedObjectSorter ()); - - for (Location ll : p.getLocations ()) - { - - tn.add (new DefaultMutableTreeNode (ll)); - - } - - root.add (tn); - - TreeParentNode o = new TreeParentNode (QObject.OBJECT_TYPE, - Environment.getObjectTypeNamePlural (QObject.OBJECT_TYPE)); - - tn = new DefaultMutableTreeNode (o); - - Collections.sort (p.getQObjects (), - new NamedObjectSorter ()); - - for (QObject oo : p.getQObjects ()) - { - - tn.add (new DefaultMutableTreeNode (oo)); - - } - - root.add (tn); - - TreeParentNode r = new TreeParentNode (ResearchItem.OBJECT_TYPE, - Environment.getObjectTypeNamePlural (ResearchItem.OBJECT_TYPE)); - - tn = new DefaultMutableTreeNode (r); - - Collections.sort (p.getResearchItems (), - NamedObjectSorter.getInstance ()); - - for (ResearchItem rr : p.getResearchItems ()) - { - - tn.add (new DefaultMutableTreeNode (rr)); - - } - - root.add (tn); - - return root; - - } -*/ - public static void getSelectedObjects (DefaultMutableTreeNode n, - NamedObject addTo, - Set s) - throws GeneralException - { - - Enumeration en = n.children (); - - while (en.hasMoreElements ()) - { - - DefaultMutableTreeNode nn = en.nextElement (); - - SelectableDataObject sd = (SelectableDataObject) nn.getUserObject (); - - if (sd.selected) - { - - s.add (new Link (addTo, - sd.obj)); - - } - - UIUtils.getSelectedObjects (nn, - addTo, - s); - - } - - } - - public static void initTable (JTable t) - { - - t.setAlignmentX (Component.LEFT_ALIGNMENT); - t.setOpaque (false); - t.setFillsViewportHeight (true); - t.setShowVerticalLines (false); - t.setRowHeight (24); - t.setBorder (null); - - t.setDefaultRenderer (Object.class, - new DefaultTableCellRenderer () - { - - @Override - public Component getTableCellRendererComponent (JTable t, - Object value, - boolean isSelected, - boolean hasFocus, - int row, - int column) - { - - super.getTableCellRendererComponent (t, - value, - isSelected, - hasFocus, - row, - column); - - this.setBorder (UIUtils.createPadding (0, 3, 0, 3)); - - return this; - - } - - }); - - } - - public static JTable createTable () - { - - JTable t = new JTable (); - - UIUtils.initTable (t); - - return t; - - } - - public static JTree createSelectableTree () - { - - final JTree tree = UIUtils.createTree (); - - tree.setCellRenderer (new SelectableProjectTreeCellRenderer ()); - - tree.setOpaque (false); - tree.setBorder (null); - tree.setBorder (UIUtils.createPadding (5, 5, 5, 5)); - - tree.setRootVisible (false); - tree.setShowsRootHandles (true); - tree.setScrollsOnExpand (true); - - tree.addMouseListener (new MouseEventHandler () - { - - private void selectAllChildren (DefaultTreeModel model, - DefaultMutableTreeNode n, - boolean v) - { - - Enumeration en = n.children (); - - while (en.hasMoreElements ()) - { - - DefaultMutableTreeNode c = en.nextElement (); - - SelectableDataObject s = (SelectableDataObject) c.getUserObject (); - - s.selected = v; - - // Tell the model that something has changed. - model.nodeChanged (c); - - // Iterate. - this.selectAllChildren (model, - c, - v); - - } - - } - - @Override - public void handlePress (MouseEvent ev) - { - - TreePath tp = tree.getPathForLocation (ev.getX (), - ev.getY ()); - - if (tp != null) - { - - DefaultMutableTreeNode n = (DefaultMutableTreeNode) tp.getLastPathComponent (); - - // Tell the model that something has changed. - DefaultTreeModel model = (DefaultTreeModel) tree.getModel (); - - SelectableDataObject s = (SelectableDataObject) n.getUserObject (); - - s.selected = !s.selected; - - model.nodeChanged (n); - - this.selectAllChildren (model, - n, - s.selected); - - } - - } - - }); - - tree.putClientProperty (com.jgoodies.looks.Options.TREE_LINE_STYLE_KEY, - com.jgoodies.looks.Options.TREE_LINE_STYLE_NONE_VALUE); - - tree.putClientProperty ("Tree.paintLines", - Boolean.FALSE); - - return tree; - - } - - public static JTree createLinkedToTree (final AbstractProjectViewer projectViewer, - final NamedObject dataObject, - boolean editMode) - { - - final JTree tree = UIUtils.createTree (); - - if (editMode) - { - - tree.setCellRenderer (new SelectableProjectTreeCellRenderer ()); - - } else - { - - tree.setCellRenderer (new ProjectTreeCellRenderer (true)); - - } - - tree.setOpaque (true); - tree.setBorder (null); - - tree.setRootVisible (false); - tree.setShowsRootHandles (true); - tree.setScrollsOnExpand (true); - - if (editMode) - { - - // Never toggle. - // tree.setToggleClickCount (-1); - - tree.addMouseListener (new MouseEventHandler () - { - - private void selectAllChildren (DefaultTreeModel model, - DefaultMutableTreeNode n, - boolean v) - { - - Enumeration en = n.children (); - - while (en.hasMoreElements ()) - { - - DefaultMutableTreeNode c = en.nextElement (); - - SelectableDataObject s = (SelectableDataObject) c.getUserObject (); - - s.selected = v; - - // Tell the model that something has changed. - model.nodeChanged (c); - - // Iterate. - this.selectAllChildren (model, - c, - v); - - } - - } - - @Override - public void handlePress (MouseEvent ev) - { - - TreePath tp = tree.getPathForLocation (ev.getX (), - ev.getY ()); - - if (tp != null) - { - - DefaultMutableTreeNode n = (DefaultMutableTreeNode) tp.getLastPathComponent (); - - // Tell the model that something has changed. - DefaultTreeModel model = (DefaultTreeModel) tree.getModel (); - - SelectableDataObject s = (SelectableDataObject) n.getUserObject (); - - /* - if ((ev.getClickCount () == 2) - && - (n.getChildCount () > 0) - ) - { - - this.selectAllChildren (model, - n, - s.selected); - - } else { - - s.selected = !s.selected; - - } - */ - s.selected = !s.selected; - - model.nodeChanged (n); - - } - - } - - }); - - } else - { - - tree.addMouseListener (new MouseEventHandler () - { - - @Override - public void handleDoublePress (MouseEvent ev) - { - - TreePath tp = tree.getPathForLocation (ev.getX (), - ev.getY ()); - - if (tp != null) - { - - DefaultMutableTreeNode n = (DefaultMutableTreeNode) tp.getLastPathComponent (); - - if ((n.getChildCount () == 0) && - (ev.getClickCount () == 2)) - { - - projectViewer.viewObject ((DataObject) n.getUserObject ()); - - } - - } - - } - - }); - - } - - tree.putClientProperty (com.jgoodies.looks.Options.TREE_LINE_STYLE_KEY, - com.jgoodies.looks.Options.TREE_LINE_STYLE_NONE_VALUE); - - tree.putClientProperty ("Tree.paintLines", - Boolean.FALSE); - - tree.setModel (UIUtils.getLinkedToTreeModel (projectViewer, - dataObject, - editMode)); - - UIUtils.expandPathsForLinkedOtherObjects (tree, - dataObject); - - return tree; - - } - - public static void scrollIntoView (final JComponent c) - { - - Environment.scrollIntoView (c); - - } - - public static void expandPathsForLinkedOtherObjects (JTree tree, - NamedObject d) - { - - DefaultMutableTreeNode root = (DefaultMutableTreeNode) ((DefaultTreeModel) tree.getModel ()).getRoot (); - - for (Link l : d.getLinks ()) - { - - // Get the path for the object. - TreePath tp = UIUtils.getTreePathForUserObject (root, - l.getOtherObject (d)); - - if (tp != null) - { - - tree.expandPath (tp.getParentPath ()); - - } - - } - - } - - public static DefaultTreeModel getLinkedToTreeModel (AbstractProjectViewer projectViewer, - NamedObject dataObject, - boolean editMode) - { - - List exclude = new ArrayList (); - exclude.add (dataObject); - - // Painful but just about the only way. - projectViewer.setLinks (dataObject); - - // Get all the "other objects" for the links the note has. - Iterator it = dataObject.getLinks ().iterator (); - - Set links = new HashSet (); - - while (it.hasNext ()) - { - - links.add (it.next ().getOtherObject (dataObject)); - - } - - return new DefaultTreeModel (UIUtils.createLinkToTree (projectViewer.getProject (), - exclude, - links, - editMode)); - - } - - public static Box createLinkedToItemsBox (final NamedObject obj, - final AbstractProjectViewer pv, - final QPopup p, - boolean addTitle) - { - - Box pa = new Box (BoxLayout.Y_AXIS); - pa.setOpaque (false); - - if (addTitle) - { - - JLabel h = UIUtils.createLabel (getUIString (linkedto,view,title)); - //"Linked to"); - pa.add (h); - pa.add (Box.createVerticalStrut (3)); - - } - - Set sl = obj.getOtherObjectsInLinks (); - - Iterator liter = sl.iterator (); - - while (liter.hasNext ()) - { - - final NamedObject other = liter.next (); - - JLabel l = new JLabel (other.getName ()); - l.setOpaque (false); - l.setIcon (Environment.getIcon (other.getObjectType (), - Constants.ICON_MENU)); - l.setToolTipText (getUIString (viewitem,tooltip)); - //"Click to view the item"); - l.setCursor (Cursor.getPredefinedCursor (Cursor.HAND_CURSOR)); - l.setForeground (Color.BLUE); - l.setBorder (new EmptyBorder (0, - 5, - 0, - 0)); - - l.setAlignmentX (Component.LEFT_ALIGNMENT); - - pa.add (l); - pa.add (Box.createVerticalStrut (3)); - - l.addMouseListener (new MouseEventHandler () - { - - @Override - public void handlePress (MouseEvent ev) - { - - // Prevents the popup from disappearing. - pv.viewObject (other); - - if (p != null) - { - - // Close the popup. - p.setVisible (false); - - } - - } - - }); - - } - - pa.setPreferredSize (new Dimension (380, - pa.getPreferredSize ().height)); - - return pa; - - } - - public static QPopup createClosablePopup (final String title, - final Icon icon, - final ActionListener onClose, - final Component content, - final AbstractViewer viewer, - Point showAt) - { - - final QPopup ep = UIUtils.createClosablePopup (title, - icon, - onClose); - - Box b = new Box (BoxLayout.Y_AXIS); - - b.setBorder (UIUtils.createPadding (10, 10, 10, 10)); - - b.add (content); - - ep.setContent (b); - - b.setPreferredSize (new Dimension (UIUtils.getPopupWidth (), - b.getPreferredSize ().height)); - - if (showAt == null) - { - - showAt = UIUtils.getCenterShowPosition (viewer, - ep); - - } - - viewer.showPopupAt (ep, - showAt, - false); - ep.setDraggable (viewer); - - return ep; - - } - - public static QPopup createClosablePopup (final String title, - final Icon icon, - final ActionListener onClose) - { - - final QPopup qp = new QPopup (Environment.replaceObjectNames (title), - icon, - null) - { - - public void setVisible (boolean v) - { - - if ((!v) - && - (onClose != null) - ) - { - - onClose.actionPerformed (new ActionEvent (this, - 0, - "closing")); - - } - - super.setVisible (v); - - } - - }; - - JButton close = UIUtils.createButton (Constants.CLOSE_ICON_NAME, - Constants.ICON_MENU, - getUIString (actions,clicktoclose), - //"Click to close", - new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - qp.removeFromParent (); - - } - - }); - - List buts = new ArrayList (); - buts.add (close); - - qp.getHeader ().setControls (UIUtils.createButtonBar (buts)); - - return qp; - - } - - public static DefaultMutableTreeNode createChapterNotesNode (Chapter c) - { - - if (!UserProperties.getAsBoolean (Constants.SHOW_NOTES_IN_CHAPTER_LIST_PROPERTY_NAME)) - { - - return null; - - } - - Set notes = c.getNotes (); - - if ((notes == null) - || - (notes.size () == 0) - ) - { - - return null; - - } - - TreeParentNode nullN = new TreeParentNode (Note.OBJECT_TYPE, - getUIString (objectnames,plural, Note.OBJECT_TYPE), - //Environment.replaceObjectNames ("{Notes}"), - notes.size ()); - - DefaultMutableTreeNode root = new DefaultMutableTreeNode (nullN); - - for (Note n : c.getNotes ()) - { - - DefaultMutableTreeNode node = UIUtils.createTreeNode (n, - null, - null, - false); - - if (node == null) - { - - continue; - - } - - root.add (node); - - } - - if ((c.getNotes () == null) - || - (c.getNotes ().size () == 0) - ) - { - - return null; - - } - - return root; - - } - - public static DefaultMutableTreeNode createNoteTree (ProjectViewer pv) - { - - DefaultMutableTreeNode root = new DefaultMutableTreeNode (pv.getProject ()); - - Map> typeNotes = pv.getNotesAgainstTypes (); - - Map noteNodes = new HashMap (); - - TreeParentNode nullN = new TreeParentNode (Note.OBJECT_TYPE, - "No Type"); - - DefaultMutableTreeNode nullNode = new DefaultMutableTreeNode (nullN); - - noteNodes.put (null, - nullNode); - - Set types = typeNotes.keySet (); - - for (String type : types) - { - - boolean added = false; - - Set notes = typeNotes.get (type); - - for (Note n : notes) - { - - String t = n.getType (); - - DefaultMutableTreeNode noteNode = null; - - if ((t == null) || - (t.equals (""))) - { - - noteNode = noteNodes.get (null); - - } else - { - - if (t.equals (type)) - { - - if (!added) - { - - added = true; - - TreeParentNode b = new TreeParentNode (Note.OBJECT_TYPE, - type, - notes.size ()); - //noteTypeHandler.getObjectsForType (t).size ()); - - DefaultMutableTreeNode tn = new DefaultMutableTreeNode (b); - - root.add (tn); - - noteNodes.put (type, - tn); - - } - - noteNode = noteNodes.get (t); - - } - - } - - if (noteNode != null) - { - - DefaultMutableTreeNode nn = new DefaultMutableTreeNode (n); - - noteNode.add (nn); - - } - - } - - } - - if (nullNode.getChildCount () > 0) - { - - // Insert at the top. - root.insert (nullNode, - 0); - - } - - return root; - - } - - public static JRadioButton createRadioButton (String text) - { - - return UIUtils.createRadioButton (text, - null); - - } - - public static JRadioButton createRadioButton (String text, - ActionListener onClick) - { - - JRadioButton b = new JRadioButton () - { - - @Override - public void setText (String t) - { - - super.setText (String.format ("%s", - Environment.replaceObjectNames (t))); - - } - - }; - - b.setText (text); - b.setBackground (null); - b.setOpaque (false); - - if (onClick != null) - { - - b.addActionListener (onClick); - - } - - b.setVerticalTextPosition (SwingConstants.TOP); - b.setVerticalAlignment (SwingConstants.TOP); - - return b; - - } - - public static JCheckBox createCheckBox (String text) - { - - return UIUtils.createCheckBox (text, - null); - - } - - public static JCheckBox createCheckBox (String text, - ActionListener onClick) - { - - JCheckBox b = new JCheckBox () - { - - @Override - public void setText (String t) - { - - super.setText (String.format ("%s", - t)); - - } - - }; - - b.setText (text); - b.setBackground (null); - b.setOpaque (false); - - if (onClick != null) - { - - b.addActionListener (onClick); - - } - - b.setVerticalTextPosition (SwingConstants.TOP); - b.setVerticalAlignment (SwingConstants.TOP); - - return b; - - } - - public static DefaultMutableTreeNode createChaptersTree (Project p, - Collection exclude, - Collection init, - boolean selectable) - { - - DefaultMutableTreeNode root = UIUtils.createTreeNode (p, - exclude, - init, - selectable); - - if (p.getBooks ().size () == 1) - { - - Book b = (Book) p.getBooks ().get (0); - - // Get the chapters. - List chaps = b.getChapters (); - - for (Chapter c : chaps) - { - - DefaultMutableTreeNode node = UIUtils.createTree (c, - exclude, - init, - selectable); - - if (node == null) - { - - continue; - - } - - root.add (node); - - } - - } else - { - - List books = p.getBooks (); - - for (int i = 0; i < books.size (); i++) - { - - Book b = books.get (i); - - DefaultMutableTreeNode node = UIUtils.createTree (b, - exclude, - init, - selectable); - - if (node == null) - { - - continue; - - } - - root.add (node); - - } - - } - - return root; - - } - - public static void addAssetsToLinkToTree (DefaultMutableTreeNode root, - UserConfigurableObjectType forType, - Set assets, - Collection exclude, - Collection init, - boolean selectable) - { - - if ((assets == null) - || - (assets.size () == 0) - ) - { - - return; - - } - - DefaultMutableTreeNode charn = null; - - if (selectable) - { - - SelectableDataObject s = new SelectableDataObject (forType); - s.parentNode = true; - - charn = new DefaultMutableTreeNode (s); - - root.add (charn); - - root = charn; - - } - - for (Asset a : assets) - { - - if (!selectable) - { - - if (!init.contains (a)) - { - - continue; - - } - - } - - DefaultMutableTreeNode node = UIUtils.createTreeNode (a, - exclude, - init, - selectable); - - if (node == null) - { - - continue; - - } - - root.add (node); - - } - - } - - public static DefaultMutableTreeNode createLinkToTree (Project p, - Collection exclude, - Collection init, - boolean selectable) - { - - DefaultMutableTreeNode root = UIUtils.createTreeNode (p, - exclude, - init, - selectable); - - if (p.getBooks ().size () == 1) - { - - Book b = (Book) p.getBooks ().get (0); - - // Get the chapters. - List chaps = b.getChapters (); - - for (Chapter c : chaps) - { - - if (!selectable) - { - - if (!init.contains (c)) - { - - continue; - - } - - } - - DefaultMutableTreeNode node = UIUtils.createTree (c, - exclude, - init, - selectable); - - if (node == null) - { - - continue; - - } - - root.add (node); - - } - - } else - { - - List books = p.getBooks (); - - for (int i = 0; i < books.size (); i++) - { - - Book b = books.get (i); - - if (!selectable) - { - - if (!init.contains (b)) - { - - continue; - - } - - } - - DefaultMutableTreeNode node = UIUtils.createTree (b, - exclude, - init, - selectable); - - if (node == null) - { - - continue; - - } - - root.add (node); - - } - - } - - Set assetTypes = Environment.getAssetUserConfigurableObjectTypes (true); - - for (UserConfigurableObjectType t : assetTypes) - { - - Set as = p.getAssets (t); - - UIUtils.addAssetsToLinkToTree (root, - t, - as, - exclude, - init, - selectable); - - } - - Map> allNotes = new TreeMap (); - - List books = p.getBooks (); - - // Collect all the notes. - for (int i = 0; i < books.size (); i++) - { - - List chapters = books.get (i).getChapters (); - - for (int j = 0; j < chapters.size (); j++) - { - - Set notes = chapters.get (j).getNotes (); - - for (Note n : notes) - { - - String t = n.getType (); - - Set l = allNotes.get (t); - - if (l == null) - { - - l = new TreeSet (new ChapterItemSorter ()); - - allNotes.put (t, - l); - - } - - l.add (n); - - } - - } - - } - - Iterator>> iter = allNotes.entrySet ().iterator (); - - while (iter.hasNext ()) - { - - Map.Entry> item = iter.next (); - - String t = item.getKey (); - - Set l = item.getValue (); - - // Peek at the top of the list to see the actual type. - t = l.iterator ().next ().getType (); - //t = l.get (0).getType (); - - BlankNamedObject bdo = new BlankNamedObject (Note.OBJECT_TYPE, - t); - - Object o = bdo; - - if (selectable) - { - - SelectableDataObject s = new SelectableDataObject (bdo); - s.parentNode = true; - o = s; - - } - - DefaultMutableTreeNode tn = new DefaultMutableTreeNode (o); - - for (Note n : l) - { - - if (!selectable) - { - - if (!init.contains (n)) - { - - continue; - - } - - } - - DefaultMutableTreeNode node = UIUtils.createTreeNode (n, - exclude, - init, - selectable); - - if (node != null) - { - - tn.add (node); - - } - - } - - if (tn.getChildCount () > 0) - { - - root.add (tn); - - } - - } - - return root; - - } - - public static void expandAllNodesWithChildren (JTree t) - { - - DefaultTreeModel dtm = (DefaultTreeModel) t.getModel (); - - DefaultMutableTreeNode root = (DefaultMutableTreeNode) dtm.getRoot (); - - Enumeration en = root.depthFirstEnumeration (); - - while (en.hasMoreElements ()) - { - - DefaultMutableTreeNode node = (DefaultMutableTreeNode) en.nextElement (); - - if (node.getChildCount () > 0) - { - - t.expandPath (new TreePath (node.getPath ())); - - } - - } - - } - - public static void getSelectedObjects (DefaultMutableTreeNode n, - Set s) - { - - Enumeration en = n.children (); - - while (en.hasMoreElements ()) - { - - DefaultMutableTreeNode nn = en.nextElement (); - - SelectableDataObject sd = (SelectableDataObject) nn.getUserObject (); - - if (sd.selected) - { - - s.add (sd.obj); - - } - - UIUtils.getSelectedObjects (nn, - s); - - } - - } - - public static void addSelectableListener (final JTree tree) - { - - tree.addMouseListener (new MouseEventHandler () - { - - private void selectAllChildren (DefaultTreeModel model, - DefaultMutableTreeNode n, - boolean v) - { - - Enumeration en = n.children (); - - while (en.hasMoreElements ()) - { - - DefaultMutableTreeNode c = en.nextElement (); - - SelectableDataObject s = (SelectableDataObject) c.getUserObject (); - - s.selected = v; - - // Tell the model that something has changed. - model.nodeChanged (c); - - // Iterate. - this.selectAllChildren (model, - c, - v); - - } - - } - - @Override - public void handlePress (MouseEvent ev) - { - - TreePath tp = tree.getPathForLocation (ev.getX (), - ev.getY ()); - - if (tp != null) - { - - DefaultMutableTreeNode n = (DefaultMutableTreeNode) tp.getLastPathComponent (); - - // Tell the model that something has changed. - DefaultTreeModel model = (DefaultTreeModel) tree.getModel (); - - SelectableDataObject s = (SelectableDataObject) n.getUserObject (); -/* - if ((ev.getClickCount () == 2) - && - (n.getChildCount () > 0) - ) - { - - this.selectAllChildren (model, - n, - s.selected); - - } else { - - s.selected = !s.selected; - - } -*/ - s.selected = !s.selected; - - model.nodeChanged (n); - - } - - } - - }); - - } - - public static DefaultMutableTreeNode createTree (Book b, - Collection exclude, - Collection init, - boolean selectable) - { - - DefaultMutableTreeNode root = UIUtils.createTreeNode (b, - exclude, - init, - selectable); - - if (root == null) - { - - return null; - - } - - // Get the chapters. - List chs = b.getChapters (); - - for (int i = 0; i < chs.size (); i++) - { - - Chapter c = chs.get (i); - - if (!selectable) - { - - if ((init != null) - && - (!init.contains (c)) - ) - { - - continue; - - } - - } - - DefaultMutableTreeNode node = UIUtils.createTree (c, - exclude, - init, - selectable); - - if (node == null) - { - - continue; - - } - - root.add (node); - - } - - return root; - - } - - public static DefaultMutableTreeNode createTreeNode (Object o, - Collection exclude, - Collection init, - boolean selectable) - { - - if ((exclude != null) && - (exclude.contains (o))) - { - - return null; - - } - - if (selectable) - { - - SelectableDataObject so = new SelectableDataObject ((NamedObject) o); - - if ((init != null) - && - (init.contains (o)) - ) - { - - so.selected = true; - - } - - o = so; - - } - - return new DefaultMutableTreeNode (o); - - } - - public static DefaultMutableTreeNode createTree (Scene s, - Collection exclude, - Collection init, - boolean selectable) - { - - DefaultMutableTreeNode root = UIUtils.createTreeNode (s, - exclude, - init, - selectable); - - if (root == null) - { - - return null; - - } - - // Get the outline items. - Iterator iter = s.getOutlineItems ().iterator (); - - while (iter.hasNext ()) - { - - Object o = iter.next (); - - if (!selectable) - { - - if ((init != null) && - (!init.contains (o))) - { - - continue; - - } - - } - - DefaultMutableTreeNode node = UIUtils.createTreeNode (o, - exclude, - init, - selectable); - - if (node == null) - { - - continue; - - } - - root.add (node); - - } - - return root; - - } - - public static DefaultMutableTreeNode createTree (Chapter c, - Collection exclude, - Collection init, - boolean selectable) - { - - DefaultMutableTreeNode root = UIUtils.createTreeNode (c, - exclude, - init, - selectable); - - if (root == null) - { - - return null; - - } - - List items = new ArrayList (c.getScenes ()); - - items.addAll (c.getOutlineItems ()); - - Collections.sort (items, - new ChapterItemSorter ()); - - for (int j = 0; j < items.size (); j++) - { - - ChapterItem i = (ChapterItem) items.get (j); -/* - if (i instanceof Note) - { - - Note n = (Note) i; - - DefaultMutableTreeNode node = UIUtils.createTreeNode ((Note) n, - exclude, - init, - false); - - if (node == null) - { - - continue; - - } - - root.add (node); - - } -*/ - if (i instanceof Scene) - { - - Scene s = (Scene) i; - - if (!selectable) - { - - if ((init != null) && - (!init.contains (s))) - { - - continue; - - } - - } - - DefaultMutableTreeNode node = UIUtils.createTree ((Scene) s, - exclude, - init, - selectable); - - if (node == null) - { - - continue; - - } - - root.add (node); - - } - - if (i instanceof OutlineItem) - { - - OutlineItem oi = (OutlineItem) i; - - if (!selectable) - { - - if ((init != null) && - (!init.contains (oi))) - { - - continue; - - } - - } - - DefaultMutableTreeNode node = UIUtils.createTreeNode (oi, - exclude, - init, - selectable); - - if (node == null) - { - - continue; - - } - - root.add (node); - - } - - } - - if (!selectable) - { - - DefaultMutableTreeNode notesNode = UIUtils.createChapterNotesNode (c); - - if (notesNode != null) - { - - root.add (notesNode); - - } - - } - - return root; - - } - - private static void showErrorMessage (final PopupsSupported parent, - final String message) - { - - if (parent == null) - { - - return; - - } - - // Force back onto event thread. - UIUtils.doActionLater (new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - final Box content = new Box (BoxLayout.Y_AXIS); - - AbstractProjectViewer pv = null; - - if (parent instanceof AbstractProjectViewer) - { - - pv = (AbstractProjectViewer) parent; - - } - - JTextPane m = UIUtils.createHelpTextPane (String.format (Environment.getUIString (LanguageStrings.errormessage, - LanguageStrings.text), - //"%s

    Click here to contact Quoll Writer support about this problem.", - message, - Constants.ACTION_PROTOCOL, - "reportbug"), - pv); - m.setSize (new Dimension (UIUtils.getPopupWidth () - 20, - m.getPreferredSize ().height)); - m.setBorder (null); - content.add (m); - - content.add (Box.createVerticalStrut (10)); - - JButton close = UIUtils.createButton (getUIString (buttons, LanguageStrings.close)); - - JButton[] buts = new JButton[] { close }; - - JComponent buttons = UIUtils.createButtonBar2 (buts, - Component.LEFT_ALIGNMENT); - buttons.setAlignmentX (Component.LEFT_ALIGNMENT); - content.add (buttons); - content.setBorder (new EmptyBorder (10, 10, 10, 10)); - - final QPopup ep = UIUtils.createPopup (Environment.getUIString (LanguageStrings.errormessage, - LanguageStrings.title), - //"Oops, an error has occurred...", - Constants.ERROR_ICON_NAME, - content, - true, - null); - - close.addActionListener (new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - ep.removeFromParent (); - - } - }); - - content.setPreferredSize (new Dimension (UIUtils.getPopupWidth (), - content.getPreferredSize ().height)); - - parent.showPopupAt (ep, - UIUtils.getCenterShowPosition ((Component) parent, - ep), - false); - ep.setDraggable ((Component) parent); - - } - - }); - - } - - /** - * And this convoluted mess is what happens when you change something fundemantal half way - * through! This needs to be cleaned up in a future release. - * - * @param parent The parent to show the error against. - * @param message The message to show. - */ - public static void showErrorMessage (Object parent, - String message) - { - - if (parent == null) - { - - UIUtils.showErrorMessage (message); - - return; - - } - - if (parent instanceof PopupsSupported) - { - - UIUtils.showErrorMessage ((PopupsSupported) parent, - message); - - return; - - } - - if (parent instanceof PopupWindow) - { - - UIUtils.showErrorMessage ((PopupWindow) parent, - message); - - return; - - } - - if (parent instanceof PopupWindow) - { - - UIUtils.showErrorMessage (((PopupWindow) parent).getViewer (), - message); - - return; - - } - - if (parent instanceof QuollPanel) - { - - UIUtils.showErrorMessage ((PopupsSupported) ((QuollPanel) parent).getViewer (), - message); - - return; - - } - - UIUtils.showErrorMessage (message); - - } -/* - private static void showErrorMessage (final AbstractProjectViewer pv, - final String message) - { - - if (pv == null) - { - - return; - - } - - UIUtils.doActionLater (new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - ErrorWindow ew = new ErrorWindow (pv, - message); - - ew.init (); - - } - - }); - - } - */ - private static void showErrorMessage (final PopupWindow p, - final String message) - { - - if (p == null) - { - - return; - - } - - UIUtils.doActionLater (new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - ErrorWindow ew = new ErrorWindow (p.getViewer (), - message); - - ew.init (); - - Rectangle pbounds = p.getBounds (); - - Dimension size = ew.getPreferredSize (); - - int x = ((pbounds.width - size.width) / 2) + pbounds.x; - int y = ((pbounds.height - size.height) / 2) + pbounds.y; - - // Move the window - Point showAt = new Point (x, - y); - - ew.setShowAt (showAt); - - } - - }); - - } - - private static void showErrorMessage (final String message) - { - - UIUtils.doActionLater (new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - ErrorWindow ew = new ErrorWindow (null, - message); - - ew.init (); - - } - - }); - - } - - public static void showObjectSelectPopup (final Set objs, - final AbstractViewer parent, - final String popupTitle, - final ActionListener onSelect, - final boolean closeOnSelect, - final Point showAt) - { - - UIUtils.showObjectSelectPopup (objs, - parent, - popupTitle, - new DefaultListCellRenderer () - { - - @Override - public Component getListCellRendererComponent (JList list, - Object value, - int index, - boolean isSelected, - boolean cellHasFocus) - { - - NamedObject obj = (NamedObject) value; - - JLabel l = (JLabel) super.getListCellRendererComponent (list, - value, - index, - isSelected, - cellHasFocus); - - l.setText (obj.getName ()); - - l.setFont (l.getFont ().deriveFont (UIUtils.getScaledFontSize (14)).deriveFont (Font.PLAIN)); - l.setIcon (Environment.getObjectIcon (obj, - Constants.ICON_NOTIFICATION)); - l.setBorder (UIUtils.createBottomLineWithPadding (5, 5, 5, 5)); - - if (cellHasFocus) - { - - l.setBackground (Environment.getHighlightColor ()); - - } - - return l; - - } - - }, - onSelect, - closeOnSelect, - showAt); - - } - - public static void showObjectSelectPopup (final Set objs, - final AbstractViewer parent, - final String popupTitle, - final ListCellRenderer renderer, - final ActionListener onSelect, - final boolean closeOnSelect, - final Point showAt) - { - - UIUtils.showObjectSelectPopup (objs, - parent, - popupTitle, - renderer, - onSelect, - closeOnSelect, - null, - showAt); - - } - - public static void showObjectSelectPopup (final Set objs, - final AbstractViewer parent, - final String popupTitle, - final ListCellRenderer renderer, - final ActionListener onSelect, - final boolean closeOnSelect, - final JComponent extra, - final Point showAt) - { - - if (popupTitle == null) - { - - throw new IllegalArgumentException ("Expected a popup title."); - - } - - UIUtils.doActionLater (new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - final Box content = new Box (BoxLayout.Y_AXIS); - - content.setOpaque (true); - content.setBackground (UIUtils.getComponentColor ()); - - DefaultListModel m = new DefaultListModel (); - - for (NamedObject o : objs) - { - - m.addElement (o); - - } - - final JList l = new JList (); - l.setModel (m); - l.setLayoutOrientation (JList.VERTICAL); - l.setVisibleRowCount (0); - l.setOpaque (true); - l.setBackground (UIUtils.getComponentColor ()); - l.setMaximumSize (new Dimension (Short.MAX_VALUE, - Short.MAX_VALUE)); - UIUtils.setAsButton (l); - - l.setCellRenderer (renderer); -/* - new DefaultListCellRenderer () - { - - public Component getListCellRendererComponent (JList list, - Object value, - int index, - boolean isSelected, - boolean cellHasFocus) - { - - NamedObject obj = (NamedObject) value; - - JLabel l = (JLabel) super.getListCellRendererComponent (list, - value, - index, - isSelected, - cellHasFocus); - - l.setText (obj.getName ()); - - l.setFont (l.getFont ().deriveFont (UIUtils.getScaledFontSize (14)).deriveFont (Font.PLAIN)); - l.setIcon (Environment.getObjectIcon (obj, - Constants.ICON_NOTIFICATION)); - l.setBorder (UIUtils.createBottomLineWithPadding (5, 5, 5, 5)); - - if (cellHasFocus) - { - - l.setBackground (Environment.getHighlightColor ()); - - } - - return l; - - } - - }); -*/ -/* - int rowHeight = 37; - - Component t = renderer.getListCellRendererComponent (l, - objs.iterator ().next (), - 0, - false, - false); - - rowHeight = t.getPreferredSize ().height; -*/ - l.setAlignmentX (JComponent.LEFT_ALIGNMENT); - /* - final Dimension sSize = new Dimension (this.swatchSize.width + (2 * this.borderWidth) + (2 * this.horizGap), - this.swatchSize.height + (2 * this.borderWidth) + (2 * this.vertGap)); - */ - JScrollPane sp = new JScrollPane (l); - - sp.setHorizontalScrollBarPolicy (ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); - sp.getVerticalScrollBar ().setUnitIncrement (20);//rowHeight); - sp.setAlignmentX (JComponent.LEFT_ALIGNMENT); - sp.setOpaque (false); -/* - sp.getViewport ().setPreferredSize (new Dimension (400, - rowHeight * (objs.size () > 3 ? 3 : objs.size ()))); -*/ - - l.setVisibleRowCount (Math.min (3, objs.size ())); - - sp.setBorder (null); - - content.add (sp); - - if (extra != null) - { - - extra.setBorder (UIUtils.createPadding (10, 5, 10, 5)); - - content.add (extra); - - } - - final QPopup ep = UIUtils.createClosablePopup (popupTitle, - Environment.getIcon (Constants.VIEW_ICON_NAME, - Constants.ICON_POPUP), - null); - - ep.setContent (content); - - l.addListSelectionListener (new ListSelectionListener () - { - - @Override - public void valueChanged (ListSelectionEvent ev) - { - - if (onSelect != null) - { - - NamedObject obj = (NamedObject) l.getSelectedValue (); - - onSelect.actionPerformed (new ActionEvent (obj, - 0, - obj.getObjectReference ().asString ())); - - if (closeOnSelect) - { - - ep.removeFromParent (); - - } - - } - } - - }); - - content.setPreferredSize (new Dimension (UIUtils.getPopupWidth (), - content.getPreferredSize ().height)); - - parent.showPopupAt (ep, - (showAt != null ? showAt : UIUtils.getCenterShowPosition (parent, - ep)), - false); - ep.setDraggable (parent); - - } - - }); - - } - - public static void showMessage (final PopupsSupported parent, - final String title, - final Component message) - { - - UIUtils.showMessage (parent, - title, - message, - null, - null); - - } - - public static void showMessage (final PopupsSupported parent, - final String title, - final Component message, - final String confirmButtonLabel, - final ActionListener onConfirm) - { - - UIUtils.showMessage (parent, - title, - message, - confirmButtonLabel, - onConfirm, - null); - - } - - public static void showMessage (final PopupsSupported parent, - final String title, - final Component message, - final String confirmButtonLabel, - final ActionListener onConfirm, - final Point showAt) - { - - if (parent == null) - { - - return; - - } - - UIUtils.doActionLater (new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - final Box content = new Box (BoxLayout.Y_AXIS); - - content.setOpaque (true); - content.setBackground (UIUtils.getComponentColor ()); - content.add (message); - - content.add (Box.createVerticalStrut (10)); - - JButton close = UIUtils.createButton ((confirmButtonLabel != null ? confirmButtonLabel : getUIString (buttons, LanguageStrings.close)), - onConfirm); - - JButton[] buts = new JButton[] { close }; - - JComponent buttons = UIUtils.createButtonBar2 (buts, - Component.CENTER_ALIGNMENT); - buttons.setAlignmentX (Component.LEFT_ALIGNMENT); - content.add (buttons); - content.setBorder (new EmptyBorder (10, 10, 10, 10)); - - final QPopup ep = UIUtils.createClosablePopup ((title != null ? title : getUIString (generalmessage,LanguageStrings.title)), - //"Just so you know..."), - Environment.getIcon (Constants.INFO_ICON_NAME, - Constants.ICON_POPUP), - onConfirm); - - ep.setContent (content); - - close.addActionListener (ep.getCloseAction ()); - - content.setPreferredSize (new Dimension (UIUtils.getPopupWidth (), - content.getPreferredSize ().height)); - - parent.showPopupAt (ep, - (showAt != null ? showAt : UIUtils.getCenterShowPosition ((Component) parent, - ep)), - false); - ep.setDraggable ((Component) parent); - - } - - }); - - } - - public static void showMessage (final PopupsSupported parent, - final String title, - final String message, - final String confirmButtonLabel, - final ActionListener onConfirm) - { - - UIUtils.showMessage (parent, - title, - message, - confirmButtonLabel, - onConfirm, - null); - - } - - public static void showMessage (final PopupsSupported parent, - final String title, - final String message, - final String confirmButtonLabel, - final ActionListener onConfirm, - final Point showAt) - { - - AbstractViewer pv = null; - - if (parent instanceof AbstractViewer) - { - - pv = (AbstractViewer) parent; - - } - - JTextPane m = UIUtils.createHelpTextPane (message, - pv); - - m.setSize (new Dimension (UIUtils.getPopupWidth () - 20, - m.getPreferredSize ().height)); - m.setBorder (null); - - UIUtils.showMessage (parent, - title, - m, - confirmButtonLabel, - onConfirm, - showAt); - - } - - public static void showMessage (PopupsSupported parent, - String title, - String message) - { - - UIUtils.showMessage (parent, - title, - message, - null); - - } - - public static void showMessage (PopupsSupported parent, - String title, - String message, - Point showAt) - { - - UIUtils.showMessage (parent, - title, - message, - null, - null, - showAt); - - } - - public static void showMessage (AbstractViewer parent, - String title, - String message, - String confirmButtonLabel, - ActionListener onConfirm) - { - - if (parent == null) - { - - UIUtils.showMessage (title, - message, - confirmButtonLabel, - onConfirm); - - return; - - } - - UIUtils.showMessage ((PopupsSupported) parent, - title, - message, - confirmButtonLabel, - onConfirm); - - } - - public static void showMessage (Component parent, - String title, - String message, - String confirmButtonLabel, - ActionListener onConfirm) - { - - if (parent == null) - { - - UIUtils.showMessage (title, - message, - confirmButtonLabel, - onConfirm); - - return; - - } - - if (parent instanceof QuollPanel) - { - - UIUtils.showMessage ((PopupsSupported) ((QuollPanel) parent).getViewer (), - title, - message, - confirmButtonLabel, - onConfirm); - - return; - - } - - if (parent instanceof PopupsSupported) - { - - UIUtils.showMessage ((PopupsSupported) parent, - title, - message, - confirmButtonLabel, - onConfirm); - - return; - - } - - if (parent instanceof PopupWindow) - { - - UIUtils.showMessage (((PopupWindow) parent).getViewer (), - title, - message, - confirmButtonLabel, - onConfirm); - - return; - - } - - UIUtils.showMessage (title, - message, - confirmButtonLabel, - onConfirm); - - } - - public static void showMessage (Component parent, - String title, - String message) - { - - UIUtils.showMessage (parent, - title, - message, - null, - null); - - } - - public static void showMessage (Component parent, - String message) - { - - UIUtils.showMessage (parent, - null, - message, - null, - null); - - } - - private static void showMessage (String title, - String message, - String confirmButtonLabel, - ActionListener onConfirm) - { - - MessageWindow ew = new MessageWindow (null, - title, - message, - confirmButtonLabel, - onConfirm); - - ew.init (); - - } - - public static QPopup createPopup (String title, - String icon, - JComponent content, - boolean includeCancel, - final ActionListener cancelListener) - { - - final QPopup p = new QPopup (title, - (icon != null ? Environment.getIcon (icon, - Constants.ICON_POPUP) : null), - null); - - if (content != null) - { - - p.setContent (content); - - } - - if (includeCancel) - { - - final JButton cancel = UIUtils.createButton ("cancel", - Constants.ICON_MENU, - getUIString (actions,clicktoclose), - //"Click to close.", - null); - - cancel.addActionListener (new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - p.setVisible (false); - - if (cancelListener != null) - { - - cancelListener.actionPerformed (ev); - - } - - } - - }); - - List buts = new ArrayList (); - buts.add (cancel); - - p.getHeader ().setControls (UIUtils.createButtonBar (buts)); - - } - - return p; - - } - - public static JLabel createInformationLabel (String message) - { - - JLabel l = new JLabel () - { - - public void setText (String t) - { - - if (t == null) - { - - super.setText (""); - - return; - - } - - super.setText (String.format ("%s", - t)); - - } - - }; - - l.setText (message); - l.setAlignmentX (Component.LEFT_ALIGNMENT); - - return l; - - } - - public static JLabel createLoadingLabel (String message) - { - - JLabel l = new JLabel (Environment.getLoadingIcon (), - SwingConstants.LEFT) - { - - @Override - public void setText (String t) - { - - super.setText (String.format ("%s", - (t != null ? t : getUIString (general,loading)))); - //"Loading..."))); - - } - - }; - - l.setText (message); - l.setVisible (false); - l.setAlignmentX (Component.LEFT_ALIGNMENT); - - return l; - - } - - public static JLabel createErrorLabel (String message) - { - - JLabel err = new JLabel () - { - - @Override - public void setText (String t) - { - - super.setText (String.format ("%s", - t)); - - } - - @Override - public void setToolTipText (String t) - { - - super.setText (String.format ("%s", - Environment.replaceObjectNames (t))); - - } - - }; - - err.setText (message); - err.setForeground (UIUtils.getColor (Constants.ERROR_TEXT_COLOR)); - err.setIcon (Environment.getIcon (Constants.ERROR_RED_ICON_NAME, - Constants.ICON_MENU)); - err.setAlignmentX (Component.LEFT_ALIGNMENT); - err.setVerticalTextPosition (SwingConstants.TOP); - err.setVerticalAlignment (SwingConstants.TOP); - - return err; - - } - - public static JLabel createLabel (String message) - { - - JLabel err = new JLabel () - { - - @Override - public void setText (String t) - { - - super.setText (String.format ("%s", - t)); - - } - - }; - - err.setText (message); - err.setAlignmentX (Component.LEFT_ALIGNMENT); - - return err; - - } - - public static void createPopupMenuLabels (Map labels) - { - - int maxWidth = 0; - int maxHeight = 0; - - Iterator iter = labels.keySet ().iterator (); - - while (iter.hasNext ()) - { - - String l = (String) iter.next (); - - JLabel lab = new JLabel (l + " "); - lab.setOpaque (false); - lab.setBorder (null); - - labels.put (l, - lab); - - Dimension dim = lab.getPreferredSize (); - - int w = dim.width; - int h = dim.height; - - if (w > maxWidth) - { - - maxWidth = w; - - } - - if (h > maxHeight) - { - - maxHeight = h; - - } - - } - - FormLayout fl = new FormLayout ("right:" + maxWidth + "px", - "center:" + 20 + "px"); - - iter = labels.entrySet ().iterator (); - - while (iter.hasNext ()) - { - - PanelBuilder b = new PanelBuilder (fl); - CellConstraints cc = new CellConstraints (); - - Map.Entry item = (Map.Entry) iter.next (); - - String l = (String) item.getKey (); - - JLabel ll = (JLabel) item.getValue (); - - b.add (ll, - cc.xy (1, - 1)); - - JPanel p = b.getPanel (); - p.setOpaque (false); - - labels.put (l, - p); - - } - - } - - public static void setAsButton (Component c) - { - - c.setCursor (Cursor.getPredefinedCursor (Cursor.HAND_CURSOR)); - - } - - public static void setDefaultCursor (Component c) - { - - c.setCursor (Cursor.getPredefinedCursor (Cursor.DEFAULT_CURSOR)); - - } - - public static void setAsButton2 (Component c) - { - - c.setCursor (Cursor.getPredefinedCursor (Cursor.HAND_CURSOR)); - - if (c instanceof AbstractButton) - { - - final AbstractButton b = (AbstractButton) c; - - b.setContentAreaFilled (false); - - // b.setMargin (new Insets (2, 2, 2, 2)); - b.addMouseListener (new MouseEventHandler () - { - - @Override - public void mouseEntered (MouseEvent ev) - { - - b.setContentAreaFilled (true); - - } - - @Override - public void mouseExited (MouseEvent ev) - { - - b.setContentAreaFilled (false); - - } - - }); - - } - - } - - public static Border createLineBorder () - { - - return new LineBorder (Environment.getBorderColor (), - 1); - - } - - public static JComboBox createNumberComboBox (Vector vals, - int def) - { - - final JComboBox cb = new JComboBox (vals); - - cb.setEditor (new javax.swing.plaf.basic.BasicComboBoxEditor () - { - - protected JTextField createEditorComponent () - { - - return new FormattedTextField ("[0-9]"); - - } - - }); - - cb.setEditable (true); - - cb.setMaximumSize (cb.getPreferredSize ()); - - if (def > 0) - { - - cb.setSelectedItem (def); - - } - - return cb; - - } - - public static JComboBox getFontSizesComboBox (final int sizeDef) - { - - Vector sizeV = new Vector (); - - boolean defAdded = false; - - for (int i = 8; i < 19; i += 2) - { - - if ((sizeDef < i) && - (!defAdded)) - { - - sizeV.addElement (sizeDef); - defAdded = true; - - } - - if (i != sizeDef) - { - - sizeV.addElement (i); - - } - - } - - if (sizeDef > 18) - { - - sizeV.addElement (sizeDef); - - } - - final JComboBox sizes = UIUtils.createNumberComboBox (sizeV, - sizeDef); - - return sizes; - - } - - public static JComboBox getLineSpacingComboBox (final float lsDef) - { - - Vector lineS = new Vector (); - - boolean defAdded = false; - - for (float i = 0.5f; i < 2.5f; i += 0.5f) - { - - if ((lsDef < i) && - (!defAdded)) - { - - lineS.addElement (lsDef); - defAdded = true; - - } - - if (lsDef != i) - { - - lineS.addElement (i); - - } - - } - - if (lsDef > 2.0f) - { - - lineS.addElement (lsDef); - - } - - final JComboBox line = new JComboBox (lineS); - - line.setEditable (true); - - line.setEditor (new javax.swing.plaf.basic.BasicComboBoxEditor () - { - - protected JTextField createEditorComponent () - { - - return new FormattedTextField ("[0-9\\.]"); - - } - - }); - - line.setMaximumSize (line.getPreferredSize ()); - - if (lsDef > 0) - { - - line.setSelectedItem (lsDef); - - } - - return line; - - } - - public static JComboBox getFontsComboBox (final String selected) - { - - GraphicsEnvironment gEnv = GraphicsEnvironment.getLocalGraphicsEnvironment (); - - String[] envfonts = gEnv.getAvailableFontFamilyNames (); - - Vector vector = new Vector (); - - for (int i = 1; i < envfonts.length; i++) - { - - if (new Font (envfonts[i], - Font.PLAIN, - 12).canDisplayUpTo ("ABCDEFabcdef") == -1) - { - - vector.addElement (envfonts[i]); - - } - - } - - final JComboBox fonts = new JComboBox (vector); - - fonts.setRenderer (new DefaultListCellRenderer () - { - - public Component getListCellRendererComponent (JList list, - Object value, - int index, - boolean isSelected, - boolean cellHasFocus) - { - - super.getListCellRendererComponent (list, - value, - index, - isSelected, - cellHasFocus); - - this.setFont (new Font ((String) value, - Font.PLAIN, - 12)); - - return this; - - } - - }); - - fonts.setMaximumSize (new Dimension (Short.MAX_VALUE, - fonts.getPreferredSize ().height)); - - if (selected != null) - { - - fonts.setSelectedItem (selected); - - } - - return fonts; - - } - - /** - * Get a combobox for the user to select the text alignment. - * The order is always, Left, Justified, Right. - * - * LanguageStrings - "textalignments". - * - * @param alignDef The default alignment, should be one of the ALIGN_* constants from QTextEditor, can be null. - * @returns The combobox. - */ - public static JComboBox getAlignmentComboBox (final String alignDef) - { - - Vector alignS = new Vector (); - alignS.add (getUIString (textalignments,left)); - //QTextEditor.ALIGN_LEFT); - alignS.add (getUIString (textalignments,justified)); - //QTextEditor.ALIGN_JUSTIFIED); - alignS.add (getUIString (textalignments,right)); - //QTextEditor.ALIGN_RIGHT); - - final JComboBox align = new JComboBox (alignS); - - align.setMaximumSize (align.getPreferredSize ()); - - if (alignDef != null) - { - - if (alignDef.equals (QTextEditor.ALIGN_LEFT)) - { - - align.setSelectedIndex (0); - - } - - if (alignDef.equals (QTextEditor.ALIGN_JUSTIFIED)) - { - - align.setSelectedIndex (1); - - } - - if (alignDef.equals (QTextEditor.ALIGN_RIGHT)) - { - - align.setSelectedIndex (2); - - } - - //align.setSelectedItem (alignDef); - - } - - return align; - - } - - public static Component getLimitWrapper (Component c) - { - - Box sw = new Box (BoxLayout.X_AXIS); - sw.add (c); - sw.add (Box.createHorizontalGlue ()); - - return sw; - - } - - public static Border createTestLineBorder () - { - - return new LineBorder (Color.GREEN, - 1); - - } - - public static Border createTestLineBorder2 () - { - - return new LineBorder (Color.RED, - 1); - - } - - public static Header createBoldSubHeader (String title, - String iconType) - { - - Header h = new Header (Environment.replaceObjectNames (title), - ((iconType == null) ? null : Environment.getIcon (iconType, - Constants.ICON_MENU)), - null); - - h.setFont (h.getFont ().deriveFont (UIUtils.getScaledFontSize (14)).deriveFont (Font.PLAIN)); - - h.setTitleColor (UIUtils.getTitleColor ()); - h.setOpaque (false); - - h.setPaintProvider (null); - - h.setAlignmentX (Component.LEFT_ALIGNMENT); - - h.setBorder (UIUtils.createPadding (0, 0, 2, 0)); - - return h; - - } - - public static JLabel createSubHeader (String title, - String iconType) - { - - JLabel l = new JLabel (title); - l.setIcon (Environment.getIcon (iconType, - Constants.ICON_MENU)); - l.setMaximumSize (new Dimension (Short.MAX_VALUE, - l.getPreferredSize ().height)); - l.setBorder (new CompoundBorder (new MatteBorder (0, - 0, - 1, - 0, - Environment.getBorderColor ()), - new EmptyBorder (0, - 0, - 2, - 0))); - l.setAlignmentX (Component.LEFT_ALIGNMENT); - - return l; - - } - -/* - - public static List getChapterSnippetsForNames (Collection names, - Chapter c) - { - - return UIUtils.getTextSnippetsForNames (names, - c.getText ()); - - } -*/ -/* - public static List getTextSnippetsForNames (Collection names, - String text) - { - - List snippets = new ArrayList (); - - if (text != null) - { - - text = StringUtils.replaceString (text, - String.valueOf ('\r'), - ""); - - } - - TextIterator ti = new TextIterator (text); - - for (String n : names) - { - - Map> matches = ti.findInSentences (n, - null); - - if (matches != null) - { - - Iterator iter = matches.keySet ().iterator (); - - char[] tchar = text.toCharArray (); - - while (iter.hasNext ()) - { - - Sentence sen = iter.next (); - - Set inds = matches.get (sen); - - if ((inds != null) - && - (inds.size () > 0) - ) - { - - Segment s = new Segment (tchar, - sen.getAllTextStartOffset (), - sen.getText ().length ()); - - snippets.add (s); - - } - - } - - } - - } - - // Order the segments by the start offset. - try - { - - Query q = new Query (); - q.parse ("SELECT * FROM javax.swing.text.Segment ORDER BY beginIndex"); - QueryResults qr = q.execute (snippets); - - snippets = new ArrayList (qr.getResults ()); - - } catch (Exception e) { - - Environment.logError ("Unable to sort segments", - e); - - } - - return snippets; - - } -*/ -/* - public static Set getObjectsContaining (String s, - Project p) - { - - Set ret = new TreeSet (NamedObjectSorter.getInstance ()); - - for (NamedObject n : p.getAllNamedChildObjects ()) - { - - if (n.contains (s)) - { - - ret.add (n); - - } - - } - - return ret; - - } - - public static Set getAssetsContaining (String s, - Project p) - { - - Set ret = new TreeSet (NamedObjectSorter.getInstance ()); - - for (NamedObject n : p.getAllNamedChildObjects (Asset.class)) - { - - if (n.contains (s)) - { - - ret.add ((Asset) n); - - } - - } - - return ret; - - } - - public static Set getAssetsContaining (String s, - UserConfigurableObjectType limitTo, - Project p) - { - - Set ret = new TreeSet (NamedObjectSorter.getInstance ()); - - if (limitTo != null) - { - - if (!limitTo.isAssetObjectType ()) - { - - return ret; - - } - - } - - for (NamedObject n : p.getAllNamedChildObjects (limitTo)) - { - - if (n.contains (s)) - { - - ret.add ((Asset) n); - - } - - } - - return ret; - - } - - public static Set getNotesContaining (String s, - Project p) - { - - Set ret = new TreeSet (NamedObjectSorter.getInstance ()); - - for (NamedObject n : p.getAllNamedChildObjects (Note.class)) - { - - if (n.contains (s)) - { - - ret.add ((Note) n); - - } - - } - - return ret; - - } - - public static Set getOutlineItemsContaining (String s, - Project p) - { - - Set ret = new TreeSet (NamedObjectSorter.getInstance ()); - - for (NamedObject n : p.getAllNamedChildObjects (OutlineItem.class)) - { - - if (n.contains (s)) - { - - ret.add ((OutlineItem) n); - - } - - } - - return ret; - - } - - public static Set getScenesContaining (String s, - Project p) - { - - Set ret = new TreeSet (NamedObjectSorter.getInstance ()); - - for (NamedObject n : p.getAllNamedChildObjects (Scene.class)) - { - - if (n.contains (s)) - { - - ret.add ((Scene) n); - - } - - } - - return ret; - - } -*/ - public static Map> getObjectSnippets (NamedObject n, - AbstractProjectViewer pv) - { - - Project p = pv.getProject (); - - Map> data = new LinkedHashMap (); - - Set names = n.getAllNames (); - - // String name = n.getName ().toLowerCase (); - - // Get all the books and chapters. - List books = p.getBooks (); - - for (int i = 0; i < books.size (); i++) - { - - Book b = books.get (i); - - List chapters = b.getChapters (); - - for (int j = 0; j < chapters.size (); j++) - { - - Chapter c = chapters.get (j); - - String t = (c.getText () != null ? c.getText ().getText () : null); - - // See if there is an editor for it. - AbstractEditorPanel aep = (AbstractEditorPanel) pv.getEditorForChapter (c); - - if (aep != null) - { - - t = aep.getEditor ().getText (); - - } - - if ((t == null) - || - (t.trim ().equals ("")) - ) - { - - continue; - - } - - List snippets = TextUtilities.getTextSnippetsForNames (names, - t); - - if ((snippets != null) && - (snippets.size () > 0)) - { - - data.put (c, - snippets); - - } - - } - - } - - return data; - - } - -/* - public static Map> getTextSnippets (String s, - AbstractProjectViewer pv) - { - - Map> data = new LinkedHashMap (); - - // String name = n.getName ().toLowerCase (); - - List names = new ArrayList (); - names.add (s); - - // Get all the books and chapters. - List books = pv.getProject ().getBooks (); - - for (int i = 0; i < books.size (); i++) - { - - Book b = books.get (i); - - List chapters = b.getChapters (); - - for (int j = 0; j < chapters.size (); j++) - { - - Chapter c = chapters.get (j); - - AbstractEditorPanel qep = pv.getEditorForChapter (c); - - String t = null; - - if (qep != null) - { - - t = qep.getEditor ().getText (); - - } else { - - if (c.getText () != null) - { - - // Get the text. - t = c.getText ().getText (); - - } - - } - - if (t == null) - { - - continue; - - } - - List snippets = TextUtilities.getTextSnippetsForNames (names, - t); - - if ((snippets != null) && - (snippets.size () > 0)) - { - - data.put (c, - snippets); - - } - - } - - } - - return data; - - } -*/ - public static String markupLinks (String s) - { - - if (s == null) - { - - return s; - - } - - //s = Environment.replaceObjectNames (s); - - s = UIUtils.markupLinks ("http://", - s); - - s = UIUtils.markupLinks ("https://", - s); - - // Replace 0) - { - - char c = s.charAt (ind - 1); - - if ((c == '"') || - (c == '\'')) - { - - ind += 1; - - continue; - - } - - } - - // Find the first whitespace char after... - char[] chars = s.toCharArray (); - - StringBuilder b = new StringBuilder (); - - for (int i = ind + urlPrefix.length (); i < chars.length; i++) - { - - if ((!Character.isWhitespace (chars[i])) - && - (chars[i] != '<') - ) - { - - b.append (chars[i]); - - } else { - - break; - - } - - } - - // Now replace whatever we got... - String st = b.toString ().trim (); - - if ((st.length () == 0) - || - (st.equals (urlPrefix)) - ) - { - - ind = ind + urlPrefix.length (); - - continue; - - } - - // Not sure about this but "may" be ok. - if ((st.endsWith (";")) || - (st.endsWith (",")) || - (st.endsWith ("."))) - { - - st = st.substring (0, - st.length () - 1); - - } - - String w = null; - - try - { - - w = "" + urlPrefix + st + ""; - - } catch (Exception e) { - - // Won't happen. - - } - - StringBuilder ss = new StringBuilder (s); - - s = ss.replace (ind, - ind + st.length () + urlPrefix.length (), - w).toString (); - - ind = ind + w.length (); - - } else - { - - // No more... - break; - - } - - } - - return s; - - } - - public static void removeNodeFromTreeIfNoChildren (JTree tree, - Object n) - { - - DefaultTreeModel model = (DefaultTreeModel) tree.getModel (); - - DefaultMutableTreeNode root = (DefaultMutableTreeNode) model.getRoot (); - - // See how many children there are. - TreePath tp = UIUtils.getTreePathForUserObject (root, - n); - - if (tp != null) - { - - DefaultMutableTreeNode nNode = (DefaultMutableTreeNode) tp.getLastPathComponent (); - - if (nNode.getChildCount () == 0) - { - - // Remove it. - model.removeNodeFromParent (nNode); - - } - - } - - } - - public static void removeNodeFromTree (JTree tree, - Object n) - { - - DefaultTreeModel model = (DefaultTreeModel) tree.getModel (); - - DefaultMutableTreeNode root = (DefaultMutableTreeNode) model.getRoot (); - - TreePath tp = UIUtils.getTreePathForUserObject (root, - n); - - // It can happen but shouldn't. - if (tp == null) - { - - return; - - } - - DefaultMutableTreeNode nNode = (DefaultMutableTreeNode) tp.getLastPathComponent (); - - if (nNode != null) - { - - model.removeNodeFromParent (nNode); - - } - - } -/* - public static Set getReferencedObjects (String t, - Project p, - NamedObject ignore) - { - - if (t == null) - { - - return t; - - } - - Set ret = new HashSet (); - - Set objs = p.getAllNamedChildObjects (Asset.class); - - Set chaps = p.getAllNamedChildObjects (Chapter.class); - - if (chaps.size () > 0) - { - - objs.addAll (chaps); - - } - - if (objs.size () == 0) - { - - return ret; - - } - - if (ignore != null) - { - - objs.remove (ignore); - - } - - Map> items = new HashMap (); - - for (NamedObject o : objs) - { - - NamedObjectNameWrapper.addTo (o, - items); - - } - - // Get all the names. - Set names = items.keySet (); - - List namesL = new ArrayList (names); - - try - { - - JoSQLComparator jc = new JoSQLComparator ("SELECT * FROM java.lang.String ORDER BY toString.length DESC"); - - Collections.sort (namesL, - jc); - - } catch (Exception e) - { - - Environment.logError ("Unable to construct josql comparator", - e); - - } - - for (String name : namesL) - { - - int ind = 0; - int start = 0; - StringBuilder b = new StringBuilder (); - String tl = t.toLowerCase (); - - while (ind != -1) - { - - ind = tl.indexOf (name, - start); - - if (ind != -1) - { - - String tag = "[[_$@" + name.hashCode () + "@$_]]"; - - b.append (t.substring (start, - ind)); - b.append (tag); - - start = ind + name.length (); - - } else - { - - b.append (t.substring (start)); - - } - - } - - t = b.toString (); - - } - - for (String name : namesL) - { - - List nitems = items.get (name); - - NamedObjectNameWrapper nw = nitems.get (0); - - t = StringUtils.replaceString (t, - "[[_$@" + name.hashCode () + "@$_]]", - "" + nw.name + ""); - - } - - - } - */ - public static String markupStringForAssets (String t, - Project p, - NamedObject ignore) - { - - if (t == null) - { - - return t; - - } - - Set objs = p.getAllNamedChildObjects (Asset.class); - - Set chaps = p.getAllNamedChildObjects (Chapter.class); - - if (chaps.size () > 0) - { - - objs.addAll (chaps); - - } - - if (objs.size () == 0) - { - - return t; - - } - - if (ignore != null) - { - - objs.remove (ignore); - - } - - Map> items = new HashMap (); - - for (NamedObject o : objs) - { - - NamedObjectNameWrapper.addTo (o, - items); - - } - - NavigableMap reps = new TreeMap (); - - TextIterator ti = new TextIterator (t); - - for (NamedObject n : objs) - { - - Set matches = null; - - for (String name : n.getAllNames ()) - { - - matches = ti.findAllTextIndexes (name, - null); - - // TODO: This needs to be on a language basis. - Set matches2 = ti.findAllTextIndexes (name + "'s", - null); - - matches.addAll (matches2); - - Iterator iter = matches.iterator (); - - while (iter.hasNext ()) - { - - Integer ind = iter.next (); - - // Now search back through the string to make sure - // we aren't actually part of a http or https string. - int httpInd = t.lastIndexOf ("http://", - ind); - int httpsInd = t.lastIndexOf ("https://", - ind); - - if ((httpInd > -1) - || - (httpsInd > -1) - ) - { - - // Check forward to ensure there is no white space. - String ss = t.substring (Math.max (httpInd, httpsInd), - ind); - - boolean hasWhitespace = false; - - char[] chars = ss.toCharArray (); - - for (int i = 0; i < chars.length; i++) - { - - if (Character.isWhitespace (chars[i])) - { - - hasWhitespace = true; - - break; - - } - - } - - if (!hasWhitespace) - { - - // This name is part of a http/https link so ignore. - continue; - - } - - } - - // Check the char at the index, if it's uppercase then we upper the word otherwise lower. - if (Character.isLowerCase (t.charAt (ind))) - { - - reps.put (ind, - new NamedObjectNameWrapper (name.toLowerCase (), - n)); - - } else { - - // Uppercase each of the words in the name. - reps.put (ind, - new NamedObjectNameWrapper (TextUtilities.capitalize (name), - n)); - - } - - } - - } - - } - - NavigableMap nreps = new TreeMap (); - - List mis = new ArrayList (reps.keySet ()); - - // Sort by location. - Collections.sort (mis); - - // Prune out the overlaps. - for (int i = 0; i < mis.size (); i++) - { - - Integer curr = mis.get (i); - - NamedObjectNameWrapper wrap = reps.get (curr); - - nreps.put (curr, - wrap); - - int ni = i + 1; - - if (ni < mis.size ()) - { - - Integer next = mis.get (ni); - - // Does the next match start before the end of the current match? - if (next.intValue () <= curr.intValue () + wrap.name.length ()) - { - - // Move to the next, when the loop goes to the next it will - // increment again moving past it. - i = ni; - - } - - } - - } - - reps = nreps; - - StringBuilder b = new StringBuilder (t); - - // We iterate backwards over the indexes so we don't have to choppy-choppy the string. - Iterator iter = reps.descendingKeySet ().iterator (); - - while (iter.hasNext ()) - { - - Integer ind = iter.next (); - - NamedObjectNameWrapper obj = reps.get (ind); -/* - b = b.replace (ind, - ind + obj.name.length (), - "" + obj.name + ""); - */ - - String w = obj.name; - - try - { - - w = URLEncoder.encode (obj.name, "utf-8"); - - } catch (Exception e) { - - // Ignore. - - } - - b = b.replace (ind, - ind + obj.name.length (), - String.format ("%s", - Constants.OBJECTNAME_PROTOCOL, - w, - obj.name)); - - } - - t = b.toString (); - - t = StringUtils.replaceString (t, - String.valueOf ('\n'), - "
    "); - - return t; - - } - - public static String getObjectALink (NamedObject d) - { - - return "" + d.getName () + ""; - - } - - public static Map parseState (String s) - { - - // Preserve the order, it "may" be important. - Map ret = new LinkedHashMap (); - - StringTokenizer t = new StringTokenizer (s, - String.valueOf ('\n')); - - while (t.hasMoreTokens ()) - { - - String tok = t.nextToken ().trim (); - - StringTokenizer tt = new StringTokenizer (tok, - "="); - - while (tt.hasMoreTokens ()) - { - - if (tt.countTokens () == 2) - { - - String name = tt.nextToken ().trim (); - String value = tt.nextToken ().trim (); - - ret.put (name, - value); - - } - - } - - } - - return ret; - - } - - public static String createState (Map values) - { - - StringBuilder b = new StringBuilder (); - - Iterator iter = values.keySet ().iterator (); - - while (iter.hasNext ()) - { - - String k = iter.next ().toString (); - String v = values.get (k).toString (); - - b.append (k); - b.append ("="); - b.append (v); - b.append ('\n'); - - } - - return b.toString (); - - } - - public static JButton createToolBarButton (String icon, - String tooltip, - String actionCommand, - ActionListener action) - { - - JButton bt = new JButton (Environment.getIcon (icon, - Constants.ICON_TOOLBAR)) - { - - @Override - public void setText (String t) - { - - super.setText (Environment.replaceObjectNames (t)); - - } - - }; - - UIUtils.setAsButton (bt); - bt.setToolTipText (Environment.replaceObjectNames (tooltip)); - bt.setActionCommand (actionCommand); - bt.setOpaque (false); - - if (action != null) - { - - bt.addActionListener (action); - - } - - return bt; - - } - - public static JScrollPane createTreeScroll (JTree tree) - { - - JScrollPane scroll = new JScrollPane (tree); - scroll.setBorder (new MatteBorder (3, - 3, - 3, - 3, - tree.getBackground ())); - scroll.setOpaque (false); - scroll.setOpaque (true); - - return scroll; - - } - - public static JTree createTree () - { - - JTree tree = new JTree (); - tree.setCellRenderer (new ProjectTreeCellRenderer (false)); - tree.setOpaque (true); - tree.setBorder (null); - tree.setRootVisible (false); - tree.setShowsRootHandles (true); - tree.setScrollsOnExpand (true); - tree.setRowHeight (0); - - tree.putClientProperty (com.jgoodies.looks.Options.TREE_LINE_STYLE_KEY, - com.jgoodies.looks.Options.TREE_LINE_STYLE_NONE_VALUE); - - tree.putClientProperty ("Tree.paintLines", - Boolean.FALSE); - - return tree; - - } - - public static void setTreeRootNode (JTree tree, - DefaultMutableTreeNode tn) - { - - java.util.List openPaths = new ArrayList (); - - Enumeration paths = tree.getExpandedDescendants (new TreePath (tree.getModel ().getRoot ())); - - if (paths != null) - { - - while (paths.hasMoreElements ()) - { - - openPaths.add (paths.nextElement ()); - - } - - } - - DefaultTreeModel dtm = (DefaultTreeModel) tree.getModel (); - - dtm.setRoot (tn); - - for (TreePath p : openPaths) - { - - tree.expandPath (UIUtils.getTreePathForUserObject (tn, - ((DefaultMutableTreeNode) p.getLastPathComponent ()).getUserObject ())); - - } - - } - - public static void setCenterOfScreenLocation (Window f) - { - - f.pack (); - - Dimension dim = Toolkit.getDefaultToolkit ().getScreenSize (); - - int w = f.getSize ().width; - int h = f.getSize ().height; - int x = (dim.width - w) / 2; - int y = (dim.height - h) / 2; - - // Move the window - f.setLocation (x, - y); - - } - - public static void addHyperLinkListener (final JEditorPane p, - final AbstractViewer viewer) - { - - p.addHyperlinkListener (new HyperlinkListener () - { - - @Override - public void hyperlinkUpdate (HyperlinkEvent ev) - { - - if (ev.getEventType () == HyperlinkEvent.EventType.ACTIVATED) - { - - URL url = ev.getURL (); - - UIUtils.openURL (viewer, - url); - - } - - } - - }); - - } - - public static Header createHeader (String title, - int titleType) - { - - return UIUtils.createHeader (title, - titleType, - (String) null, - null); - - } - - public static Header createHeader (String title, - int titleType, - String icon, - JComponent controls) - { - - int iconType = Constants.ICON_MENU; - - if (titleType == Constants.POPUP_WINDOW_TITLE) - { - - iconType = Constants.ICON_POPUP; - - } - - if (titleType == Constants.SUB_PANEL_TITLE) - { - - iconType = Constants.ICON_SUB_PANEL_MAIN; - - } - - if (titleType == Constants.PANEL_TITLE) - { - - iconType = Constants.ICON_PANEL_MAIN; - - - } - - if (titleType == Constants.FULL_SCREEN_TITLE) - { - - iconType = Constants.ICON_PANEL_MAIN; - - } - - ImageIcon ii = null; - - if (icon != null) - { - - ii = Environment.getIcon (icon, - iconType); - - } - - return UIUtils.createHeader (title, - titleType, - ii, - controls); - - } - - public static Header createHeader (String title, - int titleType, - Icon icon, - JComponent controls) - { - - int fontSize = 10; - Insets ins = null; - - if (titleType == Constants.POPUP_WINDOW_TITLE) - { - - fontSize = 16; - ins = null; //new Insets (3, 3, 3, 3); - - } - - if (titleType == Constants.SUB_PANEL_TITLE) - { - - fontSize = 14; - ins = new Insets (5, 5, 0, 0); - - } - - if (titleType == Constants.PANEL_TITLE) - { - - fontSize = 16; - ins = new Insets (5, 7, 5, 7); - - - } - - if (titleType == Constants.FULL_SCREEN_TITLE) - { - - fontSize = 18; - ins = new Insets (5, 10, 8, 5); - - - } - - Header h = new Header (Environment.replaceObjectNames (title), - icon, - controls); - - h.setAlignmentX (Component.LEFT_ALIGNMENT); - - h.setFont (h.getFont ().deriveFont ((float) UIUtils.scaleToScreenSize (fontSize)).deriveFont (Font.PLAIN)); - h.setTitleColor (UIUtils.getTitleColor ()); - h.setPadding (ins); - - return h; - - } - - public static JPanel createHelpBox (String helpText, - int iconType, - AbstractViewer pv) - { - - FormLayout fl = new FormLayout ("p, 3px, fill:90px:grow", - "top:p"); - - PanelBuilder pb = new PanelBuilder (fl); - - CellConstraints cc = new CellConstraints (); - - ImagePanel helpII = new ImagePanel (Environment.getIcon ("help", - iconType), - null); - helpII.setAlignmentX (Component.LEFT_ALIGNMENT); - - pb.add (helpII, - cc.xy (1, - 1)); - - JTextPane helpT = UIUtils.createHelpTextPane (helpText, - pv); - - JScrollPane hsp = new JScrollPane (helpT); - hsp.setOpaque (false); - hsp.setBorder (null); - hsp.getViewport ().setOpaque (false); - hsp.setAlignmentX (Component.LEFT_ALIGNMENT); - - pb.add (hsp, - cc.xy (3, - 1)); - - JPanel helpBox = pb.getPanel (); - helpBox.setOpaque (false); - helpBox.setVisible (false); - helpBox.setBorder (new EmptyBorder (0, - 0, - 5, - 0)); - helpBox.setAlignmentX (Component.LEFT_ALIGNMENT); - - return helpBox; - - } - - public static String formatTextForHelpPane (String text) - { - - if (text != null) - { - - StringBuilder buf = new StringBuilder (); - - //text = Environment.replaceObjectNames (text); - - text = StringUtils.replaceString (text, - "{QW}", - Constants.QUOLL_WRITER_NAME); - - text = StringUtils.replaceString (text, - String.valueOf ('\n'), - "
    "); - - text = UIUtils.markupLinks (text); - - int ind = text.indexOf ("["); - - while (ind > -1) - { - - int end = text.indexOf ("]", - ind + 1); - - if (end < 0) - { - - ind = text.indexOf ("[", - ind + 1); - - continue; - - } - - if (end > ind + 1) - { - - String v = text.substring (ind + 1, - end); - - StringTokenizer st = new StringTokenizer (v, - ",;"); - - String icon = st.nextToken ().trim ().toLowerCase (); - String action = null; - - if (st.hasMoreTokens ()) - { - - action = st.nextToken ().trim ().toLowerCase (); - - } - - v = ""; - - if (action != null) - { - - v = "" + v + ""; - - } - - // Split up the value. - text = text.substring (0, - ind) + v + text.substring (end + 1); - - ind = text.indexOf ("[", - ind + v.length ()); - - - } - - } - - text = UIUtils.getWithHTMLStyleSheet (new JTextField ("abcdABCD"), - text); - - } - - return text; - - } - - // TODO: Make this work. - public static JTextPane createHelpTextPane (StringWithMarkup text, - AbstractViewer viewer) - { - - return UIUtils.createHelpTextPane ((text != null ? text.getMarkedUpText () : null), - viewer); - - } - - public static JTextPane createHelpTextPane (AbstractViewer viewer) - { - - return UIUtils.createHelpTextPane ((String) null, - viewer); - - } - - public static JTextPane createHelpTextPane (String text, - AbstractViewer viewer) - { - - HTMLEditorKit kit = new HTMLEditorKit (); - HTMLDocument doc = (HTMLDocument) kit.createDefaultDocument (); - - final JTextPane desc = new JTextPane (doc) - { - - @Override - public void setText (String t) - { - - super.setText (UIUtils.formatTextForHelpPane (t)); - - } - - }; - - desc.setEditorKit (kit); - desc.setEditable (false); - desc.setOpaque (false); - desc.setAlignmentX (JComponent.LEFT_ALIGNMENT); - - desc.setSize (new Dimension (500, - Short.MAX_VALUE)); - - desc.setText (text); - - UIUtils.addHyperLinkListener (desc, - viewer); - - return desc; - - } - - public static String getWithHTMLStyleSheet (JTextComponent desc, - String text) - { - - return UIUtils.getWithHTMLStyleSheet (desc, - text, - null, - null); - - } - - public static String getWithHTMLStyleSheet (JTextComponent desc, - String text, - String linkColor, - String textColor) - { - - if (text == null) - { - - text = ""; - - } - - text = StringUtils.replaceString (text, - String.valueOf ('\n'), - "
    "); - - StringBuilder t = new StringBuilder (); - t.append (""); - t.append (UIUtils.getHTMLStyleSheet (desc, - linkColor, - textColor)); - t.append (""); - t.append (UIUtils.markupLinks (text)); - t.append (""); - - return t.toString (); - - } - - public static void openURL (Component parent, - String url) - { - - URL u = null; - - try - { - - u = new URL (url); - - } catch (Exception e) - { - - Environment.logError ("Unable to browse to: " + - url, - e); - - UIUtils.showErrorMessage (parent, - String.format (getUIString (general,unabletoopenwebpage), - url)); - //"Unable to open web page: " + url); - - return; - - } - - UIUtils.openURL (parent, - u); - - } - - public static AbstractViewer getViewer (Component parent) - { - - if (parent == null) - { - - return null; - - } - - if (parent instanceof AbstractViewer) - { - - return (AbstractViewer) parent; - - } - - if (parent instanceof PopupWindow) - { - - return ((PopupWindow) parent).getViewer (); - - } - - if (parent instanceof QuollPanel) - { - - return ((QuollPanel) parent).getViewer (); - - } - - return UIUtils.getViewer (parent.getParent ()); - - } - - public static AbstractProjectViewer getProjectViewer (Component parent) - { - - AbstractViewer v = UIUtils.getViewer (parent); - - if ((v != null) - && - (v instanceof AbstractProjectViewer) - ) - { - - return (AbstractProjectViewer) v; - - } - - return null; - - } - -/* - public static AbstractViewer getViewer (Component parent) - { - - if (parent == null) - { - - return null; - - } - - if (parent instanceof AbstractViewer) - { - - return (AbstractViewer) parent; - - } - - return UIUtils.getViewer (parent.getParent ()); - - } -*/ - public static void showFile (Component parent, - File f) - { - - try - { - - Desktop.getDesktop ().open (f); - - } catch (Exception e) - { - - Environment.logError ("Unable to open: " + - f, - e); - - UIUtils.showErrorMessage (parent, - String.format (getUIString (general,unabletoopenfile), - f.getPath ())); - //"Unable to open: " + f); - - return; - - } - - } - - public static void openURL (Component parent, - URL url) - { - - if (url == null) - { - - return; - - } - - if (url.getProtocol ().equals (Constants.QUOLLWRITER_PROTOCOL)) - { - - String u = Environment.getQuollWriterWebsite (); - - String p = url.getPath (); - - if ((!p.endsWith (".html")) - && - // Only add if the url isn't of the form [name].html?parms - (p.indexOf (".html?") < 1) - && - // Only add if the url isn't of the form [name].html#id - (p.indexOf (".html#") < 1) - ) - { - - p += ".html"; - - } - - u = u + "/" + p; - - if (url.getQuery () != null) - { - - u += "?" + url.getQuery (); - - } - - if (url.getRef () != null) - { - - u += "#" + url.getRef (); - - } - - try - { - - url = new URL (u); - - } catch (Exception e) - { - - Environment.logError ("Unable to open url: " + - u, - e); - - return; - - } - - } - - if (url.getProtocol ().equals (Constants.HELP_PROTOCOL)) - { - - // Prefix it with the website. - String u = Environment.getQuollWriterWebsite (); - - String p = url.getPath (); - - if (!p.endsWith (".html")) - { - - p += ".html"; - - } - - u = u + "/user-guide/" + url.getHost () + p; - - try - { - - url = new URL (u); - - } catch (Exception e) - { - - Environment.logError ("Unable to open url: " + - u, - e); - - return; - - } - - if (parent != null) - { - - AbstractViewer pv = UIUtils.getViewer (parent); - - if (pv != null) - { - - Environment.eventOccurred (new ProjectEvent (pv, - ProjectEvent.HELP, - ProjectEvent.SHOW)); - - } - - } - - } - - if (url.getProtocol ().equals (Constants.OPENPROJECT_PROTOCOL)) - { - - String projId = url.getPath (); - - Project proj = null; - - try - { - - Environment.openProject (projId, - null, - null); - - } catch (Exception e) { - - Environment.logError ("Unable to get project for id: " + projId, - e); - - } - - return; - - } - - if (url.getProtocol ().equals (Constants.OPENEDITORMESSAGE_PROTOCOL)) - { - - int key = 0; - - try - { - - key = Integer.parseInt (url.getPath ()); - - } catch (Exception e) { - - // Ignore? - - } - - // Get the message. - EditorMessage mess = null; - - try - { - - mess = EditorsEnvironment.getMessageByKey (key); - - } catch (Exception e) { - - Environment.logError ("Unable to get message for key: " + key, - e); - - } - - if (mess != null) - { - - // Need to work out what to do. - //EditorsEnvironment.openEditorMessage (mess); - - } - - return; - - } - - if (url.getProtocol ().equals (Constants.OBJECTREF_PROTOCOL)) - { - - if (parent != null) - { - - AbstractProjectViewer pv = UIUtils.getProjectViewer (parent); - - if (pv != null) - { - - pv.viewObject (pv.getProject ().getObjectForReference (ObjectReference.parseObjectReference (url.getHost ()))); - - return; - - } - - } - - } - - - if (url.getProtocol ().equals (Constants.ACTION_PROTOCOL)) - { - - String action = url.getPath (); - - if (parent != null) - { - - AbstractViewer pv = Environment.getFocusedViewer (); - - if (pv != null) - { - - pv.handleHTMLPanelAction (action); - - return; - - } - - } - - } - - if (url.getProtocol ().equals ("mailto")) - { - - return; - - } - - try - { - - Desktop.getDesktop ().browse (url.toURI ()); - - } catch (Exception e) - { - - Environment.logError ("Unable to browse to: " + - url, - e); - - UIUtils.showErrorMessage (parent, - String.format (getUIString (general,unabletoopenwebpage), - url)); - //"Unable to open web page: " + url); - - } - - } - - public static JTextPane createTextViewPane (final StringWithMarkup description, - final AbstractProjectViewer pv) - { - - // TODO: Markup to html? - return UIUtils.createTextViewPane ((description != null ? description.getMarkedUpText () : null), - pv); - - } - - public static JTextPane createTextViewPane (final String description, - final AbstractProjectViewer pv) - { - - HTMLEditorKit kit = new HTMLEditorKit (); - HTMLDocument doc = (HTMLDocument) kit.createDefaultDocument (); - - final JTextPane desc = new JTextPane (doc) - { - - @Override - public void setText (String t) - { - - if (t == null) - { - - t = ""; - - } - - super.setText (UIUtils.getWithHTMLStyleSheet (this, - UIUtils.markupStringForAssets (t, - pv.getProject (), - null))); - - } - - }; - - desc.setEditorKit (kit); - desc.setEditable (false); - desc.setOpaque (false); - - desc.setSize (new Dimension (500, Short.MAX_VALUE)); - desc.addHyperlinkListener (new HyperlinkAdapter () - { - - public void hyperlinkUpdate (HyperlinkEvent ev) - { - - if (ev.getEventType () == HyperlinkEvent.EventType.ACTIVATED) - { - - URL url = ev.getURL (); - - if (url.getProtocol ().equals (Constants.OBJECTREF_PROTOCOL)) - { - - pv.viewObject (pv.getProject ().getObjectForReference (ObjectReference.parseObjectReference (url.getHost ()))); - - return; - - } - - if (url.getProtocol ().equals (Constants.OBJECTNAME_PROTOCOL)) - { - - String n = url.getHost (); - - try - { - - n = URLDecoder.decode (url.getHost (), "utf-8"); - - } catch (Exception e) { - - // Ignore. - - } - - Set objs = pv.getProject ().getAllAssetsByName (n, - null); - - if ((objs == null) - || - (objs.size () == 0) - ) - { - - return; - - } - - if (objs.size () == 1) - { - - pv.viewObject (objs.iterator ().next ()); - - return; - - } else { - - try - { - - Point point = desc.modelToView (ev.getSourceElement ().getStartOffset ()).getLocation (); - - point = SwingUtilities.convertPoint (desc, - point, - pv); - - UIUtils.showObjectSelectPopup (objs, - pv, - getUIString (selectitem,popup,title), - //"Select an item to view", - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - pv.viewObject (pv.getProject ().getObjectForReference (ObjectReference.parseObjectReference (ev.getActionCommand ()))); - - } - - }, - true, - point); - - } catch (Exception e) { - - Environment.logError ("Unable to show popup", - e); - - pv.viewObject (objs.iterator ().next ()); - - return; - - } - - } - - } - - if (url.getProtocol ().equals ("mailto")) - { - - return; - - } - - UIUtils.openURL (pv, - url); - - } - - } - - }); - - desc.setText (description); - - return desc; - - } - - public static JEditorPane createObjectDescriptionViewPane (final StringWithMarkup description, - final NamedObject n, - final AbstractProjectViewer pv, - final ProjectObjectQuollPanel qp) - { - - // TODO: Markup to html? - return UIUtils.createObjectDescriptionViewPane ((description != null ? description.getMarkedUpText () : null), - n, - pv, - qp); - - } - - public static JFXPanel createJFXObjectDescriptionViewPane (final String description, - final NamedObject n, - final AbstractProjectViewer pv, - final ProjectObjectQuollPanel qp) - { - - final JFXPanel jfxp = new JFXPanel (); - - Platform.runLater (new Runnable () - { - - @Override - public void run () - { - - BorderPane bp = new BorderPane (); - WebView web = new WebView (); - - web.getEngine ().loadContent (UIUtils.getWithHTMLStyleSheet (null, - UIUtils.markupStringForAssets (description, - pv.getProject (), - n))); - - bp.setCenter (web); - - javafx.scene.Scene s = new javafx.scene.Scene (bp); - - jfxp.setScene (s); - - } - - }); - - return jfxp; - - } - - public static JEditorPane createObjectDescriptionViewPane (final String description, - final NamedObject n, - final AbstractProjectViewer pv, - final ProjectObjectQuollPanel qp) - { - - HTMLEditorKit kit = new HTMLEditorKit (); - HTMLDocument doc = (HTMLDocument) kit.createDefaultDocument (); - - //final JTextPane desc = new JTextPane (doc) - final JEditorPane desc = new JEditorPane () - { - - @Override - public void setText (String t) - { - - super.setText (UIUtils.getWithHTMLStyleSheet (this, - UIUtils.markupStringForAssets (t, - pv.getProject (), - n))); - - } - - }; - - desc.setDocument (doc); - desc.setEditorKit (kit); - desc.setEditable (false); - desc.setOpaque (false); - - /* - desc.setMaximumSize (new Dimension (Short.MAX_VALUE, - Short.MAX_VALUE)); -*/ - desc.setSize (new Dimension (250, Short.MAX_VALUE)); - desc.addHyperlinkListener (new HyperlinkListener () - { - - @Override - public void hyperlinkUpdate (HyperlinkEvent ev) - { - - if (ev.getEventType () == HyperlinkEvent.EventType.ACTIVATED) - { - - URL url = ev.getURL (); - - if (url.getProtocol ().equals (Constants.OBJECTREF_PROTOCOL)) - { - - pv.viewObject (pv.getProject ().getObjectForReference (ObjectReference.parseObjectReference (url.getHost ()))); - - return; - - } - - if (url.getProtocol ().equals (Constants.OBJECTNAME_PROTOCOL)) - { - - String un = url.getHost (); - - try - { - - un = URLDecoder.decode (un, "utf-8"); - - } catch (Exception e) { - - // Ignore. - - } - - Set objs = pv.getProject ().getAllNamedObjectsByName (un); - - if ((objs == null) - || - (objs.size () == 0) - ) - { - - return; - - } - - if (objs.size () == 1) - { - - pv.viewObject (objs.iterator ().next ()); - - return; - - } else { - - try - { - - Point point = desc.modelToView (ev.getSourceElement ().getStartOffset ()).getLocation (); - - point = SwingUtilities.convertPoint (desc, - point, - pv); - - UIUtils.showObjectSelectPopup (objs, - pv, - getUIString (selectitem,popup,title), - //"Select an item to view", - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - pv.viewObject (pv.getProject ().getObjectForReference (ObjectReference.parseObjectReference (ev.getActionCommand ()))); - - } - - }, - true, - point); - - } catch (Exception e) { - - Environment.logError ("Unable to show popup", - e); - - pv.viewObject (objs.iterator ().next ()); - - return; - - } - - } - - return; - - } - - if (url.getProtocol ().equals ("mailto")) - { - - return; - - } - - UIUtils.openURL (pv, - url); - - } - - } - - }); - - if (qp != null) - { - - PropertyChangedAdapter pca = new PropertyChangedAdapter () - { - - public void propertyChanged (PropertyChangedEvent ev) - { - - if (ev.getChangeType ().equals (NamedObject.DESCRIPTION)) - { - - desc.setText (description); - - } - - } - - }; - - qp.addObjectPropertyChangedListener (pca); - - pca.propertyChanged (new PropertyChangedEvent (qp, - NamedObject.DESCRIPTION, - null, - null)); - - } else { - - desc.setText (description); - - } - - return desc; - - } - - public static String colorToHex (Color c) - { - - return "#" + Integer.toHexString (c.getRGB ()).substring (2); - - } - - public static String getHTMLStyleSheet (JTextComponent desc, - String textColor, - String linkColor) - { - - return UIUtils.getHTMLStyleSheet (desc, - textColor, - linkColor, - -1); - - } - - public static String getHTMLStyleSheet (JTextComponent desc, - String textColor, - String linkColor, - int textSize) - { - - StringBuilder t = new StringBuilder (); - - Font f = null; - - if (desc != null) - { - - f = desc.getFont (); - - } else { - - f = new JLabel ().getFont (); - - } - - if (linkColor == null) - { - - linkColor = Constants.HTML_LINK_COLOR; - - } - - if (!linkColor.startsWith ("#")) - { - - linkColor = "#" + linkColor; - - } - - if (textColor == null) - { - - textColor = "#000000"; - - } - - if (!textColor.startsWith ("#")) - { - - textColor = "#" + textColor; - - } - - int size = textSize; - - if (size < 1) - { - - size = (int) f.getSize (); - - } - - t.append (""); - - return t.toString (); - - } - - public static String getHTMLStyleSheet (JTextComponent desc) - { - - return UIUtils.getHTMLStyleSheet (desc, - "#000000", - Constants.HTML_LINK_COLOR); - - } - - public static AbstractAction createAddAssetActionListener (final UserConfigurableObjectType forAssetType, - final ProjectViewer viewer, - final String name, - final String desc) - { - - return new AbstractAction () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - Asset as = null; - - try - { - - as = Asset.createAsset (forAssetType); - - } catch (Exception e) { - - Environment.logError ("Unable to create new asset for object type: " + - forAssetType, - e); - - UIUtils.showErrorMessage (viewer, - String.format (getUIString (assets,add,actionerror), - forAssetType.getObjectTypeName ())); - //"Unable to create new asset type."); - - return; - - } - - if (as == null) - { - - Environment.logError ("Unable to create new asset for object type: " + - forAssetType); - - UIUtils.showErrorMessage (viewer, - String.format (getUIString (assets,add,actionerror), - forAssetType.getObjectTypeName ())); - //"Unable to create new asset type."); - - return; - - } - - if (name != null) - { - - as.setName (name); - - } - - if (desc != null) - { - - as.setDescription (new StringWithMarkup (desc)); - - } - - String addAsset = UserProperties.get (Constants.ADD_ASSETS_PROPERTY_NAME); - - // Should we use a popup? - if (((addAsset.equals (Constants.ADD_ASSETS_TRY_POPUP)) - && - (forAssetType.getNonCoreFieldCount () == 0) - ) - || - (addAsset.equals (Constants.ADD_ASSETS_POPUP)) - ) - { - - AssetActionHandler aah = new AssetActionHandler (as, - viewer); - - aah.setPopupOver (viewer); - - aah.actionPerformed (ev); - - return; - - } - - viewer.showAddAsset (as, - null); - - } - - }; - - } - - public static void addNewAssetItemsToPopupMenu (final Container m, - final Component showPopupAt, - final ProjectViewer pv, - final String name, - final String desc) - { - - String pref = getUIString (general,shortcut); - //"Shortcut: "; - - Set types = Environment.getAssetUserConfigurableObjectTypes (true); - - for (UserConfigurableObjectType type : types) - { - - JMenuItem mi = new JMenuItem (type.getObjectTypeName (), - type.getIcon16x16 ()); - - m.add (mi); - - KeyStroke k = type.getCreateShortcutKeyStroke (); - - if (k != null) - { - - mi.setMnemonic (k.getKeyChar ()); - mi.setToolTipText (pref + Utils.keyStrokeToString (k)); - - } - - mi.addActionListener (UIUtils.createAddAssetActionListener (type, - pv, - name, - desc)); - - } - - } - - public static void addNewAssetItemsAsToolbarToPopupMenu (JPopupMenu m, - Component showPopupAt, - ProjectViewer pv, - String name, - String desc) - { - - List buts = new ArrayList (); - - Set types = Environment.getAssetUserConfigurableObjectTypes (true); - - for (UserConfigurableObjectType type : types) - { - - JButton but = UIUtils.createButton (type.getIcon16x16 (), - String.format (getUIString (assets,add,button,tooltip), - //"Click to add a new %s", - type.getObjectTypeName ()), - null); - - buts.add (but); - - final UserConfigurableObjectType _type = type; - - but.addActionListener (new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - Asset a = null; - - try - { - - a = Asset.createAsset (_type); - - } catch (Exception e) { - - Environment.logError ("Unable to create new asset for object type: " + - _type, - e); - - UIUtils.showErrorMessage (pv, - String.format (getUIString (assets,add,actionerror), - _type.getObjectTypeName ())); - //"Unable to create new asset type."); - - return; - - } - - if (a == null) - { - - Environment.logError ("Unable to create new asset for object type: " + - _type); - - UIUtils.showErrorMessage (pv, - String.format (getUIString (assets,add,actionerror), - _type.getObjectTypeName ())); - //"Unable to create new asset type."); - - return; - - } - - if (name != null) - { - - a.setName (name); - - } - - if (desc != null) - { - - a.setDescription (new StringWithMarkup (desc)); - - } - - AssetActionHandler aah = new AssetActionHandler (a, - pv); - - if (showPopupAt instanceof PopupsSupported) - { - - aah.setPopupOver (pv); - aah.setShowPopupAt (null, - "below"); - - } else - { - - aah.setShowPopupAt (showPopupAt, - "above"); - - } - - aah.actionPerformed (ev); - - } - - }); - - } - - m.add (UIUtils.createPopupMenuButtonBar (null, - m, - buts)); - - } - - public static Color getBorderHighlightColor () - { - - return UIUtils.getColor ("#275C92"); - - } - - public static Color getHintTextColor () - { - - return UIUtils.getColor ("#aaaaaa"); - - } - - public static Color hexToColor (String hexCode) - { - - return UIUtils.getColor (hexCode); - - } - - public static Color getColor (String hexCode) - { - - if (hexCode.startsWith ("#")) - { - - hexCode = hexCode.substring (1); - - } - - hexCode = hexCode.toUpperCase (); - - return new Color (Integer.parseInt (hexCode.substring (0, - 2), - 16), - Integer.parseInt (hexCode.substring (2, - 4), - 16), - Integer.parseInt (hexCode.substring (4), - 16)); - } - - public static String getFrameTitle (String name) - { - - return Environment.replaceObjectNames (name) + Environment.getWindowNameSuffix (); - - } - - public static void setFrameTitle (Frame f, - String name) - { - - f.setTitle (UIUtils.getFrameTitle (name)); - - } - - public static void setFrameTitle (Dialog f, - String name) - { - - f.setTitle (UIUtils.getFrameTitle (name)); - - } - - public static JButton createHelpPageButton (final String helpPage, - final int iconType, - final String helpText) - { - - final JButton helpBut = new JButton (Environment.getIcon ("help", - iconType)); - helpBut.setToolTipText ((helpText != null ? helpText : getUIString (help,button,tooltip))); - //"Click to view the help")); - helpBut.setOpaque (false); - UIUtils.setAsButton (helpBut); - - helpBut.addActionListener (new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - UIUtils.openURL (helpBut, - "help://" + helpPage); - - } - - }); - - return helpBut; - - } - - public static JLabel createWebsiteLabel (final String website, - final String display, - final boolean useLabelText) - { - - final JLabel web = new JLabel (String.format ("%s", - Environment.replaceObjectNames (((display == null) ? website : display)))) - { - - @Override - public void setText (String t) - { - - if (!this.getText ().equals ("")) - { - - throw new IllegalStateException ("Once set the website label text cannot be modified."); - - } - - super.setText (t); - - } - - }; - - // web.setEditable (false); - web.setOpaque (false); - web.setBorder (null); - web.setForeground (new Color (112, - 149, - 226)); - UIUtils.setAsButton (web); - - web.addMouseListener (new MouseEventHandler () - { - - @Override - public void mouseEntered (MouseEvent ev) - { - - Map attrs = new HashMap (); - attrs.put (TextAttribute.UNDERLINE, - TextAttribute.UNDERLINE_LOW_ONE_PIXEL); - - web.setFont (web.getFont ().deriveFont (attrs)); - - } - - @Override - public void mouseExited (MouseEvent ev) - { - - Map attrs = new HashMap (); - attrs.put (TextAttribute.UNDERLINE, - null); - - web.setFont (web.getFont ().deriveFont (attrs)); - - } - - @Override - public void handlePress (MouseEvent ev) - { - - String w = website; - - if (useLabelText) - { - - w = web.getText (); - - } - - if ((w == null) || - (w.trim ().equals (""))) - { - - return; - - } - - if ((!w.toLowerCase ().startsWith ("http://")) && - (!w.toLowerCase ().startsWith ("https://"))) - { - - w = "http://" + w; - - } - - try - { - - UIUtils.openURL (web, - w); - - } catch (Exception e) - { - - Environment.logError ("Unable to visit website: " + - w, - e); - - } - - } - - }); - - return web; - - } - - public static JLabel createClickableLabel (String title, - Icon icon) - { - - String ns = null; - - return UIUtils.createClickableLabel (title, - icon, - ns); - - } - - public static JLabel createClickableLabel (final String title, - final Icon icon, - final String gotoURLOnClick) - { - - return UIUtils.createClickableLabel (title, - icon, - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - if (gotoURLOnClick != null) - { - - UIUtils.openURL (null, - gotoURLOnClick); - - } - - } - - }); - - } - - public static void makeClickable (final JLabel l, - final ActionListener onClick) - { - - l.addMouseListener (new MouseEventHandler () - { - - @Override - public void handlePress (MouseEvent ev) - { - - if (onClick != null) - { - - try - { - - onClick.actionPerformed (new ActionEvent (l, 1, "clicked")); - - } catch (Exception e) { - - Environment.logError ("Unable to perform action", - e); - - } - - } - - } - - }); - - l.setCursor (Cursor.getPredefinedCursor (Cursor.HAND_CURSOR)); - - } - - public static JLabel createClickableLabel (final String title, - final Icon icon, - final ActionListener onClick) - { - - final JLabel l = new JLabel (null, - icon, - SwingConstants.LEFT) - { - - @Override - public void setText (String t) - { - - if (t == null) - { - - super.setText (null); - - return; - - } - - super.setText (String.format ("%s", - Environment.replaceObjectNames (t))); - - } - - @Override - public void setToolTipText (String t) - { - - if (t == null) - { - - super.setToolTipText (null); - - return; - - } - - super.setToolTipText (String.format ("%s", - Environment.replaceObjectNames (t))); - - } - - }; - - l.setText (title); - l.setForeground (UIUtils.getColor (Constants.HTML_LINK_COLOR)); - l.setCursor (Cursor.getPredefinedCursor (Cursor.HAND_CURSOR)); - l.setVerticalAlignment (SwingConstants.TOP); - l.setVerticalTextPosition (SwingConstants.TOP); - UIUtils.makeClickable (l, - onClick); - - return l; - - } - - public static JLabel createLabel (final String title, - final Icon icon, - final ActionListener onClick) - { - - final JLabel l = new JLabel (null, - icon, - SwingConstants.LEFT) - { - - @Override - public void setText (String t) - { - - if (t == null) - { - - super.setText (null); - - return; - - } - - super.setText (String.format ("%s", - t)); - - } - - @Override - public void setToolTipText (String t) - { - - if (t == null) - { - - super.setToolTipText (null); - - return; - - } - - super.setToolTipText (t); - - } - - }; - - l.setText (title); - - if (onClick != null) - { - - l.setCursor (Cursor.getPredefinedCursor (Cursor.HAND_CURSOR)); - UIUtils.makeClickable (l, - onClick); - - } - - l.setVerticalAlignment (SwingConstants.TOP); - l.setVerticalTextPosition (SwingConstants.TOP); - - return l; - - } - - public static int getA4PageCountForChapter (Chapter c, - String text) - { - - if ((text == null) - || - (text.trim ().length () == 0) - ) - { - - return 0; - - } - - // Create a new editor. - QTextEditor ed = UIUtils.wordCountPerPageEditor; -/* - QTextEditor ed = new QTextEditor (null, - false); - */ - ed.setSectionBreak (Constants.SECTION_BREAK); - - ed.setLineSpacing (c.getPropertyAsFloat (Constants.EDITOR_LINE_SPACING_PROPERTY_NAME)); - ed.setFontSize ((int) (UIUtils.getEditorFontSize (c.getPropertyAsInt (Constants.EDITOR_FONT_SIZE_PROPERTY_NAME)))); - ed.setFontFamily (c.getProperty (Constants.EDITOR_FONT_PROPERTY_NAME)); - ed.setAlignment (c.getProperty (Constants.EDITOR_ALIGNMENT_PROPERTY_NAME)); - - ed.setTextWithMarkup (new StringWithMarkup (text)); - - int ppi = java.awt.Toolkit.getDefaultToolkit ().getScreenResolution (); - - // A4 - 17cm wide, 25.7cm high. - // 6.7" wide, 10.12" high - - float pageHeight = 10.12f; - float pageWidth = 6.7f; - - ed.setSize (new Dimension ((int) (pageWidth * ppi), - Integer.MAX_VALUE)); - - ed.setSize (new Dimension ((int) (pageWidth * ppi), - ed.getPreferredSize ().height)); - - // Get the height, divide by the page size. - int a4PageCount = (int) (ed.getHeight () / (pageHeight * ppi)); - - if (ed.getHeight () > (pageHeight * ppi * a4PageCount)) - { - - a4PageCount++; - - } - - /* - *standard pages count - - ed.setSize (new Dimension (4 * ppi, - ed.getPreferredSize ().height)); - - int standardPageCount = ed.getHeight () / (4 * ppi); - - if (ed.getHeight () > (6.5f * ppi * standardPageCount)) - { - - standardPageCount++; - - } - */ - - return a4PageCount; - - } - - public static JScrollPane createScrollPane (JComponent c, - boolean addTopBorderOnScroll) - { - - final JScrollPane sp = new JScrollPane (c); - sp.setOpaque (true); - sp.getViewport ().setBackground (UIUtils.getComponentColor ()); - sp.setBackground (UIUtils.getComponentColor ()); - sp.setAlignmentX (Component.LEFT_ALIGNMENT); - sp.getVerticalScrollBar ().setUnitIncrement (DEFAULT_SCROLL_BY_AMOUNT); - - // Ease of use thing since you want all tables to scroll on rows. - if (c instanceof JTable) - { - - sp.getVerticalScrollBar ().setUnitIncrement (((JTable) c).getRowHeight ()); - sp.getVerticalScrollBar ().setBlockIncrement (1); - - } - - if (addTopBorderOnScroll) - { - - final Border defBorder = UIUtils.createPadding (1, 0, 0, 0); - - final Border scrollBorder = new MatteBorder (1, 0, 0, 0, - UIUtils.getInnerBorderColor ()); - - sp.setBorder (defBorder); - - sp.getVerticalScrollBar ().addAdjustmentListener (new AdjustmentListener () - { - - public void adjustmentValueChanged (AdjustmentEvent ev) - { - - if (sp.getVerticalScrollBar ().getValue () > 0) - { - - sp.setBorder (scrollBorder); - - } else { - - sp.setBorder (defBorder); - - } - - } - - }); - - } else { - - sp.setBorder (UIUtils.createLineBorder ()); - - } - - return sp; - - } - - public static JScrollPane createScrollPane (JComponent c) - { - - return UIUtils.createScrollPane (c, - false); - - } - - public static JScrollPane createScrollPane (final JTree c) - { - - return UIUtils.createScrollPane (c, - -1); - - } - - public static JScrollPane createScrollPane (final JTree c, - final int maxHeight) - { - - JScrollPane sp = new JScrollPane (c) - { - - public Dimension getPreferredSize () - { - - Dimension d = c.getPreferredSize (); - - if (maxHeight > 0) - { - - if (d.height > maxHeight) - { - - d.height = maxHeight; - - } - - } - - return d; - - } - - }; - - //JScrollPane sp = new JScrollPane (c); - sp.setOpaque (true); - sp.getViewport ().setBackground (UIUtils.getComponentColor ()); - sp.setBackground (UIUtils.getComponentColor ()); - sp.setBorder (UIUtils.createLineBorder ()); - sp.setAlignmentX (Component.LEFT_ALIGNMENT); - sp.getVerticalScrollBar ().setUnitIncrement (DEFAULT_SCROLL_BY_AMOUNT); - - return sp; - - } - - public static JScrollPane createScrollPane (JTextComponent t) - { - - JScrollPane sp = new JScrollPane (t); - sp.setOpaque (false); - - sp.setBorder (new JScrollPane ().getBorder ()); - - t.setMargin (new Insets (3, - 3, - 3, - 3)); - sp.setAlignmentX (Component.LEFT_ALIGNMENT); - - sp.getVerticalScrollBar ().setUnitIncrement (DEFAULT_SCROLL_BY_AMOUNT); - - return sp; - - } - - public static JSplitPane createSplitPane (int orientation) - { - - JSplitPane sp = new JSplitPane (orientation, - false); - sp.setDividerSize (4);//UIUtils.getSplitPaneDividerSize () + 4); - - sp.setUI (new BasicSplitPaneUI () - { - - public BasicSplitPaneDivider createDefaultDivider () - { - - // Probably going to hell for this... - final AtomicBoolean highlight = new AtomicBoolean (false); - - final BasicSplitPaneDivider div = new BasicSplitPaneDivider (this) - { - - @Override - public void paint (Graphics g) - { - - if (highlight.get ()) - { - - g.setColor (UIUtils.getBorderColor ()); - - } else { - - g.setColor(new Color (0, 0, 0, 0)); - - } - - g.fillRect(0, 0, getSize().width, getSize().height); - super.paint (g); - - } - - }; - - div.addMouseListener (new MouseEventHandler () - { - - @Override - public void mouseEntered (MouseEvent ev) - { - - if (UserProperties.getAsBoolean (Constants.HIGHLIGHT_SPLITPANE_DIVIDERS_PROPERTY_NAME)) - { - - highlight.set (true); - div.validate (); - div.repaint (); - - } - - } - - @Override - public void mouseExited (MouseEvent ev) - { - - highlight.set (false); - div.validate (); - div.repaint (); - - } - - @Override - public void mouseReleased (MouseEvent ev) - { - - highlight.set (false); - div.validate (); - div.repaint (); - - } - - }); - - div.addMouseMotionListener (new MouseEventHandler () - { - - @Override - public void mouseDragged (MouseEvent ev) - { - - if (UserProperties.getAsBoolean (Constants.HIGHLIGHT_SPLITPANE_DIVIDERS_PROPERTY_NAME)) - { - - highlight.set (true); - div.validate (); - div.repaint (); - - } - - } - - }); - - return div; - - } - - }); - - sp.setBorder (null); - sp.setOpaque (false); - sp.setContinuousLayout (true); - - return sp; - - } - - public static JTextField createTextField () - { - - JTextField f = new JTextField (); - f.setAlignmentX (JComponent.LEFT_ALIGNMENT); - f.setBorder (new JScrollPane ().getBorder ()); - f.setMargin (new Insets (3, - 3, - 3, - 3)); - - return f; - - } - - public static JPasswordField createPasswordField () - { - - JPasswordField f = new JPasswordField (); - f.setAlignmentX (JComponent.LEFT_ALIGNMENT); - f.setBorder (new JScrollPane ().getBorder ()); - f.setMargin (new Insets (3, - 3, - 3, - 3)); - - return f; - - } - - public static JComponent createOpaqueGlue (int dir) - { - - JComponent c = null; - - if (dir == BoxLayout.Y_AXIS) - { - - c = (JComponent) Box.createVerticalGlue (); - - } else { - - c = (JComponent) Box.createHorizontalGlue (); - - } - - c.setOpaque (true); - c.setBackground (UIUtils.getComponentColor ()); - - return c; - - } - - /** - * Create a text area with the specified placeholder for the number of rows and max chars. The - * dictionary and synonym providers from the passed in viewer are used. - * - * @param pv The project viewer. - * @param placeholder The placeholder text. - * @param rows The number of rows of text. - * @param maxChars The maximum number of characters allowed. - * @returns The text area. - */ - public static TextArea createTextArea (AbstractProjectViewer pv, - String placeholder, - int rows, - int maxChars) - { - - TextArea t = new TextArea (placeholder, - rows, - maxChars); - t.setDictionaryProvider (pv.getDictionaryProvider ()); - t.setSpellCheckEnabled (pv.isSpellCheckingEnabled ()); - - try - { - - t.setSynonymProvider (pv.getSynonymProvider ()); - - } catch (Exception e) { - - Environment.logError ("Unable to set synonym provider.", - e); - - } - - return t; - - } - - /** - * Create a text area with the specified placeholder for the number of rows and max chars. The - * default dictionary provider from Environment.getDefaultDictionaryProvider is used and a - * synonym provider with null language is also used. - * - * @param placeholder The placeholder text. - * @param rows The number of rows of text. - * @param maxChars The maximum number of characters allowed. - * @returns The text area. - */ - public static TextArea createTextArea (String placeholder, - int rows, - int maxChars) - { - - TextArea t = new TextArea (placeholder, - rows, - maxChars); - - try - { - - t.setDictionaryProvider (Environment.getDefaultDictionaryProvider ()); - t.setSpellCheckEnabled (true); - - } catch (Exception e) { - - Environment.logError ("Unable to set dictionary provider", - e); - - } - - try - { - - t.setSynonymProvider (Environment.getSynonymProvider (null)); - - } catch (Exception e) { - - Environment.logError ("Unable to set synonym provider.", - e); - - } - - return t; - - } - - public static JComponent createPopupMenuButtonBar (String title, - final JPopupMenu parent, - List buttons) - { - - ActionListener aa = new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - parent.setVisible (false); - - } - - }; - - for (JComponent but : buttons) - { - - if (but instanceof JButton) - { - - JButton b = (JButton) but; - - b.addActionListener (aa); - - } - - } - - Box b = new Box (BoxLayout.X_AXIS); - - // This is to get around the "icon space" in the menu. - b.add (Box.createHorizontalStrut (32)); - - if (title == null) - { - - title = ""; - - } - - JLabel l = new JLabel (Environment.replaceObjectNames (title)); - - l.setForeground (UIUtils.getColor ("#444444")); - l.setFont (l.getFont ().deriveFont (Font.ITALIC)); - - l.setPreferredSize (new Dimension (Math.max (50, l.getPreferredSize ().width), - l.getPreferredSize ().height)); - - b.add (l); - - b.add (Box.createHorizontalStrut (10)); - - b.add (UIUtils.createButtonBar (buttons)); - - b.add (Box.createHorizontalGlue ()); - - return b; - - } - - public static JPanel createButtonBar2 (JButton[] buts, - float alignment) - { - - ButtonBarBuilder bb = ButtonBarBuilder.create (); - - if (buts == null) - { - - return bb.build (); - - } - - if ((alignment == Component.RIGHT_ALIGNMENT) - || - (alignment == Component.CENTER_ALIGNMENT) - ) - { - - bb.addGlue (); - - } - - bb.addButton (buts); - - if (alignment == Component.CENTER_ALIGNMENT) - { - - bb.addGlue (); - - } - - bb.opaque (false); - - JPanel p = bb.build (); - - p.setAlignmentX (Component.LEFT_ALIGNMENT); - - return p; - - } - - public static JToolBar createButtonBar (List buttons) - { - - JToolBar tb = new JToolBar (); - tb.setOpaque (false); - tb.setFloatable (false); - tb.setRollover (true); - tb.setBackground (new Color (0, - 0, - 0, - 0)); - - for (int i = 0; i < buttons.size (); i++) - { - - JComponent b = buttons.get (i); - - UIUtils.setAsButton2 (b); - tb.add (b); - - } - - tb.setBackground (null); - tb.setAlignmentX (Component.LEFT_ALIGNMENT); - tb.setBorder (null); - - return tb; - - } - - public static JButton createButton (ImageIcon icon) - { - - return UIUtils.createButton (icon, - null, - null); - - } - - public static JButton createButton (ImageIcon icon, - String toolTipText, - ActionListener action) - { - - JButton b = new JButton (icon); - - b.setFocusPainted (false); - b.setToolTipText (toolTipText); - b.setOpaque (false); - UIUtils.setAsButton (b); - - if (action != null) - { - - b.addActionListener (action); - - } - - return b; - - } - - public static JButton createButton (String icon, - int iconType, - String toolTipText, - ActionListener action) - { - - return UIUtils.createButton (Environment.getIcon (icon, - iconType), - toolTipText, - action); - - } - - public static JButton createButton (String label, - String icon) - { - - JButton b = new JButton (Environment.getButtonLabel (label), - (icon == null ? null : Environment.getIcon (icon, - Constants.ICON_MENU))); - - return b; - - } - - public static JButton createButton (String label) - { - - return UIUtils.createButton (label, - (String) null); - - } - - public static JButton createButton (String label, - ActionListener onClick) - { - - JButton b = UIUtils.createButton (label, - (String) null); - - if (onClick != null) - { - - b.addActionListener (onClick); - - } - - return b; - - } - - public static void treeChanged (DataObject d, - JTree tree) - { - - DefaultTreeModel model = (DefaultTreeModel) tree.getModel (); - - DefaultMutableTreeNode node = (DefaultMutableTreeNode) UIUtils.getTreePathForUserObject ((DefaultMutableTreeNode) model.getRoot (), - d).getLastPathComponent (); - - model.nodeStructureChanged (node); - - } - - public static void informTreeOfNodeChange (NamedObject n, - JTree tree) - { - - DefaultTreeModel model = (DefaultTreeModel) tree.getModel (); - - DefaultMutableTreeNode node = (DefaultMutableTreeNode) UIUtils.getTreePathForUserObject ((DefaultMutableTreeNode) model.getRoot (), - n).getLastPathComponent (); - - model.nodeChanged (node); - - } - - public static String formatPrompt (Prompt p) - { - - if (p == null) - { - - return getUIString (warmups,prompt,view,unavailable); - //"Prompt no longer available. Usually this is due to it's removal at the request of the author."; - - } - - String link = ""; - - if (p.isUserPrompt ()) - { - - link = getUIString (warmups,prompt,view,ownprompt); - //"by You"; - - } else - { - - link = String.format (getUIString (warmups,prompt,view, LanguageStrings.link), - //"%s by %s", - p.getURL (), - p.getStoryName (), - p.getAuthor ()); - - } - - return p.getText () + "
    - " + link; - - - } - - public static Font getHeaderFont () - { - - if (UIUtils.headerFont == null) - { - - UIUtils.headerFont = new JLabel ("").getFont ().deriveFont (Font.BOLD, - 16); - - } - - return UIUtils.headerFont; - - } - - public static float getScaledFontSize (int v) - { - - // Ugh, assume a 96 dpi and let the underlying windows manager handle scaling. - // We return a float here so that calls to Font.deriveFont can use the value directly rather than - // having to cast. - return (float) (Math.round ((float) v * ((float) DEFAULT_ASSUMED_SCREEN_RESOLUTION / 72f))); - - } - - @Deprecated - /** - * Use UIUtils.getScaledFontSize instead. - */ - public static float scaleToScreenSize (double h) - { - - // Ugh, assume a 96 dpi and let the underlying windows manager handle scaling. - return UIUtils.getScaledFontSize ((int) h); - - } - - public static int getPrintFontSize () - { - - return UIUtils.getPrintFontSize (new JLabel ().getFont ().getSize ()); - - } - - public static int getPrintFontSize (int size) - { - - return Math.round ((float) size / ((float) java.awt.Toolkit.getDefaultToolkit ().getScreenResolution () / 72f)); - - } - - public static int getEditorFontSize (int size) - { - - // Need to take the screen resolution into account. - float s = (float) size * ((float) java.awt.Toolkit.getDefaultToolkit ().getScreenResolution () / 72f); - - return (int) s; - - } - - public static boolean isChildOf (MouseEvent ev, - Component parent) - { - - return UIUtils.isChildOf ((Component) ev.getSource (), - parent); - - } - - public static boolean isChildOf (Component child, - Component parent) - { - - Container p = child.getParent (); - - while (p != null) - { - - if (p == parent) - { - - return true; - - } - - p = p.getParent (); - - } - - return false; - - } - - public static ImageIcon getColoredIcon (String name, - int type, - Color c) - { - - ImageIcon ic = Environment.getIcon (name, - type); - - if (ic == null) - { - - return null; - - } - - return UIUtils.getColoredIcon (ic.getImage (), - c); - - } - - public static ImageIcon getColoredIcon (Image im, - Color c) - { - - if (im == null) - { - - return null; - - } - - final int crgb = c.getRGB (); - - ImageFilter filter = new RGBImageFilter() - { - public final int filterRGB(int x, int y, int rgb) - { - if (rgb != 0) - { - - } - return (rgb != 0 ? crgb : rgb); - - } - }; - - ImageProducer ip = new FilteredImageSource (im.getSource (), filter); - return new ImageIcon (Toolkit.getDefaultToolkit().createImage(ip)); - - } - - public static Image replaceColorInImage (Image im, - Color orig, - Color changeTo) - { - - if (im == null) - { - - return null; - - } - - final int orgb = orig.getRGB (); - final int crgb = changeTo.getRGB (); - - ImageFilter filter = new RGBImageFilter() - { - public final int filterRGB(int x, int y, int rgb) - { - if (rgb != 0) - { - - } - - return (rgb == orgb ? crgb : rgb); - - } - }; - - ImageProducer ip = new FilteredImageSource (im.getSource (), filter); - return Toolkit.getDefaultToolkit().createImage (ip); - - } - - public static Color getIconColumnColor () - { - - return UIUtils.getColor ("#f0f0f0");//"f5fcfe"); - - } - - public static int getSplitPaneDividerSize () - { - - return 2; - - } - - public static Color getTitleColor () - { - - return UIUtils.getColor ("#333333"); - - } - - public static Color getInnerBorderColor () - { - - return UIUtils.getColor ("#dddddd"); - - } - - public static Color getDragIconColor () - { - - return UIUtils.getColor ("#aaaaaa"); - - } - - public static Color getBorderColor () - { - - return UIUtils.getColor ("#aaaaaa"); - - } - - public static Color getComponentColor () - { - - return UIUtils.getColor ("#fdfdfd"); - - } - - public static boolean clipboardHasContent () - { - - try - { - - return (Toolkit.getDefaultToolkit ().getSystemClipboard ().getData (DataFlavor.stringFlavor) != null); - - } catch (Exception e) - { - - } - - return false; - - } - - /** - * Draw a string on the image at a specified "location", supported values for where are: - * - tl - draw the string starting at the top left corner. - * - bl - bottom left corner. - * - tr - top right corner. (so start the text in from the right) - * - br - bottom right corner (start, in from the right and bottom) - * - * @param im The image to draw on, this image is untouched. - * @param text The text to draw on the image. - * @param font The font to use. - * @param color The color to use. - * @param where Where the text should be drawn. - * @returns A new image with the text drawn on top of im. - */ - public static BufferedImage drawStringOnImage (BufferedImage im, - String text, - Font font, - Color color, - String where) - { - - FontMetrics m = im.getGraphics ().getFontMetrics (font); - - int sh = m.getHeight (); - int sw = m.stringWidth (text); - - int imw = im.getWidth (); - int imh = im.getHeight (); - - int nw = 0; - int nh = 0; - - Point w = null; - - if (where.equals ("tr")) - { - - nw = imw - sw; - nh = sh; - - } - - if (where.equals ("bl")) - { - - nh = imh - sh; - - } - - if (where.equals ("br")) - { - - nh = imh;// - sh; - nw = imw - sw; - - } - - return UIUtils.drawStringOnImage (im, - text, - font, - color, - new Point (nw, nh)); - - } - - public static BufferedImage getImageOfComponent (Component c, - int width, - int height) - { - - width = (width > 0 ? width : c.getWidth ()); - height = (height > 0 ? height : c.getHeight ()); - - BufferedImage image = new BufferedImage (width, - height, - BufferedImage.TYPE_INT_ARGB_PRE); - - Graphics2D g = (Graphics2D) image.getGraphics (); - - RenderingHints rh = new RenderingHints( - RenderingHints.KEY_TEXT_ANTIALIASING, - RenderingHints.VALUE_TEXT_ANTIALIAS_ON); - g.setRenderingHints(rh); - - if (c.isOpaque ()) - { - - g.setColor (c.getBackground ()); - - g.fillRect (0, - 0, - width, - height); - - } - - c.paint (g); - - return image; - - } - - public static BufferedImage copyImage (BufferedImage im) - { - - BufferedImage b = new BufferedImage (im.getWidth (), - im.getHeight (), - im.getType ()); - Graphics g = b.getGraphics (); - g.drawImage (im, - 0, - 0, - null); - g.dispose (); - - return b; - - } - - /** - * Draw a string onto an image at the specified point (where). - * - * @param im The image to draw onto. - * @param text The text to draw. - * @param font The font to use. - * @param color The color to use. - * @param where Where to draw the text. - * @returns A new image with the text overlaid on the image. - */ - public static BufferedImage drawStringOnImage (BufferedImage im, - String text, - Font font, - Color color, - Point where) - { - - BufferedImage newIm = UIUtils.copyImage (im); - - Graphics2D g = (Graphics2D) newIm.getGraphics (); - - g.setFont (font); - - g.setRenderingHint (RenderingHints.KEY_TEXT_ANTIALIASING, - RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB); - - g.setColor (color); - - FontMetrics fm = g.getFontMetrics (); - - java.awt.geom.Rectangle2D b = g.getFontMetrics ().getStringBounds (text, - g); - - g.drawString (text, - where.x, - (int) (where.y + b.getHeight ())); - - return newIm; - - } - - public static BufferedImage getBufferedImage (Image im, - Component io) - { - - if (im == null) - { - - return null; - - } - - int height = im.getHeight (io); - int width = im.getWidth (io); - - BufferedImage bi = new BufferedImage (width, - height, - BufferedImage.TYPE_INT_ARGB); - Graphics g = bi.getGraphics (); - g.drawImage (im, - 0, - 0, - Color.black, - io); - - return bi; - - } - - public static BufferedImage getScaledImage (DataSource ds, - int width, - int height) - { - - try - { - - return UIUtils.getScaledImage (ImageIO.read (ds.getInputStream ()), - width, - height); - - } catch (Exception e) { - - Environment.logError ("Unable to read image from data source: " + ds, - e); - - return null; - - } - - } - - public static BufferedImage getImage (byte[] bytes) - throws GeneralException - { - - if (bytes == null) - { - - return null; - - } - - try - { - - return ImageIO.read (new ByteArrayInputStream (bytes)); - - } catch (Exception e) { - - throw new GeneralException ("Unable to convert bytes to an image", - e); - - } - - } - - public static byte[] getImageBytes (BufferedImage im) - throws GeneralException - { - - if (im == null) - { - - return null; - - } - - try - { - - ByteArrayOutputStream bout = new ByteArrayOutputStream (); - - // Shouldn't use png here, it is too slow. - if (!ImageIO.write (im, - "png", - bout)) - { - - throw new GeneralException ("Unable to write image using png"); - - } - - bout.flush (); - bout.close (); - return bout.toByteArray (); - - } catch (Exception e) { - - throw new GeneralException ("Unable to get bytes for image", - e); - - } - - } - - public static BufferedImage getImage (File f) - { - - if (f == null) - { - - return null; - - } - - try - { - - return ImageIO.read (f); - - } catch (Exception e) { - - Environment.logError ("Unable to find image for file: " + f, - e); - - return null; - - } - - } - - public static BufferedImage getScaledImage (File f, - int width, - int height) - { - - return UIUtils.getScaledImage (UIUtils.getImage (f), - width, - height); - - } - - public static BufferedImage getScaledImage (File f, - int width) - { - - return UIUtils.getScaledImage (UIUtils.getImage (f), - width); - - } - - public static BufferedImage getScaledImage (BufferedImage img, - int targetWidth) - { - - if (img == null) - { - - return null; - - } - - return Scalr.resize (img, - Scalr.Method.QUALITY, - Scalr.Mode.FIT_TO_WIDTH, - targetWidth, - Scalr.OP_ANTIALIAS); - - } - - public static BufferedImage createBufferedImage (int width, - int height) - { - - BufferedImage im = new BufferedImage (width, - height, - BufferedImage.TYPE_INT_ARGB); - - Graphics2D g = im.createGraphics (); - - g.setBackground (new Color (0, true)); - g.clearRect (0, 0, width, height); - - g.dispose (); - - return im; - - } - - public static Graphics2D createThrowawayGraphicsInstance () - { - - return new BufferedImage (1, 1, BufferedImage.TYPE_INT_ARGB).createGraphics (); - - } - - public static BufferedImage iconToImage(Icon icon) - { - - if (icon == null) - { - - return null; - - } - - if (icon instanceof ImageIcon) - { - - return (BufferedImage) ((ImageIcon)icon).getImage(); - - } else { - - int w = icon.getIconWidth(); - int h = icon.getIconHeight(); - GraphicsEnvironment ge = - GraphicsEnvironment.getLocalGraphicsEnvironment(); - GraphicsDevice gd = ge.getDefaultScreenDevice(); - GraphicsConfiguration gc = gd.getDefaultConfiguration(); - BufferedImage image = gc.createCompatibleImage(w, h); - Graphics2D g = image.createGraphics(); - icon.paintIcon(null, g, 0, 0); - g.dispose(); - return image; - - } - - } - - public static BufferedImage getScaledImage (BufferedImage img, - int targetWidth, - int targetHeight) - { - - return Scalr.resize (img, - Scalr.Method.QUALITY, - Scalr.Mode.FIT_EXACT, - (targetWidth > 0 ? targetWidth : img.getWidth ()), - (targetHeight > 0 ? targetHeight : img.getHeight ()), - Scalr.OP_ANTIALIAS); -/* - BufferedImage tmp = new BufferedImage (targetWidth, targetHeight, BufferedImage.TYPE_INT_ARGB); - Graphics2D g2 = tmp.createGraphics(); - g2.setRenderingHint (RenderingHints.KEY_RENDERING, - RenderingHints.VALUE_RENDER_QUALITY); - g2.drawImage(img, 0, 0, targetWidth, targetHeight, null); - g2.dispose(); - - return tmp; - */ - } - - public static ImageIcon overlayImage (ImageIcon bg, - ImageIcon fg, - String where) - { - - JButton but = new JButton (); - - Image bgi = bg.getImage (); - Image fgi = fg.getImage (); - - BufferedImage n = new BufferedImage (bgi.getWidth (but), - bgi.getHeight (but), - BufferedImage.TYPE_INT_ARGB); - - Graphics2D g = n.createGraphics (); - g.setRenderingHint (RenderingHints.KEY_ANTIALIASING, - RenderingHints.VALUE_ANTIALIAS_ON); - - g.drawImage (bgi, - 0, - 0, - null); - - if (where.equals ("tl")) - { - - g.drawImage (fgi, - 0, - 0, - null); - - } - - if (where.equals ("tr")) - { - - g.drawImage (fgi, - bgi.getWidth (but) - fgi.getWidth (but), - 0, - null); - - } - - if (where.equals ("bl")) - { - - g.drawImage (fgi, - 0, - bgi.getHeight (but) - fgi.getHeight (but), - null); - - } - - if (where.equals ("br")) - { - - g.drawImage (fgi, - bgi.getWidth (but) - fgi.getWidth (but), - bgi.getHeight (but) - fgi.getHeight (but), - null); - - } - - g.dispose (); - - //bg.setImage (bgi); - - return new ImageIcon (n); - - } - - public static FileFinder createFileFind (final String initPath, - final String finderTitle, - final int fileSelectionMode, - final String approveButtonText, - final ActionListener handler) - { - - FileFinder ff = new FileFinder (); - - ff.setOnSelectHandler (handler); - ff.setApproveButtonText (approveButtonText); - ff.setFinderSelectionMode (fileSelectionMode); - ff.setFinderTitle (finderTitle); - - ff.init (); - - if (initPath != null) - { - - ff.setFile (new File (initPath)); - - } - - return ff; - - } - - public static Component getComponentByName (Container parent, - String name) - { - - if (name == null) - { - - return null; - - } - - if (parent == null) - { - - return null; - - } - - Component[] children = parent.getComponents (); - - for (int i = 0; i < children.length; i++) - { - - if (name.equals (children[i].getName ())) - { - - return children[i]; - - } - - } - - return null; - - } - - public static JMenuItem createMenuItem (String label, - String icon, - ActionListener action) - { - - JMenuItem mi = new JMenuItem (Environment.getButtonLabel (label), - Environment.getIcon (icon, - Constants.ICON_MENU)); - mi.addActionListener (action); - - return mi; - - } - - public static JMenuItem createMenuItem (String label, - ImageIcon icon, - ActionListener action) - { - - JMenuItem mi = new JMenuItem (Environment.getButtonLabel (label), - icon); - mi.addActionListener (action); - - return mi; - - } - - public static JMenuItem createMenuItem (String label, - String icon, - ActionListener action, - String actionCommand, - KeyStroke accel) - { - - JMenuItem mi = UIUtils.createMenuItem (label, - icon, - action); - - mi.setActionCommand (actionCommand); - mi.setAccelerator (accel); - - return mi; - - } - - public static void listenToTableForCellChanges (JTable table, - Action action) - { - - // Shouldn't be cleaned up since it adds itself as a property listener to the table. - new TableCellListener (table, - action); - - } - - public static boolean isAnimatedGif (File f) - { - - String type = Utils.getFileType (f); - - if (f == null) - { - - throw new IllegalArgumentException ("Unable to determine file type for file: " + - f); - - } - - int c = 0; - - ImageReader r = null; - - r = ImageIO.getImageReadersBySuffix (type).next (); - - if (r == null) - { - - throw new IllegalArgumentException ("Unsupported file type for file: " + - f); - - } - - try - { - - r.setInput (ImageIO.createImageInputStream (f)); - - } catch (Exception e) { - - throw new IllegalArgumentException ("Unable to read image file: " + - f, - e); - - } - - try - { - - int ind = 0; - - // Upper bound valid? - while (ind < 100) - { - - if (c > 1) - { - - return true; - - } - - r.read (ind); - - ind++; - c++; - - } - - } catch (Exception e) { - - } - - return false; - - } - - public static void doActionWhenPanelIsReady (final QuollPanel p, - final ActionListener action, - final Object contextObject, - final String actionTypeName) - { - - final Exception pe = new Exception (); - - final javax.swing.Timer t = new javax.swing.Timer (100, - null); - - // TODO: Change this to be based on an event that the panel fires when ready. - ActionListener l = new ActionListener () - { - - private int count = 0; - - public void actionPerformed (ActionEvent ev) - { - - if (p.isReadyForUse ()) - { - - t.setRepeats (false); - t.stop (); - - try - { - - action.actionPerformed (new ActionEvent ((contextObject != null ? contextObject : action), - 1, - (actionTypeName != null ? actionTypeName : "any"))); - - } catch (Exception e) { - - Environment.logError ("Unable to perform action: " + action + "\nCause: " + - Utils.getStackTrace (pe), - e); - - } - - return; - - } - - // 2s delay max. - if (count > 50) - { - - Environment.logError ("Unable to perform action: " + action, - new Exception ("Unable to perform action for panel: " + p.getPanelId (), - pe)); - - t.setRepeats (false); - t.stop (); - - } - - count++; - - } - - }; - - t.setRepeats (true); - t.addActionListener (l); - - t.start (); - - } - - public static void doActionLater (final ActionListener action) - { - - UIUtils.doActionLater (action, - null, - null); - - } - - public static void doActionLater (final ActionListener action, - final Object contextObject, - final String actionTypeName) - { - - SwingUtilities.invokeLater (new Runner () - { - - public void run () - { - - try - { - - action.actionPerformed (new ActionEvent ((contextObject != null ? contextObject : action), - 1, - (actionTypeName != null ? actionTypeName : "any"))); - - } catch (Exception e) { - - Environment.logError ("Unable to perform action", - e); - - } - - } - - }); - - } - - public static void addDoActionOnReturnPressed (TextArea text, - ActionListener action) - { - - text.addDoActionOnCtrlReturnPressed (action); - - } - - public static void addDoActionOnReturnPressed (final JTextComponent text, - final ActionListener action) - { - - if (action == null) - { - - return; - - } - - if (text instanceof JTextField) - { - - text.addKeyListener (new KeyAdapter () - { - - public void keyPressed (KeyEvent ev) - { - - if (ev.getKeyCode () == KeyEvent.VK_ENTER) - { - - // This is the same as save for the form. - action.actionPerformed (new ActionEvent (text, - 1, - "return-pressed")); - - } - - } - - }); - - } else { - - text.addKeyListener (new KeyAdapter () - { - - public void keyPressed (KeyEvent ev) - { - - if (((ev.getModifiersEx () & InputEvent.CTRL_DOWN_MASK) == InputEvent.CTRL_DOWN_MASK) && - (ev.getKeyCode () == KeyEvent.VK_ENTER)) - { - - action.actionPerformed (new ActionEvent (text, - 1, - "ctrl-return-pressed")); - - } - - } - - }); - - } - - } - - public static QPopup createQuestionPopup (AbstractViewer viewer, - String title, - String icon, - String message, - String confirmButtonLabel, - String cancelButtonLabel, - final ActionListener onConfirm, - final ActionListener onCancel, - final ActionListener onClose, - Point showAt) - { - - Map buttons = new LinkedHashMap (); - - if (onConfirm != null) - { - - buttons.put (Environment.getButtonLabel (confirmButtonLabel, - getUIString (LanguageStrings.buttons,confirm)), - onConfirm); - - } - - buttons.put (Environment.getButtonLabel (cancelButtonLabel, - getUIString (LanguageStrings.buttons,cancel)), - onCancel); - - return UIUtils.createQuestionPopup (viewer, - title, - icon, - message, - buttons, - onClose, - showAt); - - } - - public static QPopup createQuestionPopup (AbstractViewer viewer, - String title, - String icon, - String message, - Map buttons, - ActionListener onClose, - Point showAt) - { - - JComponent mess = UIUtils.createHelpTextPane (Environment.replaceObjectNames (message), - viewer); - mess.setBorder (null); - mess.setSize (new Dimension (UIUtils.getPopupWidth () - 20, - 500)); - - return UIUtils.createQuestionPopup (viewer, - title, - icon, - mess, - buttons, - onClose, - showAt); - - } - - public static QPopup createQuestionPopup (PopupsSupported viewer, - String title, - String icon, - JComponent mess, - Map buttons, - ActionListener onClose, - Point showAt) - { - - final QPopup qp = UIUtils.createClosablePopup (title, - Environment.getIcon (icon, - Constants.ICON_POPUP), - onClose); - - Box content = new Box (BoxLayout.Y_AXIS); - - content.add (mess); - content.add (Box.createVerticalStrut (10)); - - JButton[] buts = new JButton[buttons.size ()]; - - int i = 0; - - // Too much type information required to do entrySet... - // We will never do much iterating here so simpler and clearer to just do it the "hard way". - Iterator iter = buttons.keySet ().iterator (); - - while (iter.hasNext ()) - { - - String label = iter.next (); - - ActionListener a = buttons.get (label); - - JButton b = UIUtils.createButton (label, - qp.getCloseAction ()); - - if (a != null) - { - - b.addActionListener (a); - - } - - buts[i++] = b; - - } - - JComponent bs = UIUtils.createButtonBar2 (buts, - Component.LEFT_ALIGNMENT); //ButtonBarFactory.buildLeftAlignedBar (buts); - bs.setAlignmentX (Component.LEFT_ALIGNMENT); - content.add (bs); - content.setBorder (new EmptyBorder (10, 10, 10, 10)); - qp.setContent (content); - - content.setPreferredSize (new Dimension (Math.max (UIUtils.getPopupWidth (), bs.getPreferredSize ().width), - content.getPreferredSize ().height)); - - if (showAt == null) - { - - if (viewer instanceof Component) - { - - showAt = UIUtils.getCenterShowPosition ((Component) viewer, - qp); - - } - - } - - viewer.showPopupAt (qp, - showAt, - false); - - if (viewer instanceof Component) - { - - qp.setDraggable ((Component) viewer); - - } - - return qp; - - } - - public static QPopup createHelpPopup (AbstractViewer viewer, - String title, - String text, - ActionListener onClose, - Point showAt) - { - - final QPopup qp = UIUtils.createClosablePopup ((title != null ? title : getUIString (help,popup,title)), - //"Help"), - Environment.getIcon (Constants.HELP_ICON_NAME, - Constants.ICON_POPUP), - onClose); - - Box content = new Box (BoxLayout.Y_AXIS); - - content.add (UIUtils.createHelpTextPane (text, - viewer)); - content.add (Box.createVerticalStrut (10)); - - JButton b = UIUtils.createButton (getUIString (buttons,close)); - - JButton[] buts = { b }; - - JComponent bs = UIUtils.createButtonBar2 (buts, - Component.CENTER_ALIGNMENT); - bs.setAlignmentX (Component.LEFT_ALIGNMENT); - content.add (bs); - content.setBorder (UIUtils.createPadding (10, 10, 10, 10)); - qp.setContent (content); - - content.setPreferredSize (new Dimension (UIUtils.getPopupWidth (), - content.getPreferredSize ().height)); - - if (showAt == null) - { - - if (viewer instanceof Component) - { - - showAt = UIUtils.getCenterShowPosition ((Component) viewer, - qp); - - } - - } - - viewer.showPopupAt (qp, - showAt, - false); - - if (viewer instanceof Component) - { - - qp.setDraggable ((Component) viewer); - - } - - return qp; - - } - - public static QPopup createPasswordInputPopup (final AbstractViewer viewer, - String title, - String icon, - String message, - String confirmButtonLabel, - String cancelButtonLabel, - String initValue, - final ValueValidator validator, - final ActionListener onConfirm, - final ActionListener onCancel, - Point showAt) - { - - return UIUtils.createTextInputPopup (viewer, - title, - icon, - message, - UIUtils.createPasswordField (), - confirmButtonLabel, - cancelButtonLabel, - initValue, - validator, - onConfirm, - onCancel, - showAt); - - } - - public static QPopup createTextInputPopup (final AbstractViewer viewer, - String title, - String icon, - String message, - String confirmButtonLabel, - String cancelButtonLabel, - String initValue, - final ValueValidator validator, - final ActionListener onConfirm, - final ActionListener onCancel, - Point showAt) - { - - return UIUtils.createTextInputPopup (viewer, - title, - icon, - message, - UIUtils.createTextField (), - confirmButtonLabel, - cancelButtonLabel, - initValue, - validator, - onConfirm, - onCancel, - showAt); - - } - - private static QPopup createTextInputPopup (final AbstractViewer viewer, - String title, - String icon, - String message, - JTextField textField, - String confirmButtonLabel, - String cancelButtonLabel, - String initValue, - final ValueValidator validator, - final ActionListener onConfirm, - final ActionListener onCancel, - Point showAt) - { - - final QPopup qp = UIUtils.createPopup (Environment.replaceObjectNames (title), - icon, - null, - true, - onCancel); - - final Box content = new Box (BoxLayout.Y_AXIS); - - JComponent mess = UIUtils.createHelpTextPane (message, - viewer); - mess.setBorder (null); - mess.setSize (new Dimension (UIUtils.getPopupWidth () - 20, - mess.getPreferredSize ().height)); - - content.add (mess); - - content.add (Box.createVerticalStrut (10)); - - final JLabel error = UIUtils.createErrorLabel (getUIString (form,errors,novalue)); - //"Please enter a value."); - - error.setVisible (false); - error.setBorder (UIUtils.createPadding (0, 0, 5, 0)); - - final JTextField text = textField; - - text.setMinimumSize (new Dimension (300, - text.getPreferredSize ().height)); - text.setPreferredSize (new Dimension (300, - text.getPreferredSize ().height)); - text.setMaximumSize (new Dimension (Short.MAX_VALUE, - text.getPreferredSize ().height)); - text.setAlignmentX (Component.LEFT_ALIGNMENT); - - if (initValue != null) - { - - text.setText (initValue); - - } - - error.setAlignmentX (Component.LEFT_ALIGNMENT); - - content.add (error); - content.add (text); - - content.add (Box.createVerticalStrut (10)); - - JButton confirm = null; - JButton cancel = UIUtils.createButton ((cancelButtonLabel != null ? cancelButtonLabel : getUIString (buttons, LanguageStrings.cancel)), - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - if (onCancel != null) - { - - onCancel.actionPerformed (ev); - - } - - qp.removeFromParent (); - - } - - }); - - if (onConfirm != null) - { - - ActionListener confirmAction = new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - if (validator != null) - { - - String mess = validator.isValid (text.getText ().trim ()); - - if (mess != null) - { - - // Should probably wrap this in a - error.setText (mess); - - error.setVisible (true); - - // Got to be an easier way of doing this. - content.setPreferredSize (null); - - content.setPreferredSize (new Dimension (UIUtils.getPopupWidth (), - content.getPreferredSize ().height)); - - viewer.showPopupAt (qp, - qp.getLocation (), - false); - - return; - - } - - } - - onConfirm.actionPerformed (new ActionEvent (text, - 0, - text.getText ().trim ())); - - qp.removeFromParent (); - - } - - }; - - confirm = UIUtils.createButton ((confirmButtonLabel != null ? confirmButtonLabel : getUIString (buttons, LanguageStrings.confirm)), - confirmAction); - - UIUtils.addDoActionOnReturnPressed (text, - confirmAction); - - } - - JButton[] buts = null; - - if (confirm != null) - { - - buts = new JButton[] { confirm, cancel }; - - } else { - - buts = new JButton[] { cancel }; - - } - - JComponent buttons = UIUtils.createButtonBar2 (buts, - Component.LEFT_ALIGNMENT); //ButtonBarFactory.buildLeftAlignedBar (buts); - buttons.setAlignmentX (Component.LEFT_ALIGNMENT); - content.add (buttons); - content.setBorder (UIUtils.createPadding (10, 10, 10, 10)); - qp.setContent (content); - - content.setPreferredSize (new Dimension (UIUtils.getPopupWidth (), - content.getPreferredSize ().height)); - - if (showAt == null) - { - - showAt = UIUtils.getCenterShowPosition (viewer, - qp); - - } - - qp.setDraggable (viewer); - - viewer.showPopupAt (qp, - showAt, - false); - - if (initValue != null) - { - - text.selectAll (); - - } - - text.grabFocus (); - - return qp; - - } - - public static Point getCenterShowPosition (Component parent, - Component show) - { - - Dimension pd = (parent.isShowing () ? parent.getSize () : parent.getPreferredSize ()); - Dimension sd = (show.isShowing () ? show.getSize () : show.getPreferredSize ()); - - return new Point ((pd.width - sd.width) / 2, - (pd.height - sd.height) / 2); - - } - - public static void doLater (ActionListener l) - { - - UIUtils.doLater (l, - null); - - } - - public static void doLater (final ActionListener l, - final Object c) - { - - if (l == null) - { - - return; - - } - - SwingUtilities.invokeLater (new Runnable () - { - - public void run () - { - - try - { - - l.actionPerformed (new ActionEvent ((c != null ? c : this), - 0, - "do")); - - } catch (Exception e) { - - Environment.logError ("Unable to perform action", - e); -/* - if (c instanceof Component) - { - - UIUtils.showErrorMessage ((Component) c, - "Unable to perform action"); - - } -*/ - } - - } - - }); - - - } - - /** - * Set the specified empty border (padding) around the component, this is shorthand for: - * c.setBorder (UIUtils.createPadding (top, left, bottom, right)); - * - * @param c The component to set the border on. - * @param top The top padding. - * @param left The left padding. - * @param bottom The bottom padding. - * @param right The right padding. - */ - public static void setPadding (JComponent c, - int top, - int left, - int bottom, - int right) - { - - c.setBorder (UIUtils.createPadding (top, left, bottom, right)); - - } - - /** - * Is a wrapper for: - * - * new CompoundBorder (new MatteBorder (0, 0, 1, 0, UIUtils.getInnerBorderColor ()), - * UIUtils.createPadding (top, left, bottom, right)); - * - * - * @returns A compound border with an outer line and an inner padding. - */ - public static CompoundBorder createBottomLineWithPadding (int top, - int left, - int bottom, - int right) - { - - return new CompoundBorder (new MatteBorder (0, 0, 1, 0, UIUtils.getInnerBorderColor ()), - UIUtils.createPadding (top, left, bottom, right)); - - } - - /** - * Is a wrapper for: - * - * new CompoundBorder (new MatteBorder (1, 0, 0, 0, UIUtils.getInnerBorderColor ()), - * UIUtils.createPadding (top, left, bottom, right)); - * - * - * @returns A compound border with an outer line and an inner padding. - */ - public static CompoundBorder createTopLineWithPadding (int top, - int left, - int bottom, - int right) - { - - return new CompoundBorder (new MatteBorder (1, 0, 0, 0, UIUtils.getInnerBorderColor ()), - UIUtils.createPadding (top, left, bottom, right)); - - } - - /** - * Is a wrapper for: - * - * new CompoundBorder (new MatteBorder (1, 1, 1, 1, UIUtils.getBorderColor ()), - * UIUtils.createPadding (top, left, bottom, right)); - * - * - * @returns A compound border with an outer line and an inner padding. - */ - public static CompoundBorder createLineBorderWithPadding (int top, - int left, - int bottom, - int right) - { - - return new CompoundBorder (new MatteBorder (1, 1, 1, 1, UIUtils.getBorderColor ()), - UIUtils.createPadding (top, left, bottom, right)); - - } - - public static int getMaxStringLength (Font f, - String... strs) - { - - int maxl = 0; - - java.awt.font.FontRenderContext frc = new java.awt.font.FontRenderContext (new java.awt.geom.AffineTransform (), true, true); - - for (String s : strs) - { - - // We add 1 to prevent issues with half rounding when the cast is performed. - maxl = Math.max ((int) f.getStringBounds (s, - frc).getWidth () + 1, - maxl); - - } - - return maxl; - - } - - public static EmptyBorder createPadding (int top, - int left, - int bottom, - int right) - { - - return new EmptyBorder (top, left, bottom, right); - - } - - public static void closePopupParent (Container parent) - { - - if (parent == null) - { - - return; - - } - - if (parent instanceof QPopup) - { - - ((QPopup) parent).removeFromParent (); - - return; - - } - - UIUtils.closePopupParent (parent.getParent ()); - - } - - public static void resizeParent (final Container parent) - { - - if (parent == null) - { - - return; - - } - - if (parent instanceof QPopup) - { - - ((QPopup) parent).resize (); - - return; - - } - - if (parent instanceof PopupWindow) - { - - ((PopupWindow) parent).resize (); - - return; - - } - - UIUtils.resizeParent (parent.getParent ()); - - } - - public static QPopup createWizardPopup (String title, - String iconType, - ActionListener onClose, - Wizard wizard) - { - - QPopup p = UIUtils.createClosablePopup (title, - (iconType != null ? Environment.getIcon (iconType, Constants.ICON_POPUP) : null), - onClose); - - wizard.init (); - - wizard.setSize (new Dimension (UIUtils.getPopupWidth () - 20, - wizard.getPreferredSize ().height)); - wizard.setBorder (UIUtils.createPadding (10, 10, 10, 10)); - - p.setContent (wizard); - - return p; - - } - - /** - * Return a new value validator that ensures that the word (case-insensitive) "yes" is provided. - * - * @returns The validator. - */ - public static ValueValidator getYesValueValidator () - { - - return new ValueValidator () - { - - public String isValid (String v) - { - - if ((v == null) - || - (!v.trim ().equalsIgnoreCase (getUIString (form,affirmativevalue))) - ) - { - - return getUIString (form,errors,affirmativevalue); - //"Please enter the word Yes below."; - - } - - return null; - - } - - }; - - } - - public static JTextField createSearchBox (final int delay, - final ActionListener onSearch) - { - - final JTextField text = UIUtils.createTextField (); - text.setBorder (new CompoundBorder (UIUtils.createPadding (5, 10, 5, 10), - text.getBorder ())); - - KeyAdapter vis = new KeyAdapter () - { - - private javax.swing.Timer searchT = new javax.swing.Timer (delay, - onSearch); - - public void keyPressed (KeyEvent ev) - { - - this.searchT.setRepeats (false); - this.searchT.stop (); - - // If enter was pressed then search, don't start the timer. - if (ev.getKeyCode () == KeyEvent.VK_ENTER) - { - - if (onSearch != null) - { - - onSearch.actionPerformed (new ActionEvent (text, 1, text.getText ().trim ())); - - } - - - return; - - } - - this.searchT.start (); - - } - - }; - - text.addKeyListener (vis); - text.setMaximumSize (new Dimension (Short.MAX_VALUE, - text.getPreferredSize ().height)); - - text.addMouseListener (new MouseEventHandler () - { - - @Override - public void mouseEntered (MouseEvent ev) - { - - text.grabFocus (); - text.selectAll (); - - } - - }); - - return text; - - } - - public static JComponent showTemporaryNotification (String t, - AbstractProjectViewer parent, - Component showAt, - int showFor) - { - - Box outer = new Box (BoxLayout.Y_AXIS); - - outer.setBorder (QPopup.defaultBorder); - outer.setOpaque (false); - outer.setDoubleBuffered (true); - outer.setMaximumSize (new Dimension (Short.MAX_VALUE, - Short.MAX_VALUE)); - Box inner = new Box (BoxLayout.Y_AXIS); - inner.setBackground (UIUtils.getComponentColor ()); - inner.setOpaque (true); - - inner.setBorder (UIUtils.createPadding (5, 5, 5, 5)); - - JTextPane m = UIUtils.createHelpTextPane (t, - parent); - m.setSize (new Dimension (150 - 20, - m.getPreferredSize ().height)); - - inner.add (m); - - outer.add (inner); - - parent.showPopupAt (outer, - showAt, - false); - - return outer; - - } - - public static javax.swing.Timer createCyclicAnimator (final PropertyChangeListener cycleUp, - final PropertyChangeListener cycleDown, - final int fps, - final int duration, - final int startValue, - final int endValue, - final int repeatCount, - final ActionListener onComplete) - { - - final boolean incr = (startValue <= endValue); - - final AtomicInteger count = new AtomicInteger (0); - - final Map animators = new HashMap (); - - final javax.swing.Timer up = UIUtils.createAnimator (cycleUp, - fps, - duration / 2, - (incr ? startValue : endValue), - (incr ? endValue : startValue), - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - if (incr) - { - - count.incrementAndGet (); - - } - - if ((!incr) - && - (count.get () == repeatCount) - ) - { - - if (onComplete != null) - { - - onComplete.actionPerformed (new ActionEvent ("complete", endValue, "complete")); - - } - - return; - - } - - animators.get ("down").restart (); - - } - - }); - - animators.put ("up", - up); - - final javax.swing.Timer down = UIUtils.createAnimator (cycleDown, - fps, - duration / 2, - (incr ? endValue : startValue), - (incr ? startValue : endValue), - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - - if (!incr) - { - - count.incrementAndGet (); - - } - - if ((incr) - && - (count.get () == repeatCount) - ) - { - - if (onComplete != null) - { - - onComplete.actionPerformed (new ActionEvent ("complete", endValue, "complete")); - - } - - return; - - } - - animators.get ("up").restart (); - - } - - }); - - animators.put ("down", - down); - - javax.swing.Timer t = new javax.swing.Timer (0, null); - - t.addActionListener (new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - if (incr) - { - - up.start (); - - } else { - - down.start (); - - } - - } - - }); - - t.setRepeats (false); - - return t; - - } - - public static javax.swing.Timer createAnimator (final PropertyChangeListener l, - final int fps, - final int duration, - final double startValue, - final double endValue, - final ActionListener onComplete) - { - - final javax.swing.Timer t = new javax.swing.Timer (1000 / fps, null); - - final double increment = ((endValue - startValue) / (double) fps) * (1000d / (double) duration); - - final boolean incr = (startValue <= endValue); - - t.addActionListener (new ActionListener () - { - - private double v = startValue; - - @Override - public void actionPerformed (ActionEvent ev) - { - - if ((incr && (this.v >= endValue)) - || - (!incr && (this.v <= endValue)) - ) - { - - t.stop (); - - if (onComplete != null) - { - - this.v = startValue; - - onComplete.actionPerformed (new ActionEvent ("complete", 1, "complete")); - - } - - return; - - } - - double nv = this.v + increment; - - if ((incr) - && - (nv > endValue) - ) - { - - nv = endValue; - - } - - if ((!incr) - && - (nv < endValue) - ) - { - - nv = endValue; - - } - - l.propertyChange (new PropertyChangeEvent (this, - "value", - this.v, - nv)); - - this.v = nv; - - } - - }); - - t.setCoalesce (true); - - return t; - - } - - public static void askForPasswordForProject (final ProjectInfo proj, - ValueValidator validator, - final ActionListener onProvided, - final AbstractViewer parentViewer) - { - - AbstractProjectViewer pv = Environment.getProjectViewer (proj); - - if ((pv == null) - && - (proj != null) - && - (proj.isEncrypted ()) - ) - { - - if (validator == null) - { - - validator = new ValueValidator () - { - - public String isValid (String v) - { - - java.util.List prefix = Arrays.asList (project,actions,openproject,enterpasswordpopup,errors); - - if ((v == null) - || - (v.trim ().equals ("")) - ) - { - - return getUIString (prefix,novalue); - //"Please enter the password."; - - } - - ObjectManager om = null; - - try - { - - om = Environment.getProjectObjectManager (proj, - v); - - } catch (Exception e) { - - if (ObjectManager.isDatabaseAlreadyInUseException (e)) - { - - return getUIString (prefix,projectalreadyopen); - //"Sorry, the {project} appears to already be open in Quoll Writer. Please close all other instances of Quoll Writer first before trying to open the {project}."; - - } - - if (ObjectManager.isEncryptionException (e)) - { - - return getUIString (prefix,invalidpassword); - //"Password is not valid."; - - } - - Environment.logError ("Cant open project: " + - proj, - e); - - UIUtils.showErrorMessage (parentViewer, - getUIString (prefix,general)); - //"Sorry, the {project} can't be opened. Please contact Quoll Writer support for assistance."); - - return null; - - } finally { - - if (om != null) - { - - om.closeConnectionPool (); - - } - - } - - return null; - - } - - }; - - } - - java.util.List prefix = Arrays.asList (project,actions,openproject,enterpasswordpopup); - - UIUtils.createPasswordInputPopup (parentViewer, - getUIString (prefix,title), - //"Password required", - Constants.PROJECT_ICON_NAME, - String.format (getUIString (prefix,text), - //"{Project} %s is encrypted, please enter the password to unlock it below.", - proj.getName ()), - getUIString (prefix,buttons,open), - //"Open", - getUIString (prefix,buttons,cancel), - //Constants.CANCEL_BUTTON_LABEL_ID, - null, - validator, - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - proj.setFilePassword (ev.getActionCommand ()); - - if (onProvided != null) - { - - onProvided.actionPerformed (new ActionEvent (proj, - 1, - "provided")); - - } - - } - - }, - null, - null); - - } else { - - onProvided.actionPerformed (new ActionEvent (proj, 1, "provided")); - - } - - } - - public static JComboBox getSpellCheckLanguagesSelector (final ActionListener onSelect, - final String defLang) - { - - final JComboBox spellcheckLang = new JComboBox (); - - if (onSelect != null) - { - - spellcheckLang.addItemListener (new ItemAdapter () - { - - public void itemStateChanged (ItemEvent ev) - { - - if (ev.getStateChange () != ItemEvent.SELECTED) - { - - return; - - } - - final String lang = spellcheckLang.getSelectedItem ().toString (); - - onSelect.actionPerformed (new ActionEvent (spellcheckLang, 1, lang)); - - } - - }); - - } - - // Get the languages supported by the spellchecker. - new Thread (new Runnable () - { - - public void run () - { - - String l = null; - - try - { - - l = Environment.getUrlFileAsString (new URL (Environment.getQuollWriterWebsite () + "/" + Environment.getProperty (Constants.QUOLL_WRITER_SUPPORTED_LANGUAGES_URL_PROPERTY_NAME))); - - } catch (Exception e) { - - // Something gone wrong, so just add english. - l = Constants.ENGLISH; - - Environment.logError ("Unable to get language files url", - e); - - } - - StringTokenizer t = new StringTokenizer (l, - String.valueOf ('\n')); - - final Vector langs = new Vector (); - - while (t.hasMoreTokens ()) - { - - String lang = t.nextToken ().trim (); - - if (lang.equals ("")) - { - - continue; - - } - - langs.add (lang); - - } - - SwingUtilities.invokeLater (new Runnable () - { - - public void run () - { - - spellcheckLang.setModel (new DefaultComboBoxModel (langs)); - spellcheckLang.setSelectedItem (defLang); - spellcheckLang.setEnabled (true); - - } - - }); - - } - - }).start (); - - return spellcheckLang; - - } - - public static JComboBox getUILanguagesSelector (final ActionListener onSelect, - final String defLang) - { - - final JComboBox uiLangs = new JComboBox (); - uiLangs.setEnabled (false); - - if (onSelect != null) - { - - uiLangs.addItemListener (new ItemAdapter () - { - - public void itemStateChanged (ItemEvent ev) - { - - if (ev.getStateChange () != ItemEvent.SELECTED) - { - - return; - - } - - final String lang = uiLangs.getSelectedItem ().toString (); - - onSelect.actionPerformed (new ActionEvent (uiLangs, 1, lang)); - - } - - }); - - } - - new Thread (new Runnable () - { - - public void run () - { - - String l = null; - - Collection ls = null; - - try - { - - l = Environment.getUrlFileAsString (new URL (Environment.getQuollWriterWebsite () + "/" + Environment.getProperty (Constants.QUOLL_WRITER_AVAILABLE_UI_LANGUAGE_STRINGS_URL_PROPERTY_NAME) + "?version=" + Environment.getQuollWriterVersion ().toString ())); - - ls = (Collection) JSONDecoder.decode (l); - - } catch (Exception e) { - - // Something gone wrong, so just add our local langs. - - ls = new LinkedHashSet<> (); - - Environment.logError ("Unable to get the ui language strings files url", - e); - - } - - final Map objs = new LinkedHashMap<> (); - - Set langIds = new LinkedHashSet<> (); - - try - { - - // Add in any user generated ones. - for (LanguageStrings _ls : Environment.getAllUserLanguageStrings (Environment.getQuollWriterVersion ())) - { - - langIds.add ("user-" + _ls.getId ()); - objs.put ("user-" + _ls.getId (), - _ls.getNativeName () + " (Created by you)"); - - } - - } catch (Exception e) { - - Environment.logError ("Unable to get the user ui language strings", - e); - - } - - // Add our local ones. - Set uistrs = Environment.getAllUILanguageStrings (Environment.getQuollWriterVersion ()); - - for (LanguageStrings uistr : uistrs) - { - - langIds.add (uistr.getId ()); - objs.put (uistr.getId (), uistr.getNativeName () + " (" + uistr.getLanguageName () + ")"); - - } - - // English is always available. - Map data = new HashMap (); - ls.add (data); - data.put ("id", LanguageStrings.ENGLISH_ID); - data.put ("nativename", Constants.ENGLISH); - - Iterator iter = ls.iterator (); - - while (iter.hasNext ()) - { - - Map m = (Map) iter.next (); - - String id = (String) m.get ("id"); - - objs.put (id, m.get ("nativename").toString () + (!id.equals (LanguageStrings.ENGLISH_ID) ? " (" + m.get ("languagename") + ")" : "")); - - langIds.add (id); - - } - - final Vector langs = new Vector (langIds); - - SwingUtilities.invokeLater (new Runnable () - { - - public void run () - { - - uiLangs.setRenderer (new DefaultListCellRenderer () - { - - @Override - public Component getListCellRendererComponent (JList list, - Object val, - int index, - boolean sel, - boolean hasFocus) - { - - super.getListCellRendererComponent (list, - val, - index, - sel, - hasFocus); - - if (val == null) - { - - return this; - - } - - String name = objs.get (val.toString ()); - - this.setText (name); - - return this; - - } - - }); - - uiLangs.setModel (new DefaultComboBoxModel (langs)); - uiLangs.setSelectedItem (defLang); - uiLangs.setEnabled (true); - uiLangs.setMaximumSize (uiLangs.getPreferredSize ()); - - } - - }); - - } - - }).start (); - - return uiLangs; - - } - - public static void showManageBackups (final ProjectInfo proj, - final AbstractViewer viewer) - { - - String popupName = "managebackups" + proj.getId (); - QPopup popup = viewer.getNamedPopup (popupName); - - if (popup == null) - { - - popup = UIUtils.createClosablePopup (getUIString (backups,show, LanguageStrings.popup,title), - //"Current Backups", - Environment.getIcon (Constants.SNAPSHOT_ICON_NAME, - Constants.ICON_POPUP), - null); - - BackupsManager bm = null; - - try - { - - bm = new BackupsManager (viewer, - proj); - bm.init (); - - } catch (Exception e) { - - Environment.logError ("Unable to show backups manager", - e); - - UIUtils.showErrorMessage (viewer, - getUIString (backups,show,actionerror)); - //"Unable to show backups manager, please contact Quoll Writer support for assistance."); - - return; - - } - - bm.setSize (new Dimension (UIUtils.getPopupWidth () - 20, - bm.getPreferredSize ().height)); - bm.setBorder (UIUtils.createPadding (10, 10, 10, 10)); - - popup.setRemoveOnClose (false); - popup.setContent (bm); - - popup.setDraggable (viewer); - - popup.resize (); - - viewer.showPopupAt (popup, - UIUtils.getCenterShowPosition (viewer, - popup), - false); - - viewer.addNamedPopup (popupName, - popup); - - } else { - - popup.setVisible (true); - popup.toFront (); - - } - - Environment.fireUserProjectEvent (viewer, - ProjectEvent.BACKUPS, - ProjectEvent.SHOW); - - } - - public static void showCreateBackup (final Project proj, - final String filePassword, - final AbstractViewer viewer) - { - - UIUtils.showCreateBackup (Environment.getProjectInfo (proj), - filePassword, - viewer); - - } - - public static void showCreateBackup (final ProjectInfo proj, - final String filePassword, - final AbstractViewer viewer) - { - - UIUtils.createQuestionPopup (viewer, - getUIString (backups,_new,popup,title), - //"Create a Backup", - Constants.SNAPSHOT_ICON_NAME, - String.format (getUIString (backups,_new,popup,text), - //"Please confirm you wish to create a backup of {project} %s.", - proj.getName ()), - getUIString (backups,_new,popup,buttons,confirm), - //"Yes, create it", - getUIString (backups,_new,popup,buttons,cancel), - //null, - new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - try - { - - File f = Environment.createBackupForProject (proj, - false); - - Box b = new Box (BoxLayout.Y_AXIS); - - JTextPane m = UIUtils.createHelpTextPane (String.format (getUIString (backups,_new,confirmpopup,text), - //"A backup has been created and written to:\n\n %s", - f.getParentFile ().toURI ().toString (), - f), - viewer); - - m.setSize (new Dimension (UIUtils.getPopupWidth () - 20, - m.getPreferredSize ().height)); - m.setBorder (null); - - b.add (m); - - b.add (Box.createVerticalStrut (10)); - - JLabel l = UIUtils.createClickableLabel (getUIString (backups,_new,confirmpopup,labels,view), - //"Click to view the backups", - Environment.getIcon (Constants.SNAPSHOT_ICON_NAME, - Constants.ICON_MENU), - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - UIUtils.showManageBackups (proj, - viewer); - - } - - }); - - b.add (l); - - UIUtils.showMessage ((PopupsSupported) viewer, - getUIString (backups,_new,confirmpopup,title), - //"Backup created", - b); - - } catch (Exception e) - { - - Environment.logError ("Unable to create backup of project: " + - proj, - e); - - UIUtils.showErrorMessage (viewer, - getUIString (backups,_new,actionerror)); - //"Unable to create backup."); - - } - - } - - }, - null, - null, - null); - - } - - public static void downloadDictionaryFiles (String lang, - final AbstractViewer parent, - final ActionListener onComplete) - { - - if (Environment.isEnglish (lang)) - { - - lang = Constants.ENGLISH; - - } - - final String langOrig = lang; - final String language = lang; - - String fileLang = lang; - - // Legacy, if the user doesn't have the language file but DOES have a thesaurus then just - // download the English-dictionary-only.zip. - if ((Environment.isEnglish (lang)) - && - (!Environment.getDictionaryFile (lang).exists ()) - && - (Environment.hasSynonymsDirectory (lang)) - ) - { - - fileLang = "English-dictionary-only"; - - } - - URL url = null; - - try - { - - url = new URL (Environment.getQuollWriterWebsite () + "/" + StringUtils.replaceString (Environment.getProperty (Constants.QUOLL_WRITER_LANGUAGE_FILES_URL_PROPERTY_NAME), - "[[LANG]]", - StringUtils.replaceString (fileLang, - " ", - "%20"))); - - } catch (Exception e) { - - Environment.logError ("Unable to download language files, cant create url", - e); - - UIUtils.showErrorMessage (parent, - getUIString (dictionary,download,actionerror)); - //"Unable to download language files"); - - return; - - } - - Environment.logDebugMessage ("Downloading language file(s) from: " + url + ", for language: " + lang); - - File _file = null; - - // Create a temp file for it. - try - { - - _file = File.createTempFile ("quollwriter-language-" + fileLang, - null); - - } catch (Exception e) { - - Environment.logError ("Unable to download language files, cant create temp file", - e); - - UIUtils.showErrorMessage (parent, - getUIString (dictionary,download,actionerror)); - //"Unable to download language files"); - - return; - - } - - _file.deleteOnExit (); - - final File file = _file; - - Box b = new Box (BoxLayout.Y_AXIS); - - final JTextPane htmlP = UIUtils.createHelpTextPane (String.format (getUIString (dictionary,download,notification), - //"The language files for %s are now being downloaded.", - language), - parent); - htmlP.setBorder (null); - htmlP.setBackground (null); - htmlP.setOpaque (false); - htmlP.setAlignmentX (Component.LEFT_ALIGNMENT); - - b.add (htmlP); - b.add (Box.createVerticalStrut (10)); - - final JProgressBar prog = new JProgressBar (0, 100); - - prog.setPreferredSize (new Dimension (500, 25)); - prog.setMaximumSize (new Dimension (500, 25)); - prog.setAlignmentX (Component.LEFT_ALIGNMENT); - - b.add (prog); - - final Notification n = parent.addNotification (b, - Constants.DOWNLOAD_ICON_NAME, - -1, - null); - - final ActionListener removeNotification = new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - n.removeNotification (); - - } - }; - - final UrlDownloader downloader = new UrlDownloader (url, - file, - new DownloadListener () - { - - public void handleError (Exception e) - { - - UIUtils.doLater (removeNotification); - - Environment.logError ("Unable to download language files", - e); - - UIUtils.showErrorMessage (parent, - getUIString (dictionary,download,actionerror)); - //"A problem has occurred while downloading the language files for " + langOrig + ".

    Please contact Quoll Writer support for assistance."); - - } - - public void progress (final int downloaded, - final int total) - { - - UIUtils.doLater (new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - int val = (int) (((double) downloaded / (double) total) * 100); - - prog.setValue (val); - - } - - }); - - } - - public void finished (int total) - { - - prog.setValue (100); - prog.setIndeterminate (true); - - new Thread (new Runner () - { - - public void run () - { - - // Now extract the file into the relevant directory. - try - { - - Utils.extractZipFile (file, - Environment.getUserQuollWriterDir ()); - - } catch (Exception e) { - - Environment.logError ("Unable to extract language zip file: " + - file + - " to: " + - Environment.getUserQuollWriterDir (), - e); - - UIUtils.showErrorMessage (parent, - getUIString (dictionary,download,actionerror)); - - return; - - } finally { - - file.delete (); - - } - - if (onComplete != null) - { - - UIUtils.doLater (new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - prog.setIndeterminate (false); - - onComplete.actionPerformed (new ActionEvent (parent, 0, langOrig)); - - } - - }); - - } - - UIUtils.doLater (removeNotification); - - } - - }).start (); - - } - - }); - - downloader.start (); - - n.addCancelListener (new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - downloader.stop (); - - file.delete (); - - } - - }); - - } - - public static Form createForm (Set items) - { - - return new Form (Form.Layout.stacked, - items, - (Set) null); - - } - - public static Form createForm (Set items, - Map buttons) - { - - return new Form (Form.Layout.stacked, - items, - buttons); - - } - - public static Form createForm (Set items, - Set buttons) - { - - return new Form (Form.Layout.stacked, - items, - buttons); - - } - - public static void showAddNewProject (AbstractViewer viewer, - Point showAt, - ActionListener onCreate) - { - - final QPopup popup = UIUtils.createClosablePopup (getUIString (newproject, LanguageStrings.popup,title), - //"Create a new {project}", - Environment.getIcon (Constants.ADD_ICON_NAME, - Constants.ICON_POPUP), - null); - - Box content = new Box (BoxLayout.Y_AXIS); - - content.add (UIUtils.createHelpTextPane (getUIString (newproject, LanguageStrings.popup,text), - //"To create a new {Project} enter the name below, select the directory it should be saved to and press the Create button.", - null)); - - final NewProjectPanel newProjPanel = new NewProjectPanel (); - - JComponent cp = newProjPanel.createPanel (popup, - popup.getCloseAction (), - true, - popup.getCloseAction (), - true); - - content.add (cp); - - content.setBorder (UIUtils.createPadding (10, 10, 10, 10)); - - content.setPreferredSize (new Dimension (UIUtils.getPopupWidth (), - content.getPreferredSize ().height)); - - popup.setContent (content); - - viewer.showPopupAt (popup, - (showAt != null ? showAt : UIUtils.getCenterShowPosition (viewer, - popup)), - false); - - popup.resize (); - - popup.setDraggable (viewer); - - } - - public static JComponent getChapterInfoPreview (Chapter c, - String format, - AbstractProjectViewer viewer) - { - - // If there is no key or null chapter then return. - if ((c == null) - || - (c.getKey () == null) - ) - { - - return null; - - } - - String lastEd = ""; - - if (c.getLastModified () != null) - { - - lastEd = String.format (getUIString (project,sidebar,chapters,preview,lastedited), - //"Last edited: %s", - Environment.formatDate (c.getLastModified ())); - - } else { - - lastEd = getUIString (project,sidebar,chapters,preview,notedited); - //"Not yet edited."; - - } - - String text = format; - - if (text == null) - { - - text = UserProperties.get (Constants.CHAPTER_INFO_PREVIEW_FORMAT, - Constants.DEFAULT_CHAPTER_INFO_PREVIEW_FORMAT); - - } - - String nl = String.valueOf ('\n'); - - while (text.endsWith (nl)) - { - - text = text.substring (0, - text.length () - 1); - - } - - text = text.toLowerCase (); - - String desc = c.getDescriptionText (); - String descFirstLine = null; - - if ((desc == null) - || - (desc.length () == 0) - ) - { - - desc = getUIString (project,sidebar,chapters,preview,nodescription); - //"No description."; - descFirstLine = desc; - - } else { - - descFirstLine = new TextIterator (desc).getFirstSentence ().getText (); - - } - - String chapText = viewer.getCurrentChapterText (c); - - if (chapText != null) - { - - chapText = chapText.trim (); - - } else { - - chapText = ""; - - } - - if (chapText.length () > 0) - { - - chapText = new TextIterator (chapText).getFirstSentence ().getText (); - - } else { - - chapText = getUIString (project,sidebar,chapters,preview,emptychapter); - //"{Chapter} is empty."); - - } - - text = StringUtils.replaceString (text, - " ", - " "); - text = StringUtils.replaceString (text, - nl, - "
    "); - - text = StringUtils.replaceString (text, - Constants.DESCRIPTION_TAG, - desc); - - text = StringUtils.replaceString (text, - Constants.DESCRIPTION_FIRST_LINE_TAG, - descFirstLine); - - text = StringUtils.replaceString (text, - Constants.CHAPTER_FIRST_LINE_TAG, - chapText); - - ChapterCounts cc = viewer.getChapterCounts (c); - - if (cc == null) - { - - // Get the current text instead. - cc = new ChapterCounts (c.getChapterText ()); - - } - - text = StringUtils.replaceString (text, - Constants.WORDS_TAG, - String.format (getUIString (project,sidebar,chapters,preview,words), - //"%s words", - Environment.formatNumber (cc.wordCount))); - - text = StringUtils.replaceString (text, - Constants.LAST_EDITED_TAG, - lastEd); - - int ep = c.getEditPosition (); - - if (c.isEditComplete ()) - { - - ep = 100; - - } else { - - if (ep > 0) - { - - if (ep > chapText.length () - 1) - { - - ep = chapText.length (); - - } - - ChapterCounts ecc = new ChapterCounts (chapText.substring (0, - ep)); - - ep = Environment.getPercent (ecc.wordCount, cc.wordCount); - - } - - } - - if (ep < 0) - { - - ep = 0; - - } - - text = StringUtils.replaceString (text, - Constants.EDIT_COMPLETE_TAG, - String.format (getUIString (project,sidebar,chapters,preview,editcomplete), - //"%s%% complete", - Environment.formatNumber (ep))); - - if (text.contains (Constants.PROBLEM_FINDER_PROBLEM_COUNT_TAG)) - { - - text = StringUtils.replaceString (text, - Constants.PROBLEM_FINDER_PROBLEM_COUNT_TAG, - String.format (getUIString (project,sidebar,chapters,preview,problemcount), - //"%s problems", - Environment.formatNumber (viewer.getProblems (c).size ()))); - - } - - if (text.contains (Constants.SPELLING_ERROR_COUNT_TAG)) - { - - text = StringUtils.replaceString (text, - Constants.SPELLING_ERROR_COUNT_TAG, - String.format (getUIString (project,sidebar,chapters,preview,spellingcount), - //"%s spelling errors", - Environment.formatNumber (viewer.getSpellingErrors (c).size ()))); - - } - - ReadabilityIndices ri = viewer.getReadabilityIndices (c); - - if (ri == null) - { - - ri = new ReadabilityIndices (); - ri.add (c.getChapterText ()); - - } - - String na = getUIString (project,sidebar,chapters,preview,notapplicable); - - String GL = na; //"N/A"; - String RE = na; //"N/A"; - String GF = na; //"N/A"; - - if (cc.wordCount > Constants.MIN_READABILITY_WORD_COUNT) - { - - GL = Environment.formatNumber (Math.round (ri.getFleschKincaidGradeLevel ())); - RE = Environment.formatNumber (Math.round (ri.getFleschReadingEase ())); - GF = Environment.formatNumber (Math.round (ri.getGunningFogIndex ())); - - } - - text = StringUtils.replaceString (text, - Constants.READABILITY_TAG, - String.format (getUIString (project,sidebar,chapters,preview,readability), - //"GL: %s, RE: %s, GF: %s", - GL, - RE, - GF)); - - JEditorPane p = UIUtils.createHelpTextPane (text, - null); -/* - p.setSize (new Dimension (380, - 0)); - */ - p.setAlignmentX (Component.LEFT_ALIGNMENT); - - return p; - - } - - public static void showAddNewObjectType (AbstractViewer viewer) - { - - UserConfigurableObjectType utype = new UserConfigurableObjectType (); - - utype.setObjectTypeName (getUIString (userobjects,type,_new,defaults,names,singular)); - //"Widget"); - utype.setObjectTypeNamePlural (getUIString (userobjects,type,_new,defaults,names,plural)); - //"Widgets"); - utype.setLayout (null); - utype.setAssetObjectType (true); - utype.setIcon24x24 (Environment.getIcon ("whats-new", - Constants.ICON_TITLE)); - utype.setIcon16x16 (Environment.getIcon ("whats-new", - Constants.ICON_SIDEBAR)); - - // Name - ObjectNameUserConfigurableObjectTypeField nameF = new ObjectNameUserConfigurableObjectTypeField (); - - nameF.setFormName (getUIString (userobjects,type,_new,defaults,fields,name)); - //"Name"); - - utype.addConfigurableField (nameF); - - // Description - ObjectDescriptionUserConfigurableObjectTypeField cdescF = new ObjectDescriptionUserConfigurableObjectTypeField (); - - cdescF.setSearchable (true); - cdescF.setFormName (getUIString (userobjects,type,_new,defaults,fields,description)); - //"Description"); - - utype.addConfigurableField (cdescF); - - Wizard w = UserConfigurableObjectTypeEdit.getAsWizard (viewer, - utype); - - final QPopup p = UIUtils.createWizardPopup (getUIString (userobjects,type,_new,popup,title), - //"Add a new type of Object", - Constants.NEW_ICON_NAME, - null, - w); - w.setPreferredSize (new Dimension (UIUtils.getPopupWidth () - 20, - w.getPreferredSize ().height)); - - viewer.showPopupAt (p, - UIUtils.getCenterShowPosition (viewer, - p), - false); - p.setDraggable (viewer); - - UIUtils.doLater (new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - UIUtils.resizeParent (p); - - } - - }); - - - } - - public static void showObjectTypeEdit (UserConfigurableObjectType utype, - AbstractViewer viewer) - { - - final QPopup p = UIUtils.createClosablePopup (String.format (getUIString (userobjects,type,edit,popup,title), - //"Edit the %s information", - utype.getObjectTypeName ()), - Environment.getIcon (Constants.EDIT_ICON_NAME, - Constants.ICON_POPUP), - null); - - Box b = new Box (BoxLayout.Y_AXIS); - - b.setBorder (UIUtils.createPadding (10, 10, 10, 10)); - - JTextPane m = UIUtils.createHelpTextPane (String.format (getUIString (userobjects,type,edit,popup,text), - //"Use this popup to add or edit the fields, layout and information for your %s.", - utype.getObjectTypeNamePlural ()), - viewer); - - m.setSize (new Dimension (UIUtils.getPopupWidth () - 20, - m.getPreferredSize ().height)); - m.setBorder (null); - - b.add (m); - - b.add (Box.createVerticalStrut (5)); - - b.add (UserConfigurableObjectTypeEdit.getAsTabs (viewer, - utype)); - - JButton finishb = new JButton (getUIString (userobjects,type,edit,popup,buttons,finish)); - //"Finish"); - - finishb.addActionListener (new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - UIUtils.closePopupParent (p); - - } - - }); - - JButton[] fbuts = new JButton[] { finishb }; - - JPanel bp = UIUtils.createButtonBar2 (fbuts, - Component.CENTER_ALIGNMENT); - bp.setOpaque (false); - - bp.setAlignmentX (Component.LEFT_ALIGNMENT); - b.add (Box.createVerticalStrut (10)); - - b.add (bp); - - p.setContent (b); - - b.setPreferredSize (new Dimension (UIUtils.getPopupWidth (), - b.getPreferredSize ().height)); - - viewer.showPopupAt (p, - UIUtils.getCenterShowPosition (viewer, - p), - false); - p.setDraggable (viewer); - - } - - public static JButton createTagsMenuToolBarButton (final NamedObject obj, - final AbstractProjectViewer viewer) - { - - JButton b = UIUtils.createToolBarButton (Constants.TAG_ICON_NAME, - null, - null, - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - JPopupMenu tagMenu = new JPopupMenu (); - - Set allTags = null; - - try - { - - allTags = Environment.getAllTags (); - - } catch (Exception e) { - - Environment.logError ("Unable to get all tags", - e); - - return; - - } - - for (Tag t : allTags) - { - - final JCheckBox it = new JCheckBox (t.getName (), - obj.hasTag (t)); - it.setBorder (UIUtils.createPadding (3, 3, 3, 3)); - - it.addActionListener (new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - if (it.isSelected ()) - { - - obj.addTag (t); - - } else { - - obj.removeTag (t); - - } - - try - { - - viewer.saveObject (obj, - false); - - } catch (Exception e) { - - Environment.logError ("Unable to update object: " + - obj, - e); - - UIUtils.showErrorMessage (viewer, - getUIString (tags,actions,apply,actionerror)); - //"Unable to add/remove tag."); - - return; - - } - - viewer.reloadTreeForObjectType (TaggedObjectAccordionItem.ID_PREFIX + t.getKey ()); - - } - - }); - - tagMenu.add (it); - - } - - if (allTags.size () > 0) - { - - tagMenu.addSeparator (); - - } - - tagMenu.add (UIUtils.createMenuItem (getUIString (tags,popupmenu,_new), - //"Add New Tag(s)", - Constants.EDIT_ICON_NAME, - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - new AddNewTagActionHandler (obj, - viewer).actionPerformed (ev); - - } - - })); - - Component c = (Component) ev.getSource (); - - tagMenu.show (c, - c.getX (), - c.getY ()); - - } - - }); - - return b; - - } - - public static JMenu createTagsMenu (final NamedObject obj, - final AbstractProjectViewer viewer) - { - - JMenu tagMenu = new JMenu (getUIString (tags,popupmenu,title)); - //"Tags"); - - tagMenu.setIcon (Environment.getIcon (Constants.TAG_ICON_NAME, - Constants.ICON_MENU)); - - Set allTags = null; - - try - { - - allTags = Environment.getAllTags (); - - } catch (Exception e) { - - Environment.logError ("Unable to get all tags", - e); - - return tagMenu; - - } - - for (Tag t : allTags) - { - - final JCheckBox it = new JCheckBox (t.getName (), - obj.hasTag (t)); - it.setBorder (UIUtils.createPadding (3, 3, 3, 3)); - - it.addActionListener (new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - if (it.isSelected ()) - { - - obj.addTag (t); - - } else { - - obj.removeTag (t); - - } - - try - { - - viewer.saveObject (obj, - false); - - } catch (Exception e) { - - Environment.logError ("Unable to update object: " + - obj, - e); - - UIUtils.showErrorMessage (viewer, - getUIString (tags,actions,apply,actionerror)); - //"Unable to add/remove tag."); - - return; - - } - - viewer.reloadTreeForObjectType (TaggedObjectAccordionItem.ID_PREFIX + t.getKey ()); - - } - - }); - - tagMenu.add (it); - - } - - if (allTags.size () > 0) - { - - tagMenu.addSeparator (); - - } - - tagMenu.add (UIUtils.createMenuItem (getUIString (tags,popupmenu,_new), - //"Add New Tag(s)", - Constants.ADD_ICON_NAME, - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - new AddNewTagActionHandler (obj, - viewer).actionPerformed (ev); - - } - - })); - - return tagMenu; - - } - - public static void showEditLanguageStringsSelectorPopup (final AbstractViewer viewer) - { - - Set objs = null; - - try - { - - objs = Environment.getAllUserLanguageStrings (); - - } catch (Exception e) { - - Environment.logError ("Unable to get all user language strings.", - e); - - UIUtils.showErrorMessage (viewer, - getUIString (uilanguage,edit,actionerror)); - - return; - - } - - if (objs.size () == 0) - { - - UIUtils.showMessage ((PopupsSupported) viewer, - getUIString (uilanguage,edit,novalue,title), - getUIString (uilanguage,edit,novalue,text)); - - return; - - } - - UIUtils.showObjectSelectPopup (objs, - viewer, - getUIString (uilanguage,edit,popup,title), - new DefaultListCellRenderer () - { - - @Override - public Component getListCellRendererComponent (JList list, - Object value, - int index, - boolean isSelected, - boolean cellHasFocus) - { - - LanguageStrings obj = (LanguageStrings) value; - - JLabel l = (JLabel) super.getListCellRendererComponent (list, - value, - index, - isSelected, - cellHasFocus); - - l.setText (obj.getName () + " (" + obj.getQuollWriterVersion ().toString () + ")"); - - l.setFont (l.getFont ().deriveFont (UIUtils.getScaledFontSize (14)).deriveFont (Font.PLAIN)); -/* - l.setIcon (Environment.getObjectIcon (obj, - Constants.ICON_NOTIFICATION)); - */ - l.setBorder (UIUtils.createBottomLineWithPadding (5, 5, 5, 5)); - - if (cellHasFocus) - { - - l.setBackground (Environment.getHighlightColor ()); - - } - - return l; - - } - - }, - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - final LanguageStrings ls = (LanguageStrings) ev.getSource (); -/* - // Check to see if this version is the same as the current QW version. - if (ls.getQuollWriterVersion ().isNewer (Environment.getQuollWriterVersion ())) - { - - // It's not, so see if the user has a version for the current QW version. - LanguageStrings lscurr = null; - - try - { - - lscurr = Environment.getUserUILanguageStrings (Environment.getQuollWriterVersion (), - ls.getId ()); - - } catch (Exception e) { - - Environment.logError ("Unable to get strings: " + ls.getId (), - e); - - UIUtils.showErrorMessage (viewer, - "Unable to edit strings."); - - return; - - } - - if (lscurr == null) - { - - // Offer to update the strings to the current version. - UIUtils.createQuestionPopup (viewer, - getUIString (uilanguage,update,popup,title), - //"Update your strings to the current {QW} version?", - Constants.SAVE_ICON_NAME, - getUIString (uilanguage,update,popup,text), - //"Do you want to update your strings to the current {QW} version? This will not affect the old version.", - getUIString (uilanguage,update,popup,buttons,confirm), - //"Yes, update them", - getUIString (uilanguage,update,popup,buttons,cancel), - //"No, leave them", - // On confirm - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - ls.setQuollWriterVersion (Environment.getQuollWriterVersion ()); - - // Save it. - try - { - - Environment.saveUserUILanguageStrings (ls); - - } catch (Exception e) { - - Environment.logError ("Unable to update strings: " + ls.getId (), - e); - - UIUtils.showErrorMessage (viewer, - "Unable to update strings."); - - return; - - } - - LanguageStrings lscurr = null; - - // Now open it. - try - { - - lscurr = Environment.getUserUILanguageStrings (Environment.getQuollWriterVersion (), - ls.getId ()); - - Environment.editUILanguageStrings (lscurr, - lscurr.getQuollWriterVersion ()); - - } catch (Exception e) { - - Environment.logError ("Unable to edit strings: " + ls.getId (), - e); - - UIUtils.showErrorMessage (viewer, - "Unable to edit strings."); - - return; - - } - - } - - }, - // On cancel - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - Environment.editUILanguageStrings (ls, - ls.getQuollWriterVersion ()); - - } - - }, - // On close - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - Environment.editUILanguageStrings (ls, - ls.getQuollWriterVersion ()); - - } - - }, - null); - - return; - - } - - } -*/ - Environment.editUILanguageStrings (ls, - ls.getQuollWriterVersion ()); - - } - - }, - true, - null); - - } - - public static void showAddNewLanguageStringsPopup (final AbstractViewer viewer) - { - - java.util.List prefix = Arrays.asList (uilanguage,_new,popup); - - QPopup popup = UIUtils.createTextInputPopup (viewer, - getUIString (prefix,title), - //"Enter the language name", - Constants.ADD_ICON_NAME, - getUIString (prefix,text), - //"Enter the name of the language you want to create the strings for.", - getUIString (prefix,buttons,create), - //"Create", - getUIString (prefix,buttons,cancel), - //"Cancel", - null, - new ValueValidator () - { - - @Override - public String isValid (String v) - { - - if ((v == null) - || - (v.trim ().length () == 0) - ) - { - - return "Please enter the language name"; - - } - - return null; - - } - - }, - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - String v = ev.getActionCommand (); - - LanguageStrings ls = new LanguageStrings (Environment.getDefaultUILanguageStrings ()); - ls.setNativeName (v); - ls.setUser (true); - - try - { - - new LanguageStringsEditor (ls).init (); - - } catch (Exception e) { - - Environment.logError ("Unable to create language strings editor", - e); - - UIUtils.showErrorMessage (viewer, - "Unable to create strings editor."); - - } - - } - - }, - null, - null); - - } - -} diff --git a/src/com/quollwriter/ui/Wizard.java b/src/com/quollwriter/ui/Wizard.java deleted file mode 100644 index 1df02325..00000000 --- a/src/com/quollwriter/ui/Wizard.java +++ /dev/null @@ -1,571 +0,0 @@ -package com.quollwriter.ui; - -import java.awt.*; -import java.awt.event.*; - -import java.util.LinkedHashMap; -import java.util.Map; - -import javax.swing.*; -import javax.swing.border.*; -import javax.swing.event.*; - -import com.gentlyweb.utils.*; - -import com.jgoodies.forms.factories.*; - -import com.quollwriter.*; - -import com.quollwriter.ui.components.*; - -public abstract class Wizard extends Box -{ - - public static final String NEXT_BUTTON_ID = "next"; - public static final String PREVIOUS_BUTTON_ID = "previous"; - public static final String FINISH_BUTTON_ID = "finish"; - public static final String CANCEL_BUTTON_ID = "cancel"; - private boolean inited = false; - private WizardStep current = null; - private String currentStage = null; - private Box contentPanel = null; - private Map stages = new LinkedHashMap (); - private JButton cancelBut = null; - private JButton nextBut = null; - private JButton prevBut = null; - private Header header = null; - private JTextPane helpText = null; - protected E viewer = null; - - public Wizard (E viewer) - { - - super (BoxLayout.Y_AXIS); - - this.contentPanel = new Box (BoxLayout.Y_AXIS); - - this.viewer = viewer; - - } - - public int getContentPreferredHeight () - { - - return 250; - - } - - public void addButtonListener (String type, - ActionListener l) - { - - if (NEXT_BUTTON_ID.equals (type)) - { - - this.nextBut.addActionListener (l); - - } - - if (PREVIOUS_BUTTON_ID.equals (type)) - { - - this.prevBut.addActionListener (l); - - } - - if (CANCEL_BUTTON_ID.equals (type)) - { - - this.cancelBut.addActionListener (l); - - } - - } - - public String getCurrentStage () - { - - return this.currentStage; - - } - - public void resize () - { - - UIUtils.resizeParent (this.getParent ()); - - } - - public void init () - { - - if (this.inited) - { - - return; - - } - - final Wizard _this = this; - - this.helpText = UIUtils.createHelpTextPane (this.viewer); - - this.helpText.setBorder (null); - - this.add (this.helpText); - this.add (Box.createVerticalStrut (10)); - this.setAlignmentX (JComponent.LEFT_ALIGNMENT); - - this.header = UIUtils.createHeader ("", - Constants.SUB_PANEL_TITLE); - - this.header.setBorder (UIUtils.createBottomLineWithPadding (0, 0, 2, 0)); - - this.header.setAlignmentX (JComponent.LEFT_ALIGNMENT); - this.add (Box.createVerticalStrut (10)); - this.add (this.header); - this.add (Box.createVerticalStrut (10)); - this.add (this.contentPanel); - this.contentPanel.setAlignmentX (JComponent.LEFT_ALIGNMENT); - this.contentPanel.setAlignmentY (JComponent.TOP_ALIGNMENT); - - this.contentPanel.setPreferredSize (new Dimension (UIUtils.getPopupWidth (), - this.getContentPreferredHeight ())); - - this.add (Box.createVerticalStrut (10)); - - this.prevBut = new JButton (); - this.prevBut.setText (Environment.getUIString (LanguageStrings.wizard, - LanguageStrings.buttons, - LanguageStrings.previous)); - //"< Back"); - this.prevBut.setEnabled (false); - - this.prevBut.addActionListener (new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - Map _stages = _this.stages; - - WizardStep ws = null; - - String prev = _this.getPreviousStage (_this.currentStage); - - if (prev != null) - { - - if (!_this.handleStageChange (_this.currentStage, - prev)) - { - - return; - - } - - ws = _stages.get (prev); - - if (ws == null) - { - - try - { - - ws = _this.getStage (prev); - - } catch (Exception e) - { - - Environment.logError ("Unable to get stage for: " + - prev, - e); - - } - - _this.stages.put (prev, - ws); - - } - - if (_this.current.panel != null) - { - - _this.contentPanel.remove (_this.current.panel); - - } - - _this.current = ws; - _this.currentStage = prev; - - _this.enableButtons (_this.currentStage); - - _this.initUI (); - - } - - /* - _this.setSize (new Dimension (_this.getSize ().width, - _this.getPreferredSize ().height)); - */ - _this.repaint (); - - } - - }); - - this.nextBut = new JButton (); - this.nextBut.setText (Environment.getUIString (LanguageStrings.wizard, - LanguageStrings.buttons, - LanguageStrings.next)); - //"Next >"); - - this.nextBut.addActionListener (new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - WizardStep ws = null; - - String next = _this.getNextStage (_this.currentStage); - - if (next != null) - { - - if (!_this.handleStageChange (_this.currentStage, - next)) - { - - return; - - } - - Map _stages = _this.stages; - - ws = _stages.get (next); - - if (ws == null) - { - - try - { - - ws = _this.getStage (next); - - } catch (Exception e) - { - - Environment.logError ("Unable to get stage: " + - next, - e); - - } - - if (ws != null) - { - - _this.stages.put (next, - ws); - - } - - } - - if (ws == null) - { - - Environment.logError ("Unable to get stage view component for: " + - next); - - UIUtils.showErrorMessage (this, - Environment.getUIString (LanguageStrings.wizard, - LanguageStrings.nexterror)); - //"Unable to show next stage."); - - return; - - } - - if (_this.current.panel != null) - { - - _this.contentPanel.remove (_this.current.panel); - - } - - _this.current = ws; - _this.currentStage = next; - - _this.enableButtons (_this.currentStage); - - _this.initUI (); - - } else - { - - if (_this.handleFinish ()) - { - - _this.setVisible (false); - - UIUtils.closePopupParent (_this.getParent ()); - - return; - - } - - } - - _this.repaint (); - - } - - }); - - this.cancelBut = new JButton (); - this.cancelBut.setText (Environment.getUIString (LanguageStrings.wizard, - LanguageStrings.buttons, - LanguageStrings.cancel)); - //"Cancel"); - - final ActionAdapter cancel = new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.handleCancel (); - - _this.setVisible (false); - - UIUtils.closePopupParent (_this.getParent ()); - - } - - }; - - this.cancelBut.addActionListener (cancel); - - JButton[] buts = { this.prevBut, this.nextBut, this.cancelBut }; - - JPanel bp = UIUtils.createButtonBar2 (buts, - Component.CENTER_ALIGNMENT); - bp.setOpaque (false); - bp.setBorder (new EmptyBorder (0, - 0, - 0, - 0)); - bp.setAlignmentX (JComponent.LEFT_ALIGNMENT); - this.add (bp); - - //this.add (Box.createVerticalStrut (5)); - - String startStage = this.getStartStage (); - - // Get the stage. - WizardStep ws = this.getStage (startStage); - this.stages.put (startStage, - ws); - this.current = ws; - this.currentStage = startStage; - - this.initUI (); - - this.enableButtons (this.currentStage); - - this.handleStageChange (null, - this.currentStage); - - this.inited = true; - - } - - public void showStage (String stage) - { - - if (!this.handleStageChange (this.currentStage, - stage)) - { - - return; - - } - - WizardStep ws = this.stages.get (stage); - - if ((ws == null) - || - (ws.alwaysRefreshPanel) - ) - { - - try - { - - ws = this.getStage (stage); - - } catch (Exception e) - { - - Environment.logError ("Unable to get stage for: " + - stage, - e); - - } - - this.stages.put (stage, - ws); - - } - - if (this.current.panel != null) - { - - this.contentPanel.remove (this.current.panel); - - } - - this.current = ws; - this.currentStage = stage; - - this.enableButtons (this.currentStage); - - this.initUI (); - - } - - public JButton[] getButtons () - { - - JButton[] buts = { this.prevBut, this.nextBut, this.cancelBut }; - - return buts; - - } - - public void enableButton (String name, - boolean enable) - { - - if ((name.equals (NEXT_BUTTON_ID)) || - (name.equals (FINISH_BUTTON_ID))) - { - - this.nextBut.setEnabled (enable); - - } - - if (name.equals (PREVIOUS_BUTTON_ID)) - { - - this.prevBut.setEnabled (enable); - - } - - if (name.equals (CANCEL_BUTTON_ID)) - { - - this.cancelBut.setEnabled (enable); - - } - - } - - private void initUI () - { - - this.header.setTitle (Environment.replaceObjectNames (this.current.title)); - - if (this.current.helpText == null) - { - - this.helpText.setText (this.getFirstHelpText ()); - - } else - { - - this.helpText.setText (this.current.helpText); - - } - - if (this.current.panel != null) - { - - this.current.panel.setOpaque (false); - this.current.panel.setAlignmentY (Component.TOP_ALIGNMENT); - this.contentPanel.add (this.current.panel); - - } - - UIUtils.resizeParent (this.getParent ()); - - } - - //public abstract int getMaximumContentHeight (); - - public abstract String getNextStage (String currStage); - - public abstract String getPreviousStage (String currStage); - - public abstract String getStartStage (); - - public abstract boolean handleStageChange (String oldStage, - String newStage); - - public abstract boolean handleFinish (); - - public abstract void handleCancel (); - - public abstract String getFirstHelpText (); - - public abstract WizardStep getStage (String stage); - - public String getNextButtonLabel (String currStage) - { - - String next = this.getNextStage (currStage); - - if (next == null) - { - - return Environment.getUIString (LanguageStrings.wizard, - LanguageStrings.buttons, - LanguageStrings.finish); - //return "Finish"; - - } - - return Environment.getUIString (LanguageStrings.wizard, - LanguageStrings.buttons, - LanguageStrings.next); - //return "Next >"; - - } - - protected void enableButtons (String currentStage) - { - - String prev = this.getPreviousStage (currentStage); - String next = this.getNextStage (currentStage); - - if (this.current != null) - { - - this.prevBut.setEnabled (prev != null); - this.nextBut.setEnabled (next != null); - - } - - if (next == null) - { - - this.nextBut.setEnabled (true); - - } - - this.nextBut.setText (this.getNextButtonLabel (currentStage)); - - } - -} diff --git a/src/com/quollwriter/ui/actionHandlers/DeleteProjectActionHandler.java b/src/com/quollwriter/ui/actionHandlers/DeleteProjectActionHandler.java deleted file mode 100644 index 4fea5885..00000000 --- a/src/com/quollwriter/ui/actionHandlers/DeleteProjectActionHandler.java +++ /dev/null @@ -1,138 +0,0 @@ -package com.quollwriter.ui.actionHandlers; - -import java.awt.*; -import java.awt.event.*; - -import java.io.*; - -import javax.swing.*; - -import com.quollwriter.*; - -import com.quollwriter.data.*; - -import com.quollwriter.ui.*; -import com.quollwriter.editors.*; - -public class DeleteProjectActionHandler extends YesDeleteConfirmTextInputActionHandler -{ - - private ProjectInfo projInfo = null; - private ActionListener onDelete = null; - - public DeleteProjectActionHandler (AbstractViewer viewer, - Project proj, - ActionListener onDelete) - { - - this (viewer, - Environment.getProjectInfo (proj), - onDelete); - - } - - public DeleteProjectActionHandler (AbstractViewer viewer, - ProjectInfo pi, - ActionListener onDelete) - { - - super (viewer, - pi); - - this.projInfo = pi; - this.onDelete = onDelete; - - } - - public String getDeleteType () - { - - return Environment.getUIString (LanguageStrings.project, - LanguageStrings.actions, - LanguageStrings.deleteproject, - LanguageStrings.deletetype); - //"{Project}"; - - } - - public String getWarning () - { - - String m = Environment.getUIString (LanguageStrings.project, - LanguageStrings.actions, - LanguageStrings.deleteproject, - LanguageStrings.warning, - LanguageStrings.normal); - //"Warning! All information/chapters associated with the {project} will be deleted. Once deleted a {project} cannot be restored."; - - if (this.projInfo.isEditorProject ()) - { - - m += String.format (Environment.getUIString (LanguageStrings.project, - LanguageStrings.actions, - LanguageStrings.deleteproject, - LanguageStrings.warning, - LanguageStrings.editor), - //"

    A message will also be sent to %s telling them you are no longer editing the {project}.", - this.projInfo.getForEditor ().getShortName ()); - - } - - return m; - - } - - @Override - public boolean onConfirm (String v) - throws Exception - { - - final DeleteProjectActionHandler _this = this; - - if (this.projInfo.isEditorProject ()) - { - - EditorsEnvironment.sendProjectEditStopMessage (this.projInfo, - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - Environment.deleteProject (_this.projInfo, - _this.onDelete); - - UIUtils.showMessage ((Component) null, - Environment.getUIString (LanguageStrings.project, - LanguageStrings.actions, - LanguageStrings.deleteproject, - LanguageStrings.editorproject, - LanguageStrings.confirmpopup, - LanguageStrings.title), - String.format (Environment.getUIString (LanguageStrings.project, - LanguageStrings.actions, - LanguageStrings.deleteproject, - LanguageStrings.editorproject, - LanguageStrings.confirmpopup, - LanguageStrings.text), - _this.projInfo.getForEditor ().getShortName ()), - null, - null); - - } - - }); - - } else { - - Environment.deleteProject (this.projInfo, - this.onDelete); - - } - - return true; - - } - -} diff --git a/src/com/quollwriter/ui/charts/AllWordCountsChart.java b/src/com/quollwriter/ui/charts/AllWordCountsChart.java deleted file mode 100644 index 78aa6a66..00000000 --- a/src/com/quollwriter/ui/charts/AllWordCountsChart.java +++ /dev/null @@ -1,414 +0,0 @@ -package com.quollwriter.ui.charts; - -import java.awt.Component; -import java.awt.Font; -import java.awt.event.*; - -import java.util.*; - -import javax.swing.*; - -import org.jfree.chart.*; -import org.jfree.ui.*; -import org.jfree.data.time.*; -import org.jfree.chart.plot.*; -import org.jfree.chart.labels.*; -import org.jfree.chart.axis.*; - -import com.quollwriter.ui.*; -import com.quollwriter.ui.panels.*; -import com.quollwriter.*; -import com.quollwriter.data.*; -import com.quollwriter.db.*; -import com.quollwriter.ui.components.ActionAdapter; -import com.quollwriter.ui.components.Header; - -public class AllWordCountsChart extends AbstractQuollChart -{ - - public static final String CHART_TYPE = "all-word-count"; - //public static final String CHART_TITLE = "Total Word Count"; - - private JComboBox displayB = null; - - private JFreeChart chart = null; - private JComponent controls = null; - - public AllWordCountsChart (AbstractProjectViewer pv) - { - - super (pv); - - } - - public void init (StatisticsPanel wcp) - throws GeneralException - { - - super.init (wcp); - - this.createControls (); - - } - - private void createControls () - { - - final AllWordCountsChart _this = this; - - Box b = new Box (BoxLayout.Y_AXIS); - - Header h = UIUtils.createBoldSubHeader (Environment.getUIString (LanguageStrings.charts, - LanguageStrings.allwordcounts, - LanguageStrings.labels, - LanguageStrings._for), - //"For", - null); - h.setAlignmentY (Component.TOP_ALIGNMENT); - - b.add (h); - - java.util.List prefix = new ArrayList<> (); - prefix.add (LanguageStrings.times); - - Vector displayItems = new Vector (); - displayItems.add (Environment.getUIString (prefix, - LanguageStrings.thisweek)); - //"This week"); - displayItems.add (Environment.getUIString (prefix, - LanguageStrings.lastweek)); - //displayItems.add ("Last week"); - displayItems.add (Environment.getUIString (prefix, - LanguageStrings.thismonth)); - //displayItems.add ("This month"); - displayItems.add (Environment.getUIString (prefix, - LanguageStrings.lastmonth)); - //displayItems.add ("Last month"); - displayItems.add (Environment.getUIString (prefix, - LanguageStrings.alltime)); - //displayItems.add ("All time"); - - b.add (Box.createVerticalStrut (5)); - - this.displayB = new JComboBox (displayItems); - this.displayB.setAlignmentX (Component.LEFT_ALIGNMENT); - this.displayB.setMaximumSize (displayB.getPreferredSize ()); - this.displayB.setAlignmentY (Component.TOP_ALIGNMENT); - - this.displayB.setSelectedIndex (0); - - this.displayB.addActionListener (new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.updateChart (); - - } - - }); - - Box db = new Box (BoxLayout.X_AXIS); - db.setAlignmentX (Component.LEFT_ALIGNMENT); - db.setAlignmentY (Component.TOP_ALIGNMENT); - - db.add (Box.createHorizontalStrut (5)); - - db.add (displayB); - - b.add (db); - - b.add (Box.createVerticalStrut (10)); - - JComponent c = (JComponent) Box.createVerticalGlue (); - c.setOpaque (false); - b.add (c); - - this.controls = b; - - } - - private void createChart () - { - - int days = -1; - - Date minDate = null; - Date maxDate = new Date (); - - // This week. - if (this.displayB.getSelectedIndex () == 0) - { - - // Work out how many days there have been this week. - GregorianCalendar gc = new GregorianCalendar (); - - days = gc.get (Calendar.DAY_OF_WEEK) - gc.getFirstDayOfWeek (); - - if (days < 0) - { - - days -= 7; - - } - - gc.add (Calendar.DATE, - -1 * days); - - minDate = gc.getTime (); - - days++; - - } - - // Last week - if (this.displayB.getSelectedIndex () == 1) - { - - GregorianCalendar gc = new GregorianCalendar (); - - days = gc.get (Calendar.DAY_OF_WEEK) - gc.getFirstDayOfWeek (); - - if (days < 0) - { - - days -= 7; - - } - - gc.add (Calendar.DATE, - (-1 * days) - 1); - - maxDate = gc.getTime (); - - days += 7; - - gc.add (Calendar.DATE, - -6); - - minDate = gc.getTime (); - - days++; - - } - - // This month. - if (this.displayB.getSelectedIndex () == 2) - { - - GregorianCalendar gc = new GregorianCalendar (); - - days = gc.get (Calendar.DATE); - - gc.set (Calendar.DATE, - 1); - - minDate = gc.getTime (); - - days++; - - } - - // Last month. - if (this.displayB.getSelectedIndex () == 3) - { - - GregorianCalendar gc = new GregorianCalendar (); - - gc.add (Calendar.MONTH, - -1); - - days = gc.getActualMaximum (Calendar.DATE); - - gc.set (Calendar.DATE, - days); - - maxDate = gc.getTime (); - - gc.set (Calendar.DATE, - 1); - - minDate = gc.getTime (); - - days++; - - } - - // All time - if (this.displayB.getSelectedIndex () == 4) - { - - days = 1; - - } - - java.util.List prefix = new ArrayList<> (); - prefix.add (LanguageStrings.charts); - prefix.add (LanguageStrings.allwordcounts); - prefix.add (LanguageStrings.labels); - - final TimeSeriesCollection tsc = new TimeSeriesCollection (); - - try - { - - TimeSeries ts = new TimeSeries (Environment.getUIString (prefix, - LanguageStrings.xaxis)); - //"Date"); - - ProjectDataHandler pdh = (ProjectDataHandler) this.viewer.getDataHandler (Project.class); - - // Get all the word counts for the project. - List wordCounts = pdh.getWordCounts (this.viewer.getProject (), - 0); - - for (WordCount wc : wordCounts) - { - - if (ts.getValue (new Day (wc.getEnd ())) == null) - { - - ts.add (new Day (wc.getEnd ()), - wc.getCount ()); - - } - - } - - ts.setRangeDescription (null); - tsc.addSeries (ts); - - } catch (Exception e) - { - - Environment.logError ("Unable to get word counts", - e); - - UIUtils.showErrorMessage (this.parent, - "Unable to word counts"); - - return; - - } - - this.chart = QuollChartUtils.createTimeSeriesChart (Environment.getUIString (prefix, - LanguageStrings.xaxis), - //"Date", - Environment.getUIString (prefix, - LanguageStrings.yaxis), - //"Word Count", - tsc); - - this.chart.setBackgroundPaint (UIUtils.getComponentColor ()); - - XYPlot plot = (XYPlot) this.chart.getPlot (); - - PeriodAxis axis = (PeriodAxis) plot.getDomainAxis (); - - if (minDate != null) - { - - axis.setLowerBound (minDate.getTime ()); - - axis.setUpperBound (maxDate.getTime ()); - - } - - plot.setBackgroundPaint (UIUtils.getComponentColor ()); - plot.setDomainGridlinePaint (Environment.getBorderColor ()); - plot.setRangeGridlinePaint (Environment.getBorderColor ()); - plot.setAxisOffset (new RectangleInsets (5D, - 5D, - 5D, - 5D)); - - Font f = QuollChartUtils.getLabelFont (); - - plot.setDomainCrosshairVisible (true); - plot.setRangeCrosshairVisible (true); - plot.setDomainGridlinePaint (UIUtils.getColor ("#cfcfcf")); - plot.setRangeGridlinePaint (UIUtils.getColor ("#cfcfcf")); - plot.getDomainAxis ().setLabelFont (f); - plot.getDomainAxis ().setTickLabelFont (f); - plot.getRangeAxis ().setLabelFont (f); - plot.getRangeAxis ().setTickLabelFont (f); - - this.chart.removeLegend (); - - } - - public String getTitle () - { - - return Environment.getUIString (LanguageStrings.charts, - LanguageStrings.allwordcounts, - LanguageStrings.title); - //CHART_TITLE; - - } - - public String getType () - { - - return CHART_TYPE; - - } - - public JComponent getControls (boolean update) - { - - if (update) - { - - this.controls = null; - - } - - if (this.controls == null) - { - - this.createControls (); - - } - - return this.controls; - - } - - public JFreeChart getChart (boolean update) - { - - if (update) - { - - this.chart = null; - - } - - if (this.chart == null) - { - - this.createChart (); - - } - - return this.chart; - - } - - public JComponent getDetail (boolean update) - { - - return null; - - } - - public String toString () - { - - return this.getTitle (); - - } - -} diff --git a/src/com/quollwriter/ui/charts/PerChapterWordCountsChart.java b/src/com/quollwriter/ui/charts/PerChapterWordCountsChart.java deleted file mode 100644 index 5515afbd..00000000 --- a/src/com/quollwriter/ui/charts/PerChapterWordCountsChart.java +++ /dev/null @@ -1,857 +0,0 @@ -package com.quollwriter.ui.charts; - -import java.awt.Component; -import java.awt.Dimension; -import java.awt.Font; -import java.awt.event.*; - -import java.util.*; - -import javax.swing.*; -import javax.swing.border.*; -import javax.swing.tree.*; -import javax.swing.event.*; - -import org.jfree.chart.*; -import org.jfree.ui.*; -import org.jfree.data.time.*; -import org.jfree.chart.plot.*; -import org.jfree.chart.labels.*; -import org.jfree.chart.axis.*; -import org.jfree.data.category.*; -import org.jfree.chart.renderer.category.*; - -import static com.quollwriter.LanguageStrings.*; -import static com.quollwriter.Environment.getUIString; - -import com.quollwriter.*; -import com.quollwriter.data.*; -import com.quollwriter.ui.events.*; -import com.quollwriter.ui.*; -import com.quollwriter.ui.panels.*; -import com.quollwriter.db.*; -import com.quollwriter.ui.renderers.*; -import com.quollwriter.ui.components.Header; - -public class PerChapterWordCountsChart extends AbstractQuollChart -{ - - public static final String CHART_TYPE = "per-chapter-word-counts"; - //public static final String CHART_TITLE = "{Chapter} Word Counts"; - - private JFreeChart chart = null; - private JComponent detail = null; - private JComponent controls = null; - private JComboBox displayB = null; - private JTree chapters = null; - private JCheckBox showAvg = null; - private JCheckBox showTarget = null; - private JComponent opts = null; - - public PerChapterWordCountsChart (AbstractProjectViewer pv) - { - - super (pv); - - } - - public void init (StatisticsPanel wcp) - throws GeneralException - { - - super.init (wcp); - - this.createControls (); - - } - - private void createControls () - { - - java.util.List prefix = Arrays.asList (charts, perchapter, labels); - - final PerChapterWordCountsChart _this = this; - - Box b = new Box (BoxLayout.Y_AXIS); - b.setOpaque (false); - - this.showAvg = UIUtils.createCheckBox (getUIString (prefix,showaverage), - //"Show Average", - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - _this.updateChart (); - - } - - }); - - this.showTarget = UIUtils.createCheckBox (getUIString (prefix,showtarget), - //"Show Target", - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - TargetsData targets = _this.viewer.getProjectTargets (); - - if (targets.getMaxChapterCount () == 0) - { - - final java.util.List prefix = Arrays.asList (charts,perchapter,notarget,popup); - - UIUtils.createQuestionPopup (_this.viewer, - getUIString (prefix,title), - //"Set up Target", - Constants.TARGET_ICON_NAME, - getUIString (prefix,text), - //"You currently have no {chapter} word count target set up.

    Would you like to set the target now?

    Note: Targets can be accessed at any time from the {Project} menu.", - getUIString (prefix,buttons,confirm), - //"Yes, show me", - getUIString (prefix,buttons,cancel), - //"No, not now", - new ActionListener () - { - - @Override public void actionPerformed (ActionEvent ev) - { - - try - { - - _this.viewer.viewTargets (); - - } catch (Exception e) { - - Environment.logError ("Unable to show targets", - e); - - UIUtils.showErrorMessage (_this.viewer, - getUIString (charts,perchapter,notarget,actionerror)); - //)"Unable to show targets."); - - } - - } - - }, - null, - null, - null); - - _this.showTarget.setSelected (false); - - return; - - } - - _this.updateChart (); - - } - - }); - - this.opts = new Box (BoxLayout.Y_AXIS); - - b.add (this.opts); - - this.opts.setBorder (UIUtils.createPadding (0, 10, 0, 0)); - - this.opts.add (this.showAvg); - this.opts.add (this.showTarget); - - Header h = UIUtils.createBoldSubHeader (getUIString (prefix,_for), - //Environment.replaceObjectNames ("For"), - null); - h.setAlignmentY (Component.TOP_ALIGNMENT); - - b.add (h); - - Vector displayItems = new Vector (); - displayItems.add (getUIString (times, now)); - displayItems.add (getUIString (times, thisweek)); - displayItems.add (getUIString (times, lastweek)); - displayItems.add (getUIString (times, thismonth)); - displayItems.add (getUIString (times, lastmonth)); - displayItems.add (getUIString (times, alltime)); - - b.add (Box.createVerticalStrut (5)); - - this.displayB = new JComboBox (displayItems); - this.displayB.setAlignmentX (Component.LEFT_ALIGNMENT); - this.displayB.setMaximumSize (displayB.getPreferredSize ()); - - this.displayB.setAlignmentY (Component.TOP_ALIGNMENT); - - this.displayB.addActionListener (new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - _this.opts.setVisible (_this.displayB.getSelectedIndex () == 0); - - _this.updateChart (); - - } - - }); - - Box db = new Box (BoxLayout.X_AXIS); - db.setAlignmentX (Component.LEFT_ALIGNMENT); - db.setAlignmentY (Component.TOP_ALIGNMENT); - - db.add (Box.createHorizontalStrut (5)); - - db.add (this.displayB); - db.setMaximumSize (db.getPreferredSize ()); - - b.add (db); - - b.add (Box.createVerticalStrut (10)); - - h = UIUtils.createBoldSubHeader (getUIString (charts,perchapter,labels,forchapters), - //"For these {Chapters}"), - null); - h.setOpaque (false); - h.setAlignmentY (Component.TOP_ALIGNMENT); - - b.add (h); - - this.chapters = UIUtils.createTree (); - this.chapters.setModel (new DefaultTreeModel (UIUtils.createTree (this.viewer.getProject ().getBook (0), - new ArrayList (), /* exclude */ - this.viewer.getProject ().getBook (0).getChapters (), /* init */ - true))); - - this.chapters.getModel ().addTreeModelListener (new TreeModelAdapter () - { - - public void treeNodesChanged (TreeModelEvent ev) - { - - // Don't care what has changed, just trigger an update to the - // chart. - _this.updateChart (); - - } - - }); - - SelectableProjectTreeCellRenderer rend = new SelectableProjectTreeCellRenderer (); - - rend.setShowIcons (false); - - this.chapters.setCellRenderer (rend); - UIUtils.addSelectableListener (this.chapters); - - this.chapters.setOpaque (false); - - this.chapters.setRootVisible (false); - this.chapters.setShowsRootHandles (false); - this.chapters.setBorder (UIUtils.createPadding (0, 5, 0, 0)); - - // Never toggle. - this.chapters.setToggleClickCount (-1); - - this.chapters.setMaximumSize (this.chapters.getPreferredSize ()); - this.chapters.setAlignmentX (Component.LEFT_ALIGNMENT); - - b.add (this.chapters); - - this.controls = b; - - } - - private void createChart () - throws GeneralException - { - - if (this.displayB.getSelectedIndex () == 0) - { - - this.createCurrentChart (); - - return; - - } - - this.createHistoryChart (); - - } - - private void createCurrentChart () - throws GeneralException - { - - final PerChapterWordCountsChart _this = this; - - ChapterDataHandler dh = (ChapterDataHandler) this.viewer.getDataHandler (Chapter.class); - - Set selected = new HashSet (); - - UIUtils.getSelectedObjects ((DefaultMutableTreeNode) this.chapters.getModel ().getRoot (), - selected); - - int chapterCount = 0; - int totalWords = 0; - int maxWords = 0; - Chapter maxChap = null; - - final DefaultCategoryDataset ds = new DefaultCategoryDataset (); - - try - { - - for (Book book : this.viewer.getProject ().getBooks ()) - { - - for (Chapter c : book.getChapters ()) - { - - if (!selected.contains (c)) - { - - continue; - - } - - ChapterCounts cc = this.viewer.getChapterCounts (c); - - if (cc.wordCount > 0) - { - - chapterCount++; - - } - - totalWords += cc.wordCount; - - if (cc.wordCount > maxWords) - { - - maxChap = c; - maxWords = cc.wordCount; - - } - - ds.addValue (cc.wordCount, - "Chapters", - c.getName ()); - - } - - } - - } catch (Exception e) - { - - Environment.logError ("Unable to get word counts", - e); - - UIUtils.showErrorMessage (this.parent, - getUIString (charts,actionerror)); - //"Unable to show word counts"); - - return; - - } - - java.util.List prefix = Arrays.asList (charts, perchapter, labels); - - this.chart = QuollChartUtils.createBarChart (getUIString (prefix,xaxis), - //Environment.getObjectTypeNamePlural (Chapter.OBJECT_TYPE), - getUIString (prefix,yaxis), - //"Word Count", - ds); - - this.chart.setBackgroundPaint (UIUtils.getComponentColor ()); - this.chart.removeLegend (); - - CategoryPlot plot = (CategoryPlot) this.chart.getPlot (); - - final CategoryAxis domainAxis = plot.getDomainAxis(); - domainAxis.setCategoryLabelPositions (CategoryLabelPositions.STANDARD);//CategoryLabelPositions.createUpRotationLabelPositions (Math.PI / 0.5)); - - plot.setOrientation (PlotOrientation.HORIZONTAL); - plot.setRangeAxisLocation (AxisLocation.BOTTOM_OR_LEFT); - - QuollChartUtils.customizePlot (plot); - - CategoryToolTipGenerator ttgen = new StandardCategoryToolTipGenerator () - { - - public String generateToolTip (CategoryDataset dataset, - int row, - int column) - { - - DefaultCategoryDataset dsc = (DefaultCategoryDataset) dataset; - - Number n = dsc.getValue (row, - column); -/* - StringBuilder b = new StringBuilder (); - - b.append (Environment.formatNumber (n.intValue ())); - b.append (" words "); -*/ - return String.format (getUIString (charts, perchapter, tooltip), - Environment.formatNumber (n.intValue ())); - //b.toString (); - - } - - }; - - ((CategoryItemRenderer) plot.getRenderer ()).setSeriesToolTipGenerator (0, - ttgen); - - TargetsData ptargs = this.viewer.getProjectTargets (); - - int targetWords = ptargs.getMaxChapterCount (); - - double avgWords = 0; - - if (chapterCount > 0) - { - - avgWords = totalWords / chapterCount; - - } - - double diffAvgWords = avgWords - targetWords; - - if (this.showAvg.isSelected ()) - { - - String tgf = ""; - - if (targetWords > 0) - { - - tgf = String.format (getUIString (charts,perchapter,markers,averagesuffix), - //", %s%s target", - (diffAvgWords < 0 ? "" : "+") + Environment.formatNumber ((long) diffAvgWords)); - - } - - plot.addRangeMarker (QuollChartUtils.createMarker (String.format (getUIString (charts,perchapter,markers,average), - //"Avg %s%s", - Environment.formatNumber ((long) avgWords), - tgf), - avgWords, - 1, - org.jfree.ui.RectangleAnchor.TOP_RIGHT)); - - } - - if (this.showTarget.isSelected ()) - { - - if (targetWords > 0) - { - - plot.addRangeMarker (QuollChartUtils.createMarker (String.format (getUIString (charts,perchapter,markers,target), - //"Target %s", - Environment.formatNumber (targetWords)), - targetWords, - -1, - org.jfree.ui.RectangleAnchor.BOTTOM_LEFT)); - - } - - } - - int over = 0; - - for (Chapter c : selected) - { - - ChapterCounts cc = this.viewer.getChapterCounts (c); - - if (cc.wordCount > targetWords) - { - - over++; - - } - - } - - //((NumberAxis) plot.getRangeAxis ()).setAutoRangeIncludesZero (true); - - Set items = new LinkedHashSet (); - - if ((targetWords > 0) - && - (over > 0) - ) - { - - String t = String.format (getUIString (prefix, chaptersovertarget, text), - //"%s {Chapter%s} over target word count", - Environment.formatNumber (over)); - //(over == 1 ? "" : "s")); - - // TODO: Fix this nonsense. - ActionListener _null = null; - - final JLabel l = this.createWarningLabel (UIUtils.createClickableLabel (t, - null, - _null)); - - UIUtils.makeClickable (l, - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - Targets.showChaptersOverWordTarget (_this.viewer, - l); - - } - - }); - - l.setToolTipText (getUIString (prefix,chaptersovertarget,tooltip)); - //"Click to view the " + t); - - items.add (l); - - } - - items.add (this.createDetailLabel (String.format (getUIString (prefix,average), - //"%s - Average word count", - Environment.formatNumber ((long) avgWords)))); - - this.detail = QuollChartUtils.createDetailPanel (items); - - } - - private void createHistoryChart () - throws GeneralException - { - - java.util.List prefix = Arrays.asList (charts,perchapter,history,labels); - - int days = -1; - - Date minDate = null; - Date maxDate = new Date (); - - // This week. - if (this.displayB.getSelectedIndex () == 1) - { - - // Work out how many days there have been this week. - GregorianCalendar gc = new GregorianCalendar (); - - days = gc.get (Calendar.DAY_OF_WEEK) - gc.getFirstDayOfWeek (); - - if (days < 0) - { - - days -= 7; - - } - - gc.add (Calendar.DATE, - -1 * days); - - minDate = gc.getTime (); - - days++; - - } - - // Last week - if (this.displayB.getSelectedIndex () == 2) - { - - GregorianCalendar gc = new GregorianCalendar (); - - days = gc.get (Calendar.DAY_OF_WEEK) - gc.getFirstDayOfWeek (); - - if (days < 0) - { - - days -= 7; - - } - - gc.add (Calendar.DATE, - (-1 * days) - 1); - - maxDate = gc.getTime (); - - days += 7; - - gc.add (Calendar.DATE, - -6); - - minDate = gc.getTime (); - - days++; - - } - - // This month. - if (this.displayB.getSelectedIndex () == 3) - { - - GregorianCalendar gc = new GregorianCalendar (); - - days = gc.get (Calendar.DATE); - - gc.set (Calendar.DATE, - 1); - - minDate = gc.getTime (); - - days++; - - } - - // Last month. - if (this.displayB.getSelectedIndex () == 4) - { - - GregorianCalendar gc = new GregorianCalendar (); - - gc.add (Calendar.MONTH, - -1); - - days = gc.getActualMaximum (Calendar.DATE); - - gc.set (Calendar.DATE, - days); - - maxDate = gc.getTime (); - - gc.set (Calendar.DATE, - 1); - - minDate = gc.getTime (); - - days++; - - } - - // All time - if (this.displayB.getSelectedIndex () == 5) - { - - days = 1; - - } - - ChapterDataHandler dh = (ChapterDataHandler) this.viewer.getDataHandler (Chapter.class); - - Set selected = new HashSet (); - - UIUtils.getSelectedObjects ((DefaultMutableTreeNode) this.chapters.getModel ().getRoot (), - selected); - - final TimeSeriesCollection tscc = new TimeSeriesCollection (); - - try - { - - for (Book book : this.viewer.getProject ().getBooks ()) - { - - for (Chapter c : book.getChapters ()) - { - - if (!selected.contains (c)) - { - - continue; - - } - - TimeSeries ts = new TimeSeries (c.getName ()); - - // Get all the word counts for the chapter. - List wordCounts = dh.getWordCounts (c, - 0);// * days); - - for (WordCount wc : wordCounts) - { - - if (ts.getValue (new Day (wc.getEnd ())) == null) - { - - ts.add (new Day (wc.getEnd ()), - wc.getCount ()); - - } - - } - - ts.setRangeDescription (c.getName ()); - - tscc.addSeries (ts); - - } - - } - - } catch (Exception e) - { - - Environment.logError ("Unable to get word counts", - e); - - UIUtils.showErrorMessage (this.parent, - getUIString (charts,actionerror)); - //"Unable to show word counts"); - - return; - - } - - this.chart = QuollChartUtils.createTimeSeriesChart (getUIString (prefix,xaxis), - //"Date", - getUIString (prefix,yaxis), - //"Word Count", - tscc); - this.chart.setBackgroundPaint (UIUtils.getComponentColor ()); - - XYPlot plot = (XYPlot) this.chart.getPlot (); - - PeriodAxis axis = (PeriodAxis) plot.getDomainAxis (); - - if (minDate != null) - { - - axis.setLowerBound (minDate.getTime ()); - - axis.setUpperBound (maxDate.getTime ()); - - } - - plot.setBackgroundPaint (UIUtils.getComponentColor ()); - plot.setDomainGridlinePaint (Environment.getBorderColor ()); - plot.setRangeGridlinePaint (Environment.getBorderColor ()); - plot.setAxisOffset (new RectangleInsets (5D, - 5D, - 5D, - 5D)); - - Font f = QuollChartUtils.getLabelFont (); - - plot.setDomainCrosshairVisible (true); - plot.setRangeCrosshairVisible (true); - plot.setDomainGridlinePaint (UIUtils.getColor ("#cfcfcf")); - plot.setRangeGridlinePaint (UIUtils.getColor ("#cfcfcf")); - plot.getDomainAxis ().setLabelFont (f); - plot.getDomainAxis ().setTickLabelFont (f); - plot.getRangeAxis ().setLabelFont (f); - plot.getRangeAxis ().setTickLabelFont (f); - - //QuollChartUtils.customizePlot (xyplot); - - this.detail = null; - - } - - public String getTitle () - { - - return getUIString (charts,perchapter,title); - //return CHART_TITLE; - - } - - public String getType () - { - - return CHART_TYPE; - - } - - public JComponent getControls (boolean update) - throws GeneralException - { - - if (update) - { - - this.controls = null; - - } - - if (this.controls == null) - { - - this.createControls (); - - } - - return this.controls; - - } - - public JFreeChart getChart (boolean update) - throws GeneralException - { - - if (update) - { - - this.chart = null; - - } - - if (this.chart == null) - { - - this.createChart (); - - } - - return this.chart; - - } - - public JComponent getDetail (boolean update) - throws GeneralException - { - - if (update) - { - - this.detail = null; - - } - - if (this.detail == null) - { - - this.createChart (); - - } - - return this.detail; - - } - - public String toString () - { - - return this.getTitle (); - - } - -} diff --git a/src/com/quollwriter/ui/charts/ReadabilityIndicesChart.java b/src/com/quollwriter/ui/charts/ReadabilityIndicesChart.java deleted file mode 100644 index cb7ff3f7..00000000 --- a/src/com/quollwriter/ui/charts/ReadabilityIndicesChart.java +++ /dev/null @@ -1,972 +0,0 @@ -package com.quollwriter.ui.charts; - -import java.awt.Component; -import java.awt.Dimension; -import java.awt.BasicStroke; -import java.awt.event.*; - -import java.util.*; - -import javax.swing.*; -import javax.swing.border.*; -import javax.swing.tree.*; -import javax.swing.event.*; - -import org.jfree.chart.*; -import org.jfree.ui.*; -import org.jfree.data.time.*; -import org.jfree.data.category.*; -import org.jfree.chart.axis.*; -import org.jfree.chart.plot.*; - -import static com.quollwriter.LanguageStrings.*; -import static com.quollwriter.Environment.getUIString; - -import com.quollwriter.*; -import com.quollwriter.events.*; -import com.quollwriter.data.*; -import com.quollwriter.ui.events.*; -import com.quollwriter.ui.*; -import com.quollwriter.ui.panels.*; -import com.quollwriter.db.*; -import com.quollwriter.ui.renderers.*; -import com.quollwriter.ui.components.Header; - -public class ReadabilityIndicesChart extends AbstractQuollChart -{ - - public static final String CHART_TYPE = "readability-index"; - //public static final String CHART_TITLE = "Readability"; - - private JFreeChart chart = null; - private JComponent detail = null; - private JComponent controls = null; - private JCheckBox showGF = null; - private JCheckBox showFK = null; - private JTree chapters = null; - private JCheckBox showAvg = null; - private JCheckBox showTargets = null; - - public ReadabilityIndicesChart (AbstractProjectViewer pv) - { - - super (pv); - - } - - public void init (StatisticsPanel wcp) - throws GeneralException - { - - super.init (wcp); - - this.createControls (); - - } - - private void createControls () - { - - final java.util.List prefix = Arrays.asList (charts,readability,labels); - - final ReadabilityIndicesChart _this = this; - - Box b = new Box (BoxLayout.Y_AXIS); - b.setOpaque (false); - - this.showGF = UIUtils.createCheckBox (getUIString (prefix,showgf), - //"Show Gunning Fog", - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - _this.updateChart (); - - } - - }); - - this.showGF.setSelected (true); - - this.showGF.addActionListener (new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - if (!_this.showGF.isSelected ()) - { - - _this.showFK.setSelected (true); - - } - } - - }); - - this.showFK = UIUtils.createCheckBox (getUIString (prefix,showfk), - //"Show Flesch-Kincaid", - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - _this.updateChart (); - - } - - }); - - this.showFK.setSelected (true); - - this.showFK.addActionListener (new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - if (!_this.showFK.isSelected ()) - { - - _this.showGF.setSelected (true); - - } - } - - }); - - this.showAvg = UIUtils.createCheckBox (getUIString (prefix,showaverage), - //"Show Average", - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - _this.updateChart (); - - } - - }); - - this.showTargets = UIUtils.createCheckBox (getUIString (prefix,showtargets), - //)"Show Targets", - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - java.util.List prefix = Arrays.asList (charts,readability,notargets,popup); - - TargetsData targets = _this.viewer.getProjectTargets (); - - if ((targets.getReadabilityGF () == 0) - && - (targets.getReadabilityFK () == 0) - ) - { - - UIUtils.createQuestionPopup (_this.viewer, - getUIString (prefix,title), - //"Set up Targets", - Constants.TARGET_ICON_NAME, - getUIString (prefix,text), - //"You currently have no readability targets set up.

    Would you like to set the targets now?

    Note: Targets can be accessed at any time from the {Project} menu.", - getUIString (prefix,buttons,confirm), - //"Yes, show me", - getUIString (prefix,buttons,cancel), - //"No, not now", - new ActionListener () - { - - @Override public void actionPerformed (ActionEvent ev) - { - - try - { - - _this.viewer.viewTargets (); - - } catch (Exception e) { - - Environment.logError ("Unable to show targets", - e); - - UIUtils.showErrorMessage (_this.viewer, - getUIString (charts,readability,notargets,actionerror)); - //"Unable to show targets."); - - } - - } - - }, - null, - null, - null); - - _this.showTargets.setSelected (false); - - return; - - } - - _this.updateChart (); - - } - - }); - - Box opts = new Box (BoxLayout.Y_AXIS); - - b.add (opts); - - opts.setBorder (UIUtils.createPadding (0, 10, 0, 0)); - - opts.add (this.showFK); - opts.add (this.showGF); - opts.add (this.showAvg); - opts.add (this.showTargets); - - b.add (Box.createVerticalStrut (10)); - - Header h = UIUtils.createBoldSubHeader (getUIString (prefix,forchapters), - //"For these {Chapters}"), - null); - h.setOpaque (false); - h.setAlignmentY (Component.TOP_ALIGNMENT); - - b.add (h); - - Set init = new LinkedHashSet (); - - for (Chapter c : this.viewer.getProject ().getBook (0).getChapters ()) - { - - ChapterCounts cc = _this.viewer.getChapterCounts (c); - - if (cc.wordCount > Constants.MIN_READABILITY_WORD_COUNT) - { - - init.add (c); - - } - - } - - this.chapters = new JTree (UIUtils.createTree (this.viewer.getProject ().getBook (0), - new ArrayList (), /* exclude */ - init, /* init */ - true)); - - this.chapters.setOpaque (false); - ToolTipManager.sharedInstance().registerComponent (this.chapters); - - this.chapters.getModel ().addTreeModelListener (new TreeModelAdapter () - { - - public void treeNodesChanged (TreeModelEvent ev) - { - - // Don't care what has changed, just trigger an update to the - // chart. - _this.updateChart (); - - } - - }); - - SelectableProjectTreeCellRenderer rend = new SelectableProjectTreeCellRenderer () - { - - @Override - public boolean shouldEnable (Object v) - { - - if (v instanceof Chapter) - { - - Chapter c = (Chapter) v; - - ChapterCounts cc = _this.viewer.getChapterCounts (c); - - return cc.wordCount >= Constants.MIN_READABILITY_WORD_COUNT; - - } - - return true; - - } - - @Override - public String getToolTipText (Object v) - { - - if (v instanceof Chapter) - { - - Chapter c = (Chapter) v; - - ChapterCounts cc = _this.viewer.getChapterCounts (c); - - if (cc.wordCount < Constants.MIN_READABILITY_WORD_COUNT) - { - - return getUIString (charts,readability,excluded,single,tooltip); -/* - if (cc.wordCount == 0) - { - - return Environment.replaceObjectNames ("This {chapter} is excluded because it has no words."); - - } else { - - return String.format (getUIString (charts,readability,exlcuded,tooltip) - //"This {chapter} is excluded because it only has %s word%s.", - Environment.formatNumber (cc.wordCount)); - //(cc.wordCount == 1 ? "" : "s"))); - - } -*/ - } - - } - - return super.getToolTipText (v); - - } - - }; - - rend.setShowIcons (false); - this.chapters.setCellRenderer (rend); - - this.chapters.addMouseListener (new MouseEventHandler () - { - - private void selectAllChildren (DefaultTreeModel model, - DefaultMutableTreeNode n, - boolean v) - { - - Enumeration en = n.children (); - - while (en.hasMoreElements ()) - { - - DefaultMutableTreeNode c = en.nextElement (); - - SelectableDataObject s = (SelectableDataObject) c.getUserObject (); - - s.selected = v; - - // Tell the model that something has changed. - model.nodeChanged (c); - - // Iterate. - this.selectAllChildren (model, - c, - v); - - } - - } - - @Override - public void handlePress (MouseEvent ev) - { - - TreePath tp = _this.chapters.getPathForLocation (ev.getX (), - ev.getY ()); - - if (tp != null) - { - - DefaultMutableTreeNode n = (DefaultMutableTreeNode) tp.getLastPathComponent (); - - // Tell the model that something has changed. - DefaultTreeModel model = (DefaultTreeModel) _this.chapters.getModel (); - - SelectableDataObject s = (SelectableDataObject) n.getUserObject (); - - if (s.obj instanceof Chapter) - { - - Chapter c = (Chapter) s.obj; - - ChapterCounts cc = _this.viewer.getChapterCounts (c); - - if (cc.wordCount < Constants.MIN_READABILITY_WORD_COUNT) - { - - return; - - } - - - } - - s.selected = !s.selected; - - model.nodeChanged (n); - - } - - } - - }); - - //UIUtils.addSelectableListener (this.chapters); - - this.chapters.setRootVisible (false); - this.chapters.setShowsRootHandles (false); - this.chapters.setScrollsOnExpand (true); - this.chapters.setBorder (UIUtils.createPadding (0, 5, 0, 0)); - - // Never toggle. - this.chapters.setToggleClickCount (-1); - - this.chapters.setAlignmentX (Component.LEFT_ALIGNMENT); - - b.add (this.chapters); - - this.controls = b; - - } - - private void createChart () - throws GeneralException - { - - java.util.List prefix = Arrays.asList (charts,readability,labels); - - final ReadabilityIndicesChart _this = this; - - ChapterDataHandler dh = (ChapterDataHandler) this.viewer.getDataHandler (Chapter.class); - - Set selected = new HashSet (); - - UIUtils.getSelectedObjects ((DefaultMutableTreeNode) this.chapters.getModel ().getRoot (), - selected); - - int chapterCount = 0; - float totalFK = 0; - float totalGF = 0; - float maxFK = 0; - float maxGF = 0; - float showMax = 0; - int filteredCount = 0; - - final DefaultCategoryDataset ds = new DefaultCategoryDataset (); - - try - { - - for (Book book : this.viewer.getProject ().getBooks ()) - { - - for (Chapter c : book.getChapters ()) - { - - ChapterCounts cc = this.viewer.getChapterCounts (c); - - // Filter out chapters with less than the min readability word count. - if (cc.wordCount < Constants.MIN_READABILITY_WORD_COUNT) - { - - filteredCount++; - - continue; - - } - - if (!selected.contains (c)) - { - - continue; - - } - - ReadabilityIndices ri = this.viewer.getReadabilityIndices (c); - - float fk = ri.getFleschKincaidGradeLevel (); - float gf = ri.getGunningFogIndex (); - - chapterCount++; - totalFK += fk; - totalGF += gf; - - maxFK = Math.max (maxFK, fk); - maxGF = Math.max (maxGF, gf); - - if (this.showFK.isSelected ()) - { - - ds.addValue (fk, - getUIString (prefix, LanguageStrings.fk), - //"Flesch-Kincaid", - c.getName ()); - - } - - if (this.showGF.isSelected ()) - { - - ds.addValue (gf, - getUIString (prefix, LanguageStrings.gf), - //"Gunning Fog", - c.getName ()); - - } - - } - - } - - } catch (Exception e) - { - - Environment.logError ("Unable to get word counts", - e); - - UIUtils.showErrorMessage (this.parent, - getUIString (charts,actionerror)); - //"Unable to word counts"); - - return; - - } - - this.chart = QuollChartUtils.createBarChart (getUIString (prefix,yaxis), - //Environment.getObjectTypeNamePlural (Chapter.OBJECT_TYPE), - getUIString (prefix,xaxis), - //"Reading Level", - ds); - - this.chart.setBackgroundPaint (UIUtils.getComponentColor ()); - - CategoryPlot plot = (CategoryPlot) this.chart.getPlot (); - - QuollChartUtils.customizePlot (plot); - - final CategoryAxis domainAxis = plot.getDomainAxis(); - domainAxis.setCategoryLabelPositions (CategoryLabelPositions.STANDARD);//CategoryLabelPositions.createUpRotationLabelPositions (Math.PI / 0.5)); - - plot.setOrientation (PlotOrientation.HORIZONTAL); - plot.setRangeAxisLocation (AxisLocation.BOTTOM_OR_LEFT); - - TargetsData ptargs = this.viewer.getProjectTargets (); - - int targetGF = ptargs.getReadabilityGF (); - int targetFK = ptargs.getReadabilityFK (); - - double avgGF = 0; - double avgFK = 0; - - if (chapterCount > 0) - { - - avgGF = totalGF / chapterCount; - avgFK = totalFK / chapterCount; - - } - - double diffAvgGF = avgGF - targetGF; - - boolean showGF = this.showGF.isSelected (); - boolean showFK = this.showFK.isSelected (); - - if (this.showAvg.isSelected ()) - { - - String tgf = ""; - - if ((targetGF > 0) - && - (showGF) - ) - { - - tgf = String.format (getUIString (charts,readability,markers,averagegfsuffix), - //", %s%s target", - (diffAvgGF < 0 ? "" : "+") + Environment.formatNumber (diffAvgGF)); - - } - - RectangleAnchor anch = RectangleAnchor.TOP_LEFT; - - if (avgGF > avgFK) - { - - anch = RectangleAnchor.TOP_RIGHT; - - } - - plot.addRangeMarker (QuollChartUtils.createMarker (String.format (getUIString (charts,readability,markers,averagegf), - //"Avg GF %s%s", - Environment.formatNumber (avgGF), - tgf), - avgGF, - 1, - anch)); - - String tfk = ""; - - if ((targetFK > 0) - && - (showFK) - ) - { - - double diffAvgFK = avgFK - targetFK; - - tfk = String.format (getUIString (charts,readability,markers,averagefksuffix), - //", %s%s target", - (diffAvgFK < 0 ? "" : "+") + Environment.formatNumber (diffAvgFK)); - - } - - anch = RectangleAnchor.TOP_LEFT; - - if (avgFK > avgGF) - { - - anch = RectangleAnchor.TOP_RIGHT; - - } - - plot.addRangeMarker (QuollChartUtils.createMarker (String.format (getUIString (charts,readability,markers,averagefk), - //"Avg FK %s%s", - Environment.formatNumber (avgFK), - tfk), - avgFK, - 0, - anch)); - - } - - if (this.showTargets.isSelected ()) - { - - RectangleAnchor anch = RectangleAnchor.BOTTOM_LEFT; - - if (targetGF > targetFK) - { - - anch = RectangleAnchor.BOTTOM_RIGHT; - - } - - if ((targetGF > 0) - && - (showGF) - ) - { - - plot.addRangeMarker (QuollChartUtils.createMarker (String.format (getUIString (charts,readability,markers,targetgf), - //"GF Target %s", - Environment.formatNumber (targetGF)), - targetGF, - -1, - anch)); - - } - - anch = RectangleAnchor.BOTTOM_LEFT; - - if (targetFK > targetGF) - { - - anch = RectangleAnchor.BOTTOM_RIGHT; - - } - - if (targetGF > maxGF) - { - - showMax = targetGF + 1; - - } - - if ((targetFK > 0) - && - (showFK) - ) - { - - plot.addRangeMarker (QuollChartUtils.createMarker (String.format (getUIString (charts,readability,markers,targetfk), - //"FK Target %s", - Environment.formatNumber (targetFK)), - targetFK, - -1, - anch)); - - } - - if ((targetFK > maxFK) - && - (targetFK > showMax) - ) - { - - showMax = targetFK + 1; - - } - - if (showMax > 0) - { - - ((NumberAxis) plot.getRangeAxis()).setUpperBound (showMax); - - } - - } - - int overGF = 0; - int overFK = 0; - - for (Chapter c : selected) - { - - ReadabilityIndices ri = this.viewer.getReadabilityIndices (c); - - float fk = ri.getFleschKincaidGradeLevel (); - float gf = ri.getGunningFogIndex (); - - if (fk > targetFK) - { - - overFK++; - - } - - if (gf > targetGF) - { - - overGF++; - - } - - } - - ((NumberAxis) plot.getRangeAxis ()).setAutoRangeIncludesZero (true); - - Set items = new LinkedHashSet (); - - if ((targetFK > 0) - && - (overFK > 0) - && - (showFK) - ) - { - - String t = String.format (getUIString (charts,readability,labels,overtargetfk), - //"%s {Chapter%s} over target Flesch-Kincaid", - Environment.formatNumber (overFK)); - //(overFK == 1 ? singular : plural)); - - // TODO: Fix this nonsense. - ActionListener _null = null; - - final JLabel l = this.createWarningLabel (UIUtils.createClickableLabel (t, - null, - _null)); - - UIUtils.makeClickable (l, - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - Targets.showChaptersOverReadabilityTarget (_this.viewer, - l); - - } - - }); - - l.setToolTipText (getUIString (charts,readability,labels,clicktoview)); - //"Click to view"); - - items.add (l); - - } - - if ((targetGF > 0) - && - (overGF > 0) - && - (showGF) - ) - { - - String t = String.format (getUIString (charts,readability,labels,overtargetgf), - //"%s {Chapter%s} over target Gunning Fog", - Environment.formatNumber (overGF)); - //(overGF == 1 ? "" : "s")); - - // TODO: Fix this nonsense. - ActionListener _null = null; - - final JLabel l = this.createDetailLabel (UIUtils.createClickableLabel (t, - null, - _null)); - - l.setIcon (Environment.getIcon (Constants.ERROR_ICON_NAME, - Constants.ICON_MENU)); - - UIUtils.makeClickable (l, - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - Targets.showChaptersOverReadabilityTarget (_this.viewer, - l); - - } - - }); - - l.setToolTipText (getUIString (charts,readability,labels,clicktoview)); - //"Click to view the " + t); - - items.add (l); - - } - - if (filteredCount > 0) - { - - items.add (this.createWarningLabel (String.format (getUIString (charts,readability,excluded,plural,text), - //"%s {chapters} have less than %s words and have been excluded", - Environment.formatNumber (filteredCount)))); - //Environment.formatNumber (Constants.MIN_READABILITY_WORD_COUNT)))); - - } - - if (showFK) - { - - items.add (this.createDetailLabel (String.format (getUIString (charts,readability,labels,averagefk), - //"%s - Average Flesch-Kincaid", - Environment.formatNumber (avgFK)))); - - } - - if (showGF) - { - - items.add (this.createDetailLabel (String.format (getUIString (charts,readability,labels,averagegf), - //"%s - Average Gunning Fog", - Environment.formatNumber (avgGF)))); - - } - - this.detail = QuollChartUtils.createDetailPanel (items); - - } - - public String getTitle () - { - - return getUIString (charts,readability,title); - //CHART_TITLE; - - } - - public String getType () - { - - return CHART_TYPE; - - } - - public JComponent getControls (boolean update) - { - - if (update) - { - - this.controls = null; - - } - - if (this.controls == null) - { - - this.createControls (); - - } - - return this.controls; - - } - - public JFreeChart getChart (boolean update) - throws GeneralException - { - - if (update) - { - - this.chart = null; - - } - - if (this.chart == null) - { - - this.createChart (); - - } - - return this.chart; - - } - - public JComponent getDetail (boolean update) - throws GeneralException - { - - if (update) - { - - this.detail = null; - - } - - if (this.detail == null) - { - - this.createChart (); - - } - - return this.detail; - - } - - public String toString () - { - - return this.getTitle (); - - } - -} diff --git a/src/com/quollwriter/ui/charts/SessionTimeChart.java b/src/com/quollwriter/ui/charts/SessionTimeChart.java deleted file mode 100644 index c4bb1283..00000000 --- a/src/com/quollwriter/ui/charts/SessionTimeChart.java +++ /dev/null @@ -1,700 +0,0 @@ -package com.quollwriter.ui.charts; - -import java.awt.Component; -import java.awt.Dimension; -import java.awt.Font; -import java.awt.event.*; - -import java.text.*; -import java.util.*; - -import javax.swing.*; -import javax.swing.border.*; -import javax.swing.tree.*; -import javax.swing.event.*; - -import org.jfree.chart.*; -import org.jfree.chart.labels.StandardXYToolTipGenerator; -import org.jfree.chart.labels.XYToolTipGenerator; -import org.jfree.ui.*; -import org.jfree.data.time.*; -import org.jfree.data.xy.XYDataset; -import org.jfree.chart.renderer.xy.*; -import org.jfree.chart.axis.*; -import org.jfree.chart.plot.*; - -import static com.quollwriter.LanguageStrings.*; -import static com.quollwriter.Environment.getUIString; - -import com.quollwriter.*; -import com.quollwriter.data.*; -import com.quollwriter.ui.events.*; -import com.quollwriter.ui.*; -import com.quollwriter.ui.panels.*; -import com.quollwriter.db.*; -import com.quollwriter.ui.renderers.*; -import com.quollwriter.ui.components.Header; - -public class SessionTimeChart extends AbstractQuollChart -{ - - public static final String CHART_TYPE = "session-time"; - //public static final String CHART_TITLE = "Session Length"; - - private JFreeChart chart = null; - private JComponent controls = null; - private JComboBox displayB = null; - private JCheckBox showAvg = null; - private JCheckBox showZeroWordCount = null; - private JComponent detail = null; - - public SessionTimeChart (AbstractViewer v) - { - - super (v); - - } - - public void init (StatisticsPanel wcp) - throws GeneralException - { - - super.init (wcp); - - this.createControls (); - - } - - private void createControls () - { - - final SessionTimeChart _this = this; - - Box b = new Box (BoxLayout.Y_AXIS); - b.setOpaque (false); - - Header h = UIUtils.createBoldSubHeader (getUIString (charts,sessionlength,labels,_for), - //"For", - null); - h.setAlignmentY (Component.TOP_ALIGNMENT); - - b.add (h); - - Vector displayItems = new Vector (); - displayItems.add (getUIString (times,thisweek));//"This week"); - displayItems.add (getUIString (times,lastweek));//"Last week"); - displayItems.add (getUIString (times,thismonth));//"This month"); - displayItems.add (getUIString (times,lastmonth));//"Last month"); - displayItems.add (getUIString (times,alltime));//"All time"); - - b.add (Box.createVerticalStrut (5)); - - this.displayB = new JComboBox (displayItems); - this.displayB.setAlignmentX (Component.LEFT_ALIGNMENT); - this.displayB.setMaximumSize (displayB.getPreferredSize ()); - - this.displayB.setAlignmentY (Component.TOP_ALIGNMENT); - - this.displayB.addActionListener (new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - _this.updateChart (); - - } - - }); - - Box db = new Box (BoxLayout.X_AXIS); - db.setAlignmentX (Component.LEFT_ALIGNMENT); - db.setAlignmentY (Component.TOP_ALIGNMENT); - - db.add (Box.createHorizontalStrut (5)); - - db.add (this.displayB); - db.setMaximumSize (db.getPreferredSize ()); - - b.add (db); - - b.add (Box.createVerticalStrut (10)); - - this.showAvg = UIUtils.createCheckBox (getUIString (charts,sessionlength,labels,showaverage),//"Show Average", - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - _this.updateChart (); - - } - - }); - - this.showZeroWordCount = UIUtils.createCheckBox (getUIString (charts,sessionlength,labels,showzero),//"Show zero word count sessions", - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - _this.updateChart (); - - } - - }); - - Box opts = new Box (BoxLayout.Y_AXIS); - - b.add (opts); - - opts.setBorder (UIUtils.createPadding (0, 10, 0, 0)); - - opts.add (this.showAvg); - opts.add (this.showZeroWordCount); - - this.controls = b; - - } - - private void createChart () - throws GeneralException - { - - java.util.List lprefix = Arrays.asList (charts,sessionlength,labels); - java.util.List mprefix = Arrays.asList (charts,sessionlength,markers); - - int days = -1; - - Date minDate = null; - Date maxDate = new Date (); - - // This week. - if (this.displayB.getSelectedIndex () == 0) - { - - // Work out how many days there have been this week. - GregorianCalendar gc = new GregorianCalendar (); - - days = gc.get (Calendar.DAY_OF_WEEK) - gc.getFirstDayOfWeek (); - - if (days < 0) - { - - days -= 7; - - } - - gc.add (Calendar.DATE, - -1 * days); - - minDate = gc.getTime (); - - } - - // Last week - if (this.displayB.getSelectedIndex () == 1) - { - - GregorianCalendar gc = new GregorianCalendar (); - - days = gc.get (Calendar.DAY_OF_WEEK) - gc.getFirstDayOfWeek (); - - if (days < 0) - { - - days -= 7; - - } - - gc.add (Calendar.DATE, - (-1 * days) - 1); - - maxDate = gc.getTime (); - - days += 7; - - gc.add (Calendar.DATE, - -6); - - minDate = gc.getTime (); - - } - - // This month. - if (this.displayB.getSelectedIndex () == 2) - { - - GregorianCalendar gc = new GregorianCalendar (); - - days = gc.get (Calendar.DATE); - - gc.set (Calendar.DATE, - 1); - - minDate = gc.getTime (); - - } - - // Last month. - if (this.displayB.getSelectedIndex () == 3) - { - - GregorianCalendar gc = new GregorianCalendar (); - - gc.add (Calendar.MONTH, - -1); - - days = gc.getActualMaximum (Calendar.DATE); - - gc.set (Calendar.DATE, - days); - - maxDate = gc.getTime (); - - gc.set (Calendar.DATE, - 1); - - minDate = gc.getTime (); - - } - - // All time - if (this.displayB.getSelectedIndex () == 4) - { - - days = -1; - - } - - long avg = 0; - long total = 0; - long sessions = 0; - long max = 0; - Date maxSessStart = null; - long zeroSessions = 0; - long zeroSessionsTime = 0; - long longSessions = 0; - long totalWords = 0; - - final TimePeriodValuesCollection ds = new TimePeriodValuesCollection (); - - try - { - - TimePeriodValues vals = new TimePeriodValues (getUIString (lprefix, LanguageStrings.sessions));//"Sessions"); - - for (Session s : Environment.getSessions (days)) - { - - int wc = s.getWordCount (); - - if ((!this.showZeroWordCount.isSelected ()) - && - (wc == 0) - ) - { - - continue; - - } - - if (days == -1) - { - - if (minDate == null) - { - - minDate = s.getStart (); - - } - - if (s.getStart ().before (minDate)) - { - - minDate = s.getStart (); - - } - - } - - long time = s.getEnd ().getTime () - s.getStart ().getTime (); - - if (time < 60 * 1000) - { - - continue; - - } - - if (wc == 0) - { - - zeroSessions++; - zeroSessionsTime += time; - - } - - totalWords += wc; - - total += time; - - if ((time > 1 * 60 * 60 * 1000) - && - (wc > 0) - ) - { - - longSessions++; - - } - - if (time > max) - { - - max = time; - maxSessStart = s.getStart (); - - } - - sessions++; - - vals.add (new SimpleTimePeriod (s.getStart (), - s.getEnd ()), - time); - - } - - ds.addSeries (vals); - - } catch (Exception e) - { - - Environment.logError ("Unable to get sessions", - e); - - UIUtils.showErrorMessage (this.parent, - getUIString (charts,actionerror)); - //"Unable to show sessions"); - - return; - - } - - if (sessions > 0) - { - - avg = total / sessions; - - } - - if (minDate == null) - { - - minDate = new Date (); - - } - - this.chart = QuollChartUtils.createTimeSeriesChart (getUIString (lprefix,xaxis),//"Date", - getUIString (lprefix,yaxis),//"Duration", - ds); - - this.chart.removeLegend (); - - this.chart.setBackgroundPaint (UIUtils.getComponentColor ()); - - XYPlot xyplot = (XYPlot) this.chart.getPlot (); - - PeriodAxis axis = (PeriodAxis) xyplot.getDomainAxis (); - - if (minDate != null) - { - - axis.setLowerBound (minDate.getTime ()); - - axis.setUpperBound (maxDate.getTime ()); - - } - - QuollChartUtils.customizePlot (xyplot); - - if (this.showAvg.isSelected ()) - { - - xyplot.addRangeMarker (QuollChartUtils.createMarker (String.format (getUIString (mprefix,average),//"Avg %s", - Utils.formatAsDuration (avg)), - avg, - 0)); - - } - - ((NumberAxis) xyplot.getRangeAxis ()).setAutoRangeIncludesZero (true); - - ((NumberAxis) xyplot.getRangeAxis ()).setNumberFormatOverride (new NumberFormat () - { - - @Override - public StringBuffer format (double number, - StringBuffer toAppendTo, - FieldPosition pos) - { - - return new StringBuffer (Utils.formatAsDuration (number)); - - } - - @Override - public StringBuffer format (long number, - StringBuffer toAppendTo, - FieldPosition pos) - { - - return new StringBuffer (Utils.formatAsDuration (number)); - - } - - @Override - public Number parse(String source, ParsePosition parsePosition) { - return null; - } - - }); - - long min = 60 * 1000; - long hour = 60 * min; - long day = 24 * hour; - - // Default 5 min tick. - long tick = 5 * min; - - if (max > (hour)) - { - - tick = 20 * min; - - } - - if (max > (3 * hour)) - { - - tick = 30 * min; - - } - - if (max > (6 * hour)) - { - - tick = hour; - - } - - if (max > (12 * hour)) - { - - tick = 2 * hour; - - } - - if (max > (day)) - { - - tick = 3 * hour; - - } - - if (max > (2 * day)) - { - - tick = 6 * hour; - - } - - if (max > (3 * day)) - { - - tick = 12 * hour; - - } - - if (max > (5 * day)) - { - - tick = day; - - } - - ((NumberAxis) xyplot.getRangeAxis ()).setTickUnit (new NumberTickUnit (tick) - { - - @Override - public String valueToString (double number) - { - - return Utils.formatAsDuration (number); - - } - - }); - - final SimpleDateFormat dateFormat = new SimpleDateFormat ("hh:mm a, EEE, dd MMM yyyy"); - - XYToolTipGenerator ttgen = new StandardXYToolTipGenerator () - { - - public String generateToolTip (XYDataset dataset, - int series, - int item) - { - - TimePeriodValuesCollection tsc = (TimePeriodValuesCollection) dataset; - - TimePeriodValues ts = tsc.getSeries (series); - - Number n = ts.getValue (item); - - return String.format (getUIString (charts,sessionlength,tooltip), - dateFormat.format (ts.getTimePeriod (item).getStart ()), - Utils.formatAsDuration (n.intValue ())); - - } - - }; - - ((XYBarRenderer) xyplot.getRenderer ()).setSeriesToolTipGenerator (0, - ttgen); - - Set items = new LinkedHashSet (); - - items.add (this.createDetailLabel (String.format (getUIString (lprefix,numsessions),//"%s - Session%s", - Environment.formatNumber (sessions)))); - //(sessions == 1 ? "" : "s")))); - - items.add (this.createDetailLabel (String.format (getUIString (lprefix,sessionsover1hr),//"%s - Session%s over 1 hour", - Environment.formatNumber (longSessions)))); - //(longSessions == 1 ? "" : "s")))); - - items.add (this.createDetailLabel (String.format (getUIString (lprefix,totalwords),//"%s - Words total", - Environment.formatNumber (totalWords)))); - - items.add (this.createDetailLabel (String.format (getUIString (lprefix,totalsessiontime),//"%s - Total session time", - Utils.formatAsDuration (total)))); - - items.add (this.createDetailLabel (String.format (getUIString (lprefix,averagesessionlength),//"%s - Average session length", - Utils.formatAsDuration (avg)))); - - if (maxSessStart != null) - { - - items.add (this.createDetailLabel (String.format (getUIString (lprefix,longestsession),//"%s, %s - Longest session", - Utils.formatAsDuration (max), - Environment.formatDateTime (maxSessStart)))); - - } - - if (this.showZeroWordCount.isSelected ()) - { - - items.add (this.createDetailLabel (String.format (getUIString (lprefix,numzerowordsessions),//"%s, %s - Zero word count sessions", - Environment.formatNumber (zeroSessions), - Utils.formatAsDuration (zeroSessionsTime)))); - - } - - this.detail = QuollChartUtils.createDetailPanel (items); - - } - - public String getTitle () - { - - return getUIString (charts,sessionlength,title); - //CHART_TITLE; - - } - - public String getType () - { - - return CHART_TYPE; - - } - - public JComponent getControls (boolean update) - throws GeneralException - { - - if (update) - { - - this.controls = null; - - } - - if (this.controls == null) - { - - this.createControls (); - - } - - return this.controls; - - } - - public JFreeChart getChart (boolean update) - throws GeneralException - { - - if (update) - { - - this.chart = null; - - } - - if (this.chart == null) - { - - this.createChart (); - - } - - return this.chart; - - } - - public JComponent getDetail (boolean update) - throws GeneralException - { - - if (update) - { - - this.chart = null; - - } - - if (this.chart == null) - { - - this.createChart (); - - } - - return this.detail; - - } - - public String toString () - { - - return this.getTitle (); - - } - -} diff --git a/src/com/quollwriter/ui/charts/SessionWordCountChart.java b/src/com/quollwriter/ui/charts/SessionWordCountChart.java deleted file mode 100644 index b913bf77..00000000 --- a/src/com/quollwriter/ui/charts/SessionWordCountChart.java +++ /dev/null @@ -1,673 +0,0 @@ -package com.quollwriter.ui.charts; - -import java.awt.Component; -import java.awt.Dimension; -import java.awt.Font; -import java.awt.event.*; - -import java.text.*; -import java.util.*; - -import javax.swing.*; -import javax.swing.border.*; -import javax.swing.tree.*; -import javax.swing.event.*; - -import org.jfree.chart.*; -import org.jfree.ui.*; -import org.jfree.chart.labels.StandardXYToolTipGenerator; -import org.jfree.chart.labels.XYToolTipGenerator; -import org.jfree.data.time.*; -import org.jfree.data.xy.XYDataset; -import org.jfree.chart.renderer.xy.*; -import org.jfree.chart.axis.*; -import org.jfree.chart.plot.*; - -import static com.quollwriter.LanguageStrings.*; -import static com.quollwriter.Environment.getUIString; - -import com.quollwriter.*; -import com.quollwriter.data.*; -import com.quollwriter.ui.events.*; -import com.quollwriter.ui.*; -import com.quollwriter.ui.panels.*; -import com.quollwriter.db.*; -import com.quollwriter.ui.renderers.*; -import com.quollwriter.ui.components.Header; - -public class SessionWordCountChart extends AbstractQuollChart -{ - - public static final String CHART_TYPE = "session-word-count"; - //public static final String CHART_TITLE = "Session Word Count"; - - private JFreeChart chart = null; - private JComponent controls = null; - private JComboBox displayB = null; - private JCheckBox showAvg = null; - private JCheckBox showTarget = null; - private JComponent detail = null; - - public SessionWordCountChart (AbstractViewer v) - { - - super (v); - - } - - public void init (StatisticsPanel wcp) - throws GeneralException - { - - super.init (wcp); - - this.createControls (); - - } - - private void createControls () - { - - final SessionWordCountChart _this = this; - - Box b = new Box (BoxLayout.Y_AXIS); - b.setOpaque (false); - - Header h = UIUtils.createBoldSubHeader (getUIString (charts,sessionwordcount,labels,_for), - //"For"), - null); - h.setAlignmentY (Component.TOP_ALIGNMENT); - - b.add (h); - - Vector displayItems = new Vector (); - displayItems.add (getUIString (times,thisweek));//"This week"); - displayItems.add (getUIString (times,lastweek));//"Last week"); - displayItems.add (getUIString (times,thismonth));//"This month"); - displayItems.add (getUIString (times,lastmonth));//"Last month"); - displayItems.add (getUIString (times,alltime));//"All time"); - - b.add (Box.createVerticalStrut (5)); - - this.displayB = new JComboBox (displayItems); - this.displayB.setAlignmentX (Component.LEFT_ALIGNMENT); - this.displayB.setMaximumSize (displayB.getPreferredSize ()); - - this.displayB.setAlignmentY (Component.TOP_ALIGNMENT); - - this.displayB.addActionListener (new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - _this.updateChart (); - - } - - }); - - Box db = new Box (BoxLayout.X_AXIS); - db.setAlignmentX (Component.LEFT_ALIGNMENT); - db.setAlignmentY (Component.TOP_ALIGNMENT); - - db.add (Box.createHorizontalStrut (5)); - - db.add (this.displayB); - db.setMaximumSize (db.getPreferredSize ()); - - b.add (db); - - b.add (Box.createVerticalStrut (10)); - - this.showAvg = UIUtils.createCheckBox (getUIString (charts,sessionwordcount,labels,showaverage), - //"Show Average", - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - _this.updateChart (); - - } - - }); - - this.showTarget = UIUtils.createCheckBox (getUIString (charts,sessionwordcount,labels,showtarget),//"Show Target", - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - TargetsData targets = Environment.getUserTargets (); - - if ((targets.getMySessionWriting () == 0) - ) - { - - java.util.List prefix = Arrays.asList (charts,sessionwordcount,notarget,popup); - - UIUtils.createQuestionPopup (_this.viewer, - getUIString (prefix,title),//"Set up Target", - Constants.TARGET_ICON_NAME, - getUIString (prefix,text), - //"You currently have no writing targets set up.

    Would you like to set the targets now?

    Note: Targets can be accessed at any time from the {Project} menu.", - getUIString (prefix,buttons,confirm), - //"Yes, show me", - getUIString (prefix,buttons,cancel), - //"No, not now", - new ActionListener () - { - - @Override public void actionPerformed (ActionEvent ev) - { - - try - { - - _this.viewer.viewTargets (); - - } catch (Exception e) { - - Environment.logError ("Unable to show targets", - e); - - UIUtils.showErrorMessage (_this.viewer, - getUIString (charts,sessionwordcount,notarget,actionerror)); - //"Unable to show targets."); - - } - - } - - }, - null, - null, - null); - - _this.showTarget.setSelected (false); - - return; - - } - - _this.updateChart (); - - } - - }); - - Box opts = new Box (BoxLayout.Y_AXIS); - - b.add (opts); - - opts.setBorder (UIUtils.createPadding (0, 5, 0, 0)); - - opts.add (this.showAvg); - opts.add (this.showTarget); - - this.controls = b; - - } - - private void createChart () - throws GeneralException - { - - int days = -1; - - Date minDate = null; - Date maxDate = new Date (); - - // This week. - if (this.displayB.getSelectedIndex () == 0) - { - - // Work out how many days there have been this week. - GregorianCalendar gc = new GregorianCalendar (); - - days = gc.get (Calendar.DAY_OF_WEEK) - gc.getFirstDayOfWeek (); - - if (days < 0) - { - - days -= 7; - - } - - gc.add (Calendar.DATE, - -1 * days); - - minDate = gc.getTime (); - - } - - // Last week - if (this.displayB.getSelectedIndex () == 1) - { - - GregorianCalendar gc = new GregorianCalendar (); - - days = gc.get (Calendar.DAY_OF_WEEK) - gc.getFirstDayOfWeek (); - - if (days < 0) - { - - days -= 7; - - } - - gc.add (Calendar.DATE, - (-1 * days) - 1); - - maxDate = gc.getTime (); - - days += 7; - - gc.add (Calendar.DATE, - -6); - - minDate = gc.getTime (); - - } - - // This month. - if (this.displayB.getSelectedIndex () == 2) - { - - GregorianCalendar gc = new GregorianCalendar (); - - days = gc.get (Calendar.DATE); - - gc.set (Calendar.DATE, - 1); - - minDate = gc.getTime (); - - } - - // Last month. - if (this.displayB.getSelectedIndex () == 3) - { - - GregorianCalendar gc = new GregorianCalendar (); - - gc.add (Calendar.MONTH, - -1); - - days = gc.getActualMaximum (Calendar.DATE); - - gc.set (Calendar.DATE, - days); - - maxDate = gc.getTime (); - - gc.set (Calendar.DATE, - 1); - - minDate = gc.getTime (); - - } - - // All time - if (this.displayB.getSelectedIndex () == 4) - { - - days = -1; - - } - - long sessions = 0; - long totalWords = 0; - long totalTime = 0; - long sessionsAboveTarget = 0; - long longSessions = 0; - long maxTime = 0; - long maxWords = 0; - Session maxWordsSession = null; - Session longestSession = null; - int target = Environment.getUserTargets ().getMySessionWriting (); - - java.util.List prefix = Arrays.asList (charts,sessionwordcount,labels); - - final TimePeriodValuesCollection ds = new TimePeriodValuesCollection (); - - try - { - - TimePeriodValues vals = new TimePeriodValues (getUIString (prefix, LanguageStrings.sessions));//"Sessions"); - - for (Session s : Environment.getSessions (days)) - { - - int wc = s.getWordCount (); - - if (wc == 0) - { - - continue; - - } - - if (wc > target) - { - - sessionsAboveTarget++; - - } - - if (days == -1) - { - - if (minDate == null) - { - - minDate = s.getStart (); - - } - - if (s.getStart ().before (minDate)) - { - - minDate = s.getStart (); - - } - - } - - long time = s.getEnd ().getTime () - s.getStart ().getTime (); - - totalTime += time; - totalWords += wc; - sessions++; - - if (time > 60 * 60 * 1000) - { - - longSessions++; - - } - - if (time > maxTime) - { - - maxTime = time; - - longestSession = s; - - } - - if (wc > maxWords) - { - - maxWords = wc; - maxWordsSession = s; - - } - - vals.add (new SimpleTimePeriod (s.getStart (), - s.getEnd ()), - wc); - - } - - ds.addSeries (vals); - - } catch (Exception e) - { - - Environment.logError ("Unable to get sessions", - e); - - UIUtils.showErrorMessage (this.parent, - getUIString (charts,actionerror)); - //"Unable to sessions"); - - return; - - } - - if (minDate == null) - { - - minDate = new Date (); - - } - - this.chart = QuollChartUtils.createTimeSeriesChart (getUIString (prefix,xaxis),//"Date", - getUIString (prefix,yaxis),//"Word Count", - ds); - - this.chart.removeLegend (); - - XYPlot xyplot = (XYPlot) this.chart.getPlot (); - - PeriodAxis axis = (PeriodAxis) xyplot.getDomainAxis (); - - if (minDate != null) - { - - axis.setLowerBound (minDate.getTime ()); - - axis.setUpperBound (maxDate.getTime ()); - - } - - QuollChartUtils.customizePlot (xyplot); - - if (this.showAvg.isSelected ()) - { - - long avgWords = (sessions > 0 ? totalWords / sessions : 0); - - String t = ""; - - if (target > 0) - { - - double diffAvg = avgWords - target; - - t = String.format (getUIString (prefix,averagesuffix),//", %s%s target", - (diffAvg < 0 ? "" : "+") + Environment.formatNumber ((long) diffAvg)); - - } - - xyplot.addRangeMarker (QuollChartUtils.createMarker (String.format (getUIString (prefix,average),//"Avg %s%s", - Environment.formatNumber (avgWords), - t), - avgWords, - 0)); - - } - - if (this.showTarget.isSelected ()) - { - - if (target > maxWords) - { - - ((NumberAxis) xyplot.getRangeAxis()).setUpperBound (target + 100); - - } - xyplot.addRangeMarker (QuollChartUtils.createMarker (String.format (getUIString (prefix, LanguageStrings.target),//"Target %s", - Environment.formatNumber (target)), - target, - -1)); - - } - - this.chart.setBackgroundPaint (UIUtils.getComponentColor ()); - - final SimpleDateFormat dateFormat = new SimpleDateFormat ("hh:mm a, EEE, dd MMM yyyy"); - - XYToolTipGenerator ttgen = new StandardXYToolTipGenerator () - { - - public String generateToolTip (XYDataset dataset, - int series, - int item) - { - - TimePeriodValuesCollection tsc = (TimePeriodValuesCollection) dataset; - - TimePeriodValues ts = tsc.getSeries (series); - - Number n = ts.getValue (item); - - return String.format (getUIString (charts,sessionwordcount,tooltip), - dateFormat.format (ts.getTimePeriod (item).getStart ()), - Utils.formatAsDuration (n.intValue ())); -/* - StringBuilder b = new StringBuilder (); - - b.append (dateFormat.format (ts.getTimePeriod (item).getStart ())); - b.append (", "); - - b.append (Utils.formatAsDuration (n.intValue ())); - - return b.toString (); -*/ - } - - }; - - ((XYBarRenderer) xyplot.getRenderer ()).setSeriesToolTipGenerator (0, - ttgen); - - Set items = new LinkedHashSet (); - - items.add (this.createDetailLabel (String.format (getUIString (prefix,numsessions),//"%s - Session%s", - Environment.formatNumber (sessions)))); - //(sessions == 1 ? "" : "s")))); - - if (this.showTarget.isSelected ()) - { - - items.add (this.createDetailLabel (String.format (getUIString (prefix,sessionsovertarget),//"%s - Sessions above word target", - Environment.formatNumber (sessionsAboveTarget)))); - - } - - if (sessions > 0) - { - - // Work out number of sessions over target. - - items.add (this.createDetailLabel (String.format (getUIString (prefix,sessionsover1hr),//"%s - Session%s over 1 hr", - Environment.formatNumber (longSessions)))); - //(longSessions == 1 ? "" : "s")))); - - items.add (this.createDetailLabel (String.format (getUIString (prefix,averagesession),//"%s words, %s - Average session", - Environment.formatNumber (totalWords / sessions), - Utils.formatAsDuration (totalTime / sessions)))); - - items.add (this.createDetailLabel (String.format (getUIString (prefix,longestsession),//"%s words, %s, %s, - Longest session", - Environment.formatNumber (longestSession.getWordCount ()), - Utils.formatAsDuration (longestSession.getSessionDuration ()), - Environment.formatDateTime (longestSession.getStart ())))); - - items.add (this.createDetailLabel (String.format (getUIString (prefix,sessionmostwords),//"%s words, %s, %s - Session with most words", - Environment.formatNumber (maxWordsSession.getWordCount ()), - Utils.formatAsDuration (maxWordsSession.getSessionDuration ()), - Environment.formatDateTime (maxWordsSession.getStart ())))); - - } - - this.detail = QuollChartUtils.createDetailPanel (items); - - } - - public String getTitle () - { - - return getUIString (charts,sessionwordcount,title); - //CHART_TITLE; - - } - - public String getType () - { - - return CHART_TYPE; - - } - - public JComponent getControls (boolean update) - throws GeneralException - { - - if (update) - { - - this.controls = null; - - } - - if (this.controls == null) - { - - this.createControls (); - - } - - return this.controls; - - } - - public JFreeChart getChart (boolean update) - throws GeneralException - { - - if (update) - { - - this.chart = null; - - } - - if (this.chart == null) - { - - this.createChart (); - - } - - return this.chart; - - } - - public JComponent getDetail (boolean update) - throws GeneralException - { - - if (update) - { - - this.detail = null; - - } - - if (this.detail == null) - { - - this.createChart (); - - } - - return this.detail; - - } - - public String toString () - { - - return this.getTitle (); - - } - -} diff --git a/src/com/quollwriter/ui/components/CompoundUndoManager.java b/src/com/quollwriter/ui/components/CompoundUndoManager.java deleted file mode 100644 index 563a6cbb..00000000 --- a/src/com/quollwriter/ui/components/CompoundUndoManager.java +++ /dev/null @@ -1,398 +0,0 @@ -/** - * Taken from: http://tips4java.wordpress.com/2008/10/27/compound-undo-manager/ - * - * All credit to: Rob Camick - */ -package com.quollwriter.ui.components; - -import java.awt.*; -import java.awt.event.*; - -import javax.swing.*; -import javax.swing.event.*; -import javax.swing.text.*; -import javax.swing.undo.*; - - -public class CompoundUndoManager extends UndoManager implements UndoableEditListener, - DocumentListener -{ - - - class MyCompoundEdit extends CompoundEdit - { - public boolean isInProgress () - { - // in order for the canUndo() and canRedo() methods to work - // assume that the compound edit is never in progress - - return false; - } - - public void undo () - throws CannotUndoException - { - // End the edit so future edits don't get absorbed by this edit - - if (compoundEdit != null) - { - compoundEdit.end (); - } - - super.undo (); - - // Always start a new compound edit after an undo - - compoundEdit = null; - } - } - - /* - * Perform the Undo and update the state of the undo/redo Actions - */ - class UndoAction extends AbstractAction - { - public UndoAction() - { - putValue (Action.NAME, - "Undo"); - putValue (Action.SHORT_DESCRIPTION, - getValue (Action.NAME)); - putValue (Action.MNEMONIC_KEY, - new Integer (KeyEvent.VK_U)); - putValue (Action.ACCELERATOR_KEY, - KeyStroke.getKeyStroke ("control Z")); - setEnabled (false); - } - - public void actionPerformed (ActionEvent e) - { - - try - { - undoManager.undo (); - textComponent.requestFocusInWindow (); - } catch (CannotUndoException ex) - { - } - - updateUndoState (); - redoAction.updateRedoState (); - } - - private void updateUndoState () - { - setEnabled (undoManager.canUndo ()); - } - } - - /* - * Perform the Redo and update the state of the undo/redo Actions - */ - class RedoAction extends AbstractAction - { - public RedoAction() - { - putValue (Action.NAME, - "Redo"); - putValue (Action.SHORT_DESCRIPTION, - getValue (Action.NAME)); - putValue (Action.MNEMONIC_KEY, - new Integer (KeyEvent.VK_R)); - putValue (Action.ACCELERATOR_KEY, - KeyStroke.getKeyStroke (KeyEvent.VK_Y, - InputEvent.CTRL_MASK)); - setEnabled (false); - } - - public void actionPerformed (ActionEvent e) - { - - try - { - undoManager.redo (); - textComponent.requestFocusInWindow (); - } catch (CannotRedoException ex) - { - } - - updateRedoState (); - undoAction.updateUndoState (); - } - - protected void updateRedoState () - { - setEnabled (undoManager.canRedo ()); - } - } - - private UndoManager undoManager; - private CompoundEdit compoundEdit; - private JTextComponent textComponent; - private UndoAction undoAction; - private RedoAction redoAction; - private boolean forceCompoundEdit = false; - - private boolean record = false; - - // These fields are used to help determine whether the edit is an - // incremental edit. The offset and length should increase by 1 for - // each character added or decrease by 1 for each character removed. - - private int lastOffset; - private int lastLength; - - public CompoundUndoManager(JTextComponent textComponent) - { - this.textComponent = textComponent; - undoManager = this; - undoAction = new UndoAction (); - redoAction = new RedoAction (); - textComponent.getDocument ().addUndoableEditListener (this); - } - - /* - ** Add a DocumentLister before the undo is done so we can position - ** the Caret correctly as each edit is undone. - */ - public void undo () - { - - textComponent.getDocument ().addDocumentListener (this); - super.undo (); - textComponent.getDocument ().removeDocumentListener (this); - - } - - /* - ** Add a DocumentLister before the redo is done so we can position - ** the Caret correctly as each edit is redone. - */ - public void redo () - { - textComponent.getDocument ().addDocumentListener (this); - super.redo (); - textComponent.getDocument ().removeDocumentListener (this); - } - - public void setRecordUndos (boolean v) - { - - this.record = v; - - } - - public boolean isRecordUndos () - { - - return this.record; - - } - - public void endCompoundEdit () - { - - this.forceCompoundEdit = false; - - compoundEdit.end (); - - compoundEdit = null; - - } - - public void startCompoundEdit () - { - - if (compoundEdit != null) - { - - compoundEdit.end (); - - compoundEdit = null; - - } - - this.forceCompoundEdit = true; - - } - - /* - ** Whenever an UndoableEdit happens the edit will either be absorbed - ** by the current compound edit or a new compound edit will be started - */ - public void undoableEditHappened (UndoableEditEvent e) - { - - // Start a new compound edit - - if (!this.record) - { - - return; - - } - - if (compoundEdit == null) - { - - compoundEdit = startCompoundEdit (e.getEdit ()); - - return; - } - - if (this.forceCompoundEdit) - { - - compoundEdit.addEdit (e.getEdit ()); - - return; - - } - - // Check for an attribute change - AbstractDocument.DefaultDocumentEvent event = (AbstractDocument.DefaultDocumentEvent) e.getEdit (); - - int offsetChange = textComponent.getCaretPosition () - lastOffset; - - if (event.getType ().equals (DocumentEvent.EventType.CHANGE)) - { - - if (offsetChange == 0) - { - - compoundEdit.end (); - compoundEdit = startCompoundEdit (e.getEdit ()); - - return; - } - } - - // Check for an incremental edit or backspace. - // The Change in Caret position and Document length should both be - // either 1 or -1. - -// int offsetChange = textComponent.getCaretPosition() - lastOffset; -// int lengthChange = textComponent.getDocument().getLength() - lastLength; - - - int lengthChange = textComponent.getDocument ().getLength () - lastLength; - - if ((offsetChange == lengthChange) && - (Math.abs (offsetChange) == 1)) - { - - String last = "x"; - - try - { - - last = this.textComponent.getText (this.textComponent.getCaretPosition () - 1, - 1); - - } catch (Exception ex) { - - // Ignore. - - } - - // Get the char, if it's white space then end the edit. - if (Character.isWhitespace (last.charAt (0))) - { - - compoundEdit.end (); - compoundEdit = startCompoundEdit (e.getEdit ()); - - } else { - - compoundEdit.addEdit (e.getEdit ()); - - } - - lastOffset = textComponent.getCaretPosition (); - lastLength = textComponent.getDocument ().getLength (); - - return; - } - - // Not incremental edit, end previous edit and start a new one - - compoundEdit.end (); - compoundEdit = startCompoundEdit (e.getEdit ()); - } - - /* - ** Each CompoundEdit will store a group of related incremental edits - ** (ie. each character typed or backspaced is an incremental edit) - */ - private CompoundEdit startCompoundEdit (UndoableEdit anEdit) - { - // Track Caret and Document information of this compound edit - - lastOffset = textComponent.getCaretPosition (); - lastLength = textComponent.getDocument ().getLength (); - - // The compound edit is used to store incremental edits - - compoundEdit = new MyCompoundEdit (); - compoundEdit.addEdit (anEdit); - - // The compound edit is added to the UndoManager. All incremental - // edits stored in the compound edit will be undone/redone at once - - addEdit (compoundEdit); - - undoAction.updateUndoState (); - redoAction.updateRedoState (); - - return compoundEdit; - } - - /* - * The Action to Undo changes to the Document. - * The state of the Action is managed by the CompoundUndoManager - */ - public Action getUndoAction () - { - return undoAction; - } - - /* - * The Action to Redo changes to the Document. - * The state of the Action is managed by the CompoundUndoManager - */ - public Action getRedoAction () - { - return redoAction; - } - -// -// Implement DocumentListener -// - /* - * Updates to the Document as a result of Undo/Redo will cause the - * Caret to be repositioned - */ - public void insertUpdate (final DocumentEvent e) - { - SwingUtilities.invokeLater (new Runnable () - { - public void run () - { - int offset = e.getOffset () + e.getLength (); - offset = Math.min (offset, - textComponent.getDocument ().getLength ()); - textComponent.setCaretPosition (offset); - } - }); - } - - public void removeUpdate (DocumentEvent e) - { - textComponent.setCaretPosition (e.getOffset ()); - } - - public void changedUpdate (DocumentEvent e) - { - } - -} diff --git a/src/com/quollwriter/ui/components/QSpellChecker.java b/src/com/quollwriter/ui/components/QSpellChecker.java deleted file mode 100644 index 1e74546b..00000000 --- a/src/com/quollwriter/ui/components/QSpellChecker.java +++ /dev/null @@ -1,821 +0,0 @@ -package com.quollwriter.ui.components; - -import java.awt.Color; -import java.awt.Point; -import java.awt.event.*; - -import java.util.List; -import java.util.Map; -import java.util.Timer; -import java.util.WeakHashMap; - -import javax.swing.*; -import javax.swing.event.*; -import javax.swing.text.*; - -import com.quollwriter.text.*; -import com.quollwriter.BlankTimerTask; -import com.quollwriter.DictionaryProvider2; -import com.quollwriter.synonyms.SynonymProvider; - -import com.quollwriter.ui.events.DictionaryChangedEvent; -import com.quollwriter.ui.events.DictionaryChangedListener; - -public class QSpellChecker implements DocumentListener, - CaretListener, - DictionaryChangedListener -{ - - private static final char NULL_CHAR = (char) 0; - - private QTextEditor text = null; - private SpellChecker checker = null; - private LinePainter painter = new LinePainter (Color.RED); - private Map elsToCheck = new WeakHashMap (); - private boolean enabled = false; - private int lastCaret = -1; - private char lastCharacterOver = QSpellChecker.NULL_CHAR; - private DictionaryProvider2 dictProvider = null; - private SynonymProvider synonymProvider = null; - - public QSpellChecker(QTextEditor text, - DictionaryProvider2 prov) - { - - this.text = text; - - this.text.getDocument ().addDocumentListener (this); - this.text.addCaretListener (this); - - this.setDictionaryProvider (prov); - - } - - public SynonymProvider getSynonymProvider () - { - - return this.synonymProvider; - - } - - public void setSynonymProvider (SynonymProvider sp) - { - - this.synonymProvider = sp; - - } - - public void setDictionaryProvider (DictionaryProvider2 dp) - { - - if (this.dictProvider != null) - { - - this.dictProvider.removeDictionaryChangedListener (this); - - } - - if (dp == null) - { - - this.checker = null; - this.dictProvider = null; - - return; - - } - - this.checker = dp.getSpellChecker (); - - //this.checker = new SpellChecker (); - - this.dictProvider = dp; - this.dictProvider.addDictionaryChangedListener (this); -/* - List dicts = dp.getDictionaries (); - - for (int i = 0; i < dicts.size (); i++) - { - - this.checker.addDictionary ((SpellDictionaryHashMap) (dicts.get (i))); - - } - - this.checker.setUserDictionary (dp.getUserDictionary ()); - - this.dictProvider = dp; - this.dictProvider.addDictionaryChangedListener (this); -*/ - } - - public void dictionaryChanged (DictionaryChangedEvent ev) - { - - if (ev.getType () == DictionaryChangedEvent.WORD_ADDED) - { - - // Recheck the document. - this.checkAll (); - - } - - if (ev.getType () == DictionaryChangedEvent.WORD_REMOVED) - { - - // Recheck the document. - this.checkAll (); - - } - - } - - public boolean isWordCorrect (Word word) - { - - if (this.checker == null) - { - - return false; - - } - - return this.checker.isCorrect (word); - -/* - if (w.isPunctuation ()) - { - - continue; - - } - - // See if the word is a number. - try - { - - Double.parseDouble (word); - - return true; - - } catch (Exception e) { - - // Not a number. - - } - - boolean v = this.checker.isCorrect (word) - || - this.checker.isIgnored (word); - - if (!v) - { - - // See if we have a synonym provider, if so check to see if the word ends with - // "s", "ed" or "er", if it does strip the ending then look for the synonym, if it has - // one then allow it through. - if (((word.endsWith ("s")) - || - (word.endsWith ("ed")) - || - (word.endsWith ("er")) - ) - && - (this.synonymProvider != null) - ) - { - - if (word.endsWith ("s")) - { - - word = word.substring (0, - word.length () - 1); - - } else { - - word = word.substring (0, - word.length () - 2); - - } - - try - { - - v = this.synonymProvider.hasSynonym (word); - - } catch (Exception e) { - - // Ignore it. - - } - - } - - } - - return v; -*/ - } - - public void addWord (String w) - { - - this.dictProvider.addWord (w); - - } - - public List getSuggestions (Point p) - { - - TextIterator ti = new TextIterator (this.text.getText ()); - - int start = this.text.viewToModel (p); - - Word word = null; - - if (start > -1) - { - - word = ti.getWordAt (start); - - } - - return this.getSuggestions (word); - - } - - public List getSuggestions (Word word) - { - - if (word == null) - { - - return null; - - } - - if (this.checker == null) - { - - return null; - - } - - return this.checker.getSuggestions (word); - - } - - public void checkElements (final int start) - { - - // Get the element for the offset. - final Element el; - - try - { - - el = ((AbstractDocument) this.text.getDocument ()).getParagraphElement (start); - - } catch (Exception ex) - { - - return; - - } - - // See if we have it scheduled for checking. - if (this.elsToCheck.containsKey (el)) - { - - // Already scheduled. - return; - - } - - this.elsToCheck.put (el, - el); - - final QSpellChecker _this = this; - - SwingUtilities.invokeLater (new Runnable () - { - - public void run () - { - - _this.checkElement (el); - - final Object o = new Object (); - - synchronized (o) - { - - _this.elsToCheck.remove (el); - - } - - } - - }); - - } - - private void checkElements (int start, - int length) - { - - int end = start + length; - - Document document = this.text.getDocument (); - - Element element; - - do - { - - try - { - - element = ((AbstractDocument) document).getParagraphElement (start); - - } catch (Exception ex) - { - - return; - - } - - this.checkElement (element); - - start = element.getEndOffset (); - - } while ((start <= end) && (start < document.getLength ())); - - } - - public void checkAll () - { - - Document document = this.text.getDocument (); - - for (int i = 0; i < document.getLength ();) - { - - Element el = null; - - try - { - - el = ((AbstractDocument) document).getParagraphElement (i); - - } catch (Exception e) - { - - // Need to funnel this back somewhere! - - } - - this.checkElements (i); - - i = el.getEndOffset (); - - } - - } - - private void clearAllHighlights () - { - - this.text.removeAllHighlights (this.painter); - - } - - public void checkElement (Element el) - { - - this.text.removeHighlightsForElement (el, - this.painter); - - if (!this.enabled) - { - - return; - - } - - int start = el.getStartOffset (); - - int docLength = this.text.getDocument ().getLength (); - - int end = el.getEndOffset (); - - if (start == end) - { - - return; - - } - - TextIterator ti = new TextIterator (this.text.getText ().substring (start, - end - 1)); - - List words = ti.getWords (); - - for (Word w : words) - { - - if (w.isPunctuation ()) - { - - continue; - - } - - //String word = w.getText (); - - if (!this.isWordCorrect (w)) - { - - try - { - - int wordStart = w.getAllTextStartOffset () + start; - int wordEnd = w.getAllTextEndOffset () + start; - - this.text.addHighlight (wordStart, - wordEnd, - this.painter, - false); - - } catch (Exception e) - { - - } - - } - - } - /* - int wordStart = -1; - int wordEnd = -1; - - while ((docTok.hasMoreWords ()) && - (docTok.getCurrentWordPosition () <= end)) - { - - String word = docTok.nextWord (); - - wordStart = docTok.getCurrentWordPosition (); - - wordEnd = docTok.getCurrentWordEnd (); - - if (wordEnd > docLength) - { - - wordEnd = docLength - 1; - - } - - if (wordStart >= wordEnd) - { - - continue; - - } - - if (!this.isWordCorrect (word)) - { - - try - { - - this.text.addHighlight (wordStart, - wordEnd, - this.painter, - false); - - } catch (Exception e) - { - - } - - } - - } - */ - - } - - public boolean isEnabled () - { - - return this.enabled; - - } - - public void enable (boolean v) - { - - boolean turningOn = (!this.enabled && v); - - this.enabled = v; - - if (turningOn) - { - - this.checkAll (); - - } else - { - - this.clearAllHighlights (); - - } - - } - - public void insertUpdate (DocumentEvent ev) - { - - if (!this.enabled) - { - - return; - - } - - if (ev.getLength () == 1) - { - - this.lastCharacterOver = QSpellChecker.NULL_CHAR; - - } - - if (ev.getLength () == 1) - { - - String t = null; - - try - { - - t = ev.getDocument ().getText (ev.getOffset (), - ev.getLength ()); - - } catch (Exception e) { - - // Wtf... - return; - - } - - if (t.trim ().length () == 0) - { - - // Check the previous element. - Element element; - - try - { - - element = ((AbstractDocument) ev.getDocument ()).getParagraphElement (ev.getOffset ()); - - } catch (Exception ex) - { - - return; - - } - - this.checkElement (element); - - } - - } else { - - this.checkElements (ev.getOffset (), - ev.getLength ()); - - } - - } - - public void changedUpdate (DocumentEvent ev) - { - - } - - public void removeUpdate (DocumentEvent ev) - { - - if (!this.enabled) - { - - return; - - } - - if (ev.getOffset () == 0) - { - - return; - - } - - if (ev.getLength () == 1) - { - - this.lastCharacterOver = QSpellChecker.NULL_CHAR; - - } - - if (ev.getLength () == 1) - { - - // Check the previous char, if there is one then don't check, if it's whitespace then check. - if (ev.getOffset () > 0) - { - - String t = null; - - try - { - - t = ev.getDocument ().getText (ev.getOffset () - 1, - ev.getLength ()); - - } catch (Exception e) { - - // Wtf... - return; - - } - - // Check the previous element. - Element element; - - try - { - - element = ((AbstractDocument) ev.getDocument ()).getParagraphElement (ev.getOffset ()); - - } catch (Exception ex) - { - - return; - - } - - this.checkElement (element); - - return; - - } - - } else { - - this.checkElements (ev.getOffset (), - ev.getLength ()); - - } - - } - - public void caretUpdate (CaretEvent ev) - { - - if (!this.enabled) - { - - return; - - } - - if (this.lastCaret == -1) - { - - this.lastCaret = ev.getDot (); - - return; - - } - - Document document = this.text.getDocument (); - - try - { - - Element oldEl = ((AbstractDocument) document).getParagraphElement (this.lastCaret); - Element newEl = ((AbstractDocument) document).getParagraphElement (ev.getDot ()); - - if (oldEl != newEl) - { - - this.checkElements (this.lastCaret); - - } else - { - - boolean d = false; - - if ((Math.max (this.lastCaret, - ev.getDot ()) - Math.min (this.lastCaret, - ev.getDot ())) > 1) - { - - this.checkElement (newEl); - - } else - { - - if (this.lastCharacterOver != QSpellChecker.NULL_CHAR) - { - - String text = this.text.getText (); - - if ((text.length () == 0) || - (ev.getDot () > (text.length () - 1))) - { - - return; - - } - - if ((Character.isWhitespace (this.lastCharacterOver)) && - (Character.isWhitespace (text.charAt (ev.getDot ())))) - { - - d = true; - - } - - try - { - - if (ev.getDot () < this.lastCaret) - { - - if ((!Character.isWhitespace (this.lastCharacterOver)) && - (Character.isWhitespace (text.charAt (ev.getDot ())))) - { - - d = true; - - } - - } else - { - - if (Character.isWhitespace (this.lastCharacterOver)) - { - - d = true; - - } - - } - - } catch (Exception e) - { - - com.quollwriter.Environment.logError ("HERE: ", - e); - - } - - } - - } - - if (d) - { - - this.checkElement (newEl); - - } - - } - - } catch (Exception e) - { - - return; - - } - - this.lastCaret = ev.getDot (); - - String t = this.text.getText (); - - if ((this.lastCaret >= t.length ()) || - (this.lastCaret < 0)) - { - - return; - - } - - this.lastCharacterOver = this.text.getText ().charAt (this.lastCaret); - - } - -} diff --git a/src/com/quollwriter/ui/components/QTextEditor.java b/src/com/quollwriter/ui/components/QTextEditor.java deleted file mode 100644 index 728fd6d6..00000000 --- a/src/com/quollwriter/ui/components/QTextEditor.java +++ /dev/null @@ -1,1672 +0,0 @@ -package com.quollwriter.ui.components; - -import java.awt.*; -import java.awt.event.*; - -import java.awt.datatransfer.*; - -import java.io.*; - -import java.util.ArrayList; -import java.util.List; -import java.util.Set; -import java.util.LinkedHashSet; - -import javax.swing.*; -import javax.swing.event.*; -import javax.swing.text.*; -import javax.swing.undo.*; - -import com.gentlyweb.utils.*; - -import com.quollwriter.StringWithMarkup; -import com.quollwriter.DictionaryProvider2; - -import com.quollwriter.text.*; - -import com.quollwriter.synonyms.SynonymProvider; - -public class QTextEditor extends JTextPane implements TextStylable -{ - - public static final String ALIGN_LEFT = "Left"; - public static final String ALIGN_RIGHT = "Right"; - public static final String ALIGN_JUSTIFIED = "Justified"; - - public static final String PASTE_ACTION_NAME = "__paste"; - public static final String COPY_ACTION_NAME = "__copy"; - public static final String CUT_ACTION_NAME = "__cut"; - public static final String UNDO_ACTION_NAME = "__undo"; - public static final String REDO_ACTION_NAME = "__redo"; - public static final String BOLD_ACTION_NAME = "bold"; - public static final String ITALIC_ACTION_NAME = "italic"; - public static final String UNDERLINE_ACTION_NAME = "underline"; - public static final String PRINT_ACTION_NAME = "print"; - - public CompoundUndoManager undoManager = null; - public QSpellChecker spellChecker = null; - private boolean loading = false; - public SimpleAttributeSet styles = new SimpleAttributeSet (); - private DefaultStyledDocument doc = null; - public Style sectionBreakStyle = null; - private String sectionBreak = null; - private Set styleChangeListeners = new LinkedHashSet (); - private LineHighlighter lineHighlighter = null; - private boolean canCopy = true; - private boolean canFormat = true; - - public QTextEditor(DictionaryProvider2 prov, - boolean spellCheckerEnabled) - { - - this.setCaret (new QCaret ()); - this.getCaret ().setBlinkRate (500); - - this.undoManager = new CompoundUndoManager (this); - - // Adapted from: https://community.oracle.com/thread/2376090 - // When there is a long contiguous piece of text it will prevent the text from - // wrapping. This allows the wrapping to occur. However it does not prevent the - // word wrapping from going nuts in text after this. - // The bug only triggers when the text is wider than the view. - /* - final ViewFactory vf = new ViewFactory () - { - - @Override - public View create (Element elem) - { - - String kind = elem.getName(); - - if (kind != null) - { - - if (kind.equals (AbstractDocument.ContentElementName)) - { - - return new LabelView (elem) - { - - @Override - public float getMinimumSpan (int axis) - { - - if (axis == View.X_AXIS) - { - - return 0; - - } - - if (axis == View.Y_AXIS) - { - - return super.getMinimumSpan (axis); - - } - - throw new IllegalArgumentException ("Invalid axis: " + axis); - - } - - }; - - } else if (kind.equals(AbstractDocument.ParagraphElementName)) { - return new ParagraphView(elem); - } else if (kind.equals(AbstractDocument.SectionElementName)) { - return new BoxView(elem, View.Y_AXIS); - } else if (kind.equals(StyleConstants.ComponentElementName)) { - return new ComponentView(elem); - } else if (kind.equals(StyleConstants.IconElementName)) { - return new IconView(elem); - } - - } - - // default to text display - return new LabelView (elem); - - } - - }; -*/ - this.setEditorKit (new QStyledEditorKit ()); -/* - { - - @Override - public ViewFactory getViewFactory () - { - - return vf; - - } - - }); - */ - this.initDocument (); - - this.setMargin (new Insets (5, - 5, - 0, - 5)); - - final QTextEditor _this = this; - - this.undoManager.discardAllEdits (); - - // Get the files. - this.spellChecker = new QSpellChecker (this, - prov); - this.spellChecker.enable (spellCheckerEnabled); - - ActionMap am = this.getActionMap (); - - am.put (REDO_ACTION_NAME, - new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - if (_this.undoManager.canRedo ()) - { - - _this.undoManager.redo (); - - } - - } - - }); - - am.put (UNDO_ACTION_NAME, - new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - if (_this.undoManager.canUndo ()) - { - - _this.undoManager.undo (); - - } - - } - - }); - - am.put (PRINT_ACTION_NAME, - new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - try - { - - _this._print (); - - } catch (Exception e) - { - - // e.printStackTrace (); - - } - - } - - }); - - am.put (BOLD_ACTION_NAME, - new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.toggleBold (); - - } - - }); - - am.put (ITALIC_ACTION_NAME, - new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.toggleItalic (); - - } - - }); - - am.put (UNDERLINE_ACTION_NAME, - new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.toggleUnderline (); - - } - - }); - - am.put (PASTE_ACTION_NAME, - new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.paste (); - - } - - }); - - am.put (COPY_ACTION_NAME, - new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.copy (); - - } - - }); - - am.put (CUT_ACTION_NAME, - new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.cut (); - - } - - }); -/* - am.put (UNDO_ACTION_NAME, - this.getEditor ().getUndoManager ().getUndoAction ()); - - am.put (REDO_ACTION_NAME, - this.getEditor ().getUndoManager ().getRedoAction ()); - */ -/* - am.put ("redo", - new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - if (_this.undoManager.canRedo ()) - { - - _this.undoManager.redo (); - - } - - } - - }); - - am.put ("undo", - new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - if (_this.undoManager.canUndo ()) - { - - _this.undoManager.undo (); - - } - - } - - }); - - am.put ("print", - new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - try - { - - _this._print (); - - } catch (Exception e) - { - - // e.printStackTrace (); - - } - - } - - }); - - am.put ("bold", - new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.toggleBold (); - - } - - }); - - am.put ("italic", - new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.toggleItalic (); - - } - - }); - - am.put ("underline", - new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.toggleUnderline (); - - } - - }); -*/ - InputMap im = this.getInputMap (JComponent.WHEN_IN_FOCUSED_WINDOW); - - im.put (KeyStroke.getKeyStroke (KeyEvent.VK_Z, - Event.CTRL_MASK), - UNDO_ACTION_NAME); - im.put (KeyStroke.getKeyStroke (KeyEvent.VK_Y, - Event.CTRL_MASK), - REDO_ACTION_NAME); - im.put (KeyStroke.getKeyStroke (KeyEvent.VK_P, - Event.CTRL_MASK), - PRINT_ACTION_NAME); - im.put (KeyStroke.getKeyStroke (KeyEvent.VK_B, - Event.CTRL_MASK), - BOLD_ACTION_NAME);//new StyledEditorKit.BoldAction ()); - im.put (KeyStroke.getKeyStroke (KeyEvent.VK_I, - Event.CTRL_MASK), - ITALIC_ACTION_NAME); - im.put (KeyStroke.getKeyStroke (KeyEvent.VK_U, - Event.CTRL_MASK), - UNDERLINE_ACTION_NAME); - - this.lineHighlighter = new LineHighlighter (Color.LIGHT_GRAY); - - } - - public void initDocument () - { - - this.doc = new DefaultStyledDocument (); - - this.doc.putProperty (DefaultEditorKit.EndOfLineStringProperty, - "\n"); - - this.sectionBreakStyle = this.doc.addStyle ("section-break", - null); - StyleConstants.setAlignment (this.sectionBreakStyle, - StyleConstants.ALIGN_CENTER); - - this.doc.addUndoableEditListener (this.undoManager); - - this.doc.setParagraphAttributes (0, - 0, - this.styles, - true); - this.doc.setCharacterAttributes (0, - 0, - this.styles, - true); - - this.setDocument (this.doc); - - } - - public void setCanFormat (boolean c) - { - - this.canFormat = c; - - } - - public boolean isCanFormat () - { - - return this.canFormat; - - } - - public void setCanCopy (boolean c) - { - - this.canCopy = c; - - } - - public boolean isCanCopy () - { - - return this.canCopy; - - } - - @Override - public void copy () - { - - if (!this.canCopy) - { - - return; - - } - - super.copy (); - - } - - @Override - public void paste () - { - - if (!this.canCopy) - { - - return; - - } - - Transferable trans = Toolkit.getDefaultToolkit().getSystemClipboard().getContents (null); - - if ((trans != null) - && - (trans.isDataFlavorSupported (DataFlavor.stringFlavor)) - ) - { - - try - { - - String s = (String) trans.getTransferData (DataFlavor.stringFlavor); - - s = com.quollwriter.text.TextUtilities.sanitizeText (s); - - TransferHandler transferHandler = this.getTransferHandler(); - transferHandler.importData (this, - new StringSelection (s)); - - } catch (Exception e) { - - super.paste (); - - } - - } - - } - - protected QTextEditor() - { - - - } - - public void setWritingLineColor (Color c) - { - - this.lineHighlighter.setPaint (c); - this.validate (); - this.repaint (); - - } - - public void setHighlightWritingLine (boolean v) - { - - if (v) - { - - this.lineHighlighter.install (this); - - } else { - - this.lineHighlighter.uninstall (); - - } - - } - - public SynonymProvider getSynonymProvider () - { - - if (this.spellChecker != null) - { - - return this.spellChecker.getSynonymProvider (); - - } - - return null; - - } - - public void setSynonymProvider (SynonymProvider sp) - { - - if (this.spellChecker != null) - { - - this.spellChecker.setSynonymProvider (sp); - - } - - } - - public boolean _print () - throws java.awt.print.PrinterException - { - - QTextEditor qt = new QTextEditor (null, - false); - - qt.setSectionBreak (this.sectionBreak); - - qt.setLineSpacing (this.getLineSpacing ()); - qt.setFontSize (this.getPrintFontSize (this.getFontSize ())); - qt.setFontFamily (this.getFontFamily ()); - qt.setAlignment (this.getAlignment ()); - qt.setFirstLineIndent (this.getFirstLineIndent ()); - qt.setMargin (null); - qt.setTextWithMarkup (this.getTextWithMarkup ()); - - int ppi = java.awt.Toolkit.getDefaultToolkit ().getScreenResolution (); - - // A4 - 17cm wide, 25.7cm high. - // 6.7" wide, 10.12" high - - float pageHeight = 10.12f; - float pageWidth = 8.5f; - - qt.setSize (new Dimension ((int) (pageWidth * ppi), - Integer.MAX_VALUE)); - - qt.setSize (new Dimension ((int) (pageWidth * ppi), - qt.getPreferredSize ().height)); - - return qt.print (); - - } - - public void setDictionaryProvider (DictionaryProvider2 dp) - { - - this.spellChecker.setDictionaryProvider (dp); - - this.checkSpelling (); - - } - - public void applyStyle (Object style, - int start, - int end) - throws Exception - { - - MutableAttributeSet attrs = new SimpleAttributeSet (); - attrs.addAttribute (style, - true); - - this.doc.setCharacterAttributes (start, - end - start, - attrs, - false); - - } - - public String getSelectedText () - { - - int start = this.getSelectionStart (); - - if (start < 0) - { - - return ""; - - } - - int end = this.getSelectionEnd (); - - if (end < 0) - { - - return ""; - - } - - return this.getText ().substring (start, - end); - - } - - public StringWithMarkup getTextWithMarkup () - { - - return new StringWithMarkup (this.getText (), - new Markup (this.getDocument ())); - - } - - public void addStyleChangeListener (StyleChangeListener l) - { - - this.styleChangeListeners.add (l); - - } - - public void removeStyleChangeListener (StyleChangeListener l) - { - - this.styleChangeListeners.remove (l); - - } - - protected void fireStyleChangeEvent (int start, - int end, - String styleType, - boolean on) - { - - StyleChangeEvent ev = new StyleChangeEvent (this, - start, - end, - styleType, - on); - - for (StyleChangeListener l : this.styleChangeListeners) - { - - l.styleChanged (ev); - - } - - } - - private void clearBoldItalicUnderline () - { - - SimpleAttributeSet attrs = new SimpleAttributeSet (); - - StyleConstants.setBold (attrs, - false); - StyleConstants.setItalic (attrs, - false); - StyleConstants.setUnderline (attrs, - false); - - StyledEditorKit k = (StyledEditorKit) this.getEditorKit (); - - MutableAttributeSet inAttrs = k.getInputAttributes (); - - inAttrs.addAttributes (attrs); - - } - - public void setStyle (MutableAttributeSet attrs, - TextRange range) - { - - if (range.start != range.end) - { - - this.doc.setCharacterAttributes (range.start, - range.end - range.start, - attrs, - false); - - } - - StyledEditorKit k = (StyledEditorKit) this.getEditorKit (); - - MutableAttributeSet inAttrs = k.getInputAttributes (); - - inAttrs.addAttributes (attrs); - - } - - public void toggleBold () - { - - if (!this.canFormat) - { - - return; - - } - - int start = this.getSelectionStart (); - - if (start < 0) - { - - start = this.getCaret ().getDot (); - - } - - if (this.getSelectionEnd () == start) - { - - if (start > 0) - { - - start--; - - } - - } - - AbstractDocument.AbstractElement el = (AbstractDocument.AbstractElement) this.doc.getCharacterElement (start); - - SimpleAttributeSet attr = new SimpleAttributeSet (); - - StyleConstants.setBold (attr, - !StyleConstants.isBold (el.getAttributes ())); - - TextRange tr = new TextRange (this); - - this.setStyle (attr, - tr); - - this.fireStyleChangeEvent (tr.start, - tr.end, - StyleChangeEvent.BOLD, - StyleConstants.isBold (attr)); - - } - - public void toggleItalic () - { - - if (!this.canFormat) - { - - return; - - } - - int start = this.getSelectionStart (); - - if (start < 0) - { - - start = this.getCaret ().getDot (); - - } - - if (this.getSelectionEnd () == start) - { - - if (start > 0) - { - - start--; - - } - - } - - AbstractDocument.AbstractElement el = (AbstractDocument.AbstractElement) this.doc.getCharacterElement (start); - - SimpleAttributeSet attr = new SimpleAttributeSet (); - - StyleConstants.setItalic (attr, - !StyleConstants.isItalic (el.getAttributes ())); - - TextRange tr = new TextRange (this); - - this.setStyle (attr, - tr); - - this.fireStyleChangeEvent (tr.start, - tr.end, - StyleChangeEvent.ITALIC, - StyleConstants.isItalic (attr)); - - } - - public void toggleUnderline () - { - - if (!this.canFormat) - { - - return; - - } - - int start = this.getSelectionStart (); - - if (start < 0) - { - - start = this.getCaret ().getDot (); - - } - - if (this.getSelectionEnd () == start) - { - - if (start > 0) - { - - start--; - - } - - } - - AbstractDocument.AbstractElement el = (AbstractDocument.AbstractElement) this.doc.getCharacterElement (start); - - SimpleAttributeSet attr = new SimpleAttributeSet (); - - StyleConstants.setUnderline (attr, - !StyleConstants.isUnderline (el.getAttributes ())); - - TextRange tr = new TextRange (this); - - this.setStyle (attr, - tr); - - this.fireStyleChangeEvent (tr.start, - tr.end, - StyleChangeEvent.UNDERLINE, - StyleConstants.isUnderline (attr)); - - } - - public void replaceText (String replace) - { - - if (this.getText ().length () == 0) - { - - this.setTextWithMarkup (new StringWithMarkup (replace)); - - return; - - } - - int caret = this.getCaret ().getDot (); - - this.startCompoundEdit (); - - this.select (0, - this.getText ().length ()); - - this.replaceSelection (replace); - - this.endCompoundEdit (); - - this.getCaret ().setDot (caret); - - - } - - public void replaceText (int start, - int end, - String replace) - { - - int caret = this.getCaret ().getDot (); - - this.startCompoundEdit (); - - this.select (start, - end); - - this.replaceSelection (replace); - - this.endCompoundEdit (); - - this.getCaret ().setDot (caret); - - } - - public void startCompoundEdit () - { - - this.undoManager.startCompoundEdit (); - - } - - public void endCompoundEdit () - { - - this.undoManager.endCompoundEdit (); - - } - - public CompoundUndoManager getUndoManager () - { - - return this.undoManager; - - } -/* - public TextProperties getTextProperties () - { - - return new TextProperties (this, - this.getFontFamily (), - this.getFontSize (), - this.getAlignmentAsString (), - this.getFirstLineIndent (), - this.getLineSpacing () + 1, - this.getTextColor (), - this.getBackgroundColor ()); - - } - */ - public String getAlignmentAsString () - { - - int v = this.getAlignment (); - - if (v == StyleConstants.ALIGN_LEFT) - { - - return QTextEditor.ALIGN_LEFT; - - } - - if (v == StyleConstants.ALIGN_RIGHT) - { - - return QTextEditor.ALIGN_RIGHT; - - } - - if (v == StyleConstants.ALIGN_JUSTIFIED) - { - - return QTextEditor.ALIGN_JUSTIFIED; - - } - - return QTextEditor.ALIGN_LEFT; - - } - - public int getAlignment () - { - - return StyleConstants.getAlignment (this.styles); - - } - - public void setAlignment (int v) - { - - StyleConstants.setAlignment (this.styles, - v); - - this.applyStyles (); - - } - - public boolean getFirstLineIndent () - { - - return StyleConstants.getFirstLineIndent (this.styles) != 0; - - } - - public void setFirstLineIndent (boolean v) - { - - float f = 0f; - - if (v) - { - - f = 30f; - - } - - StyleConstants.setFirstLineIndent (this.styles, - f); - - this.applyStyles (); - - } - - public void setAlignment (String v) - { - - int a = StyleConstants.ALIGN_LEFT; - - if (v.equalsIgnoreCase (QTextEditor.ALIGN_LEFT)) - { - - a = StyleConstants.ALIGN_LEFT; - - } - - if (v.equalsIgnoreCase (QTextEditor.ALIGN_RIGHT)) - { - - a = StyleConstants.ALIGN_RIGHT; - - } - - if (v.equalsIgnoreCase (QTextEditor.ALIGN_JUSTIFIED)) - { - - a = StyleConstants.ALIGN_JUSTIFIED; - - } - - this.setAlignment (a); - - } - - public Color getTextColor () - { - - return this.getFontColor (); - - } - - public Color getFontColor () - { - - return StyleConstants.getForeground (this.styles); - - } - - public void setTextColor (Color c) - { - - this.setFontColor (c); - - } - - public void setFontColor (Color c) - { - - // Change the caret color to match. - this.setCaretColor (c); - - StyleConstants.setForeground (this.styles, - c); - - this.applyStyles (); - - } - - /** - * Note: is here for compatibility, but will do nothing, parent components need to - * implement TextStyleable.setTextBorder with their own behaviour. - */ - @Override - public void setTextBorder (int v) - { - - // Do nothing. - - } - - public int getFontSize () - { - - return StyleConstants.getFontSize (this.styles); - - } - - public Font getFontForStyles () - { - - return new Font (this.getFontFamily (), - Font.PLAIN, - this.getFontSize ()); - - } - - public void setFontSize (int v) - { - - StyleConstants.setFontSize (this.styles, - v); - - this.applyStyles (); - - this.fireStyleChangeEvent (0, - this.doc.getEndPosition ().getOffset (), - StyleChangeEvent.FONT_SIZE, - false); - - } - - public String getFontFamily () - { - - return StyleConstants.getFontFamily (this.styles); - - } - - public void setFontFamily (String name) - { - - if (name == null) - { - - throw new IllegalArgumentException ("Font family name cannot be null"); - - } - - StyleConstants.setFontFamily (this.styles, - name); - - this.applyStyles (); - - this.fireStyleChangeEvent (0, - this.doc.getEndPosition ().getOffset (), - StyleChangeEvent.FONT_NAME, - false); - - } - - private void applyStyles () - { - - this.doc.setParagraphAttributes (0, - this.doc.getEndPosition ().getOffset (), - this.styles, - true); - - this.initSectionBreaks (this.getText ()); - - } - - public int getLineHeight () - { - - java.awt.image.BufferedImage bi = new java.awt.image.BufferedImage (1, 1, java.awt.image.BufferedImage.TYPE_INT_ARGB); - Graphics g = bi.getGraphics (); - - return (int) (g.getFontMetrics (new Font (this.getFontFamily (), Font.PLAIN, this.getFontSize ())).getHeight () * this.getLineSpacing ()); - - } - - public float getLineSpacing () - { - - return StyleConstants.getLineSpacing (this.styles) + 1; - - } - - public void setLineSpacing (float v) - { - - StyleConstants.setLineSpacing (this.styles, - v - 1); - - this.applyStyles (); - - } - - public void addWordToDictionary (String word) - { - - if (this.spellChecker != null) - { - - this.spellChecker.addWord (word); - - } - - } - - public void setSpellCheckEnabled (boolean v) - { - - if (this.spellChecker != null) - { - - this.spellChecker.enable (v); - - } - - } - - public boolean isSpellCheckEnabled () - { - - if (this.spellChecker != null) - { - - return this.spellChecker.isEnabled (); - - } - - return false; - - } - - public List getSpellCheckSuggestions (Word word) - { - - if (this.spellChecker == null) - { - - return new ArrayList (); - - } - - return this.spellChecker.getSuggestions (word); - - } - - public boolean isLoadingText () - { - - return this.loading; - - } - - public void setSectionBreak (String b) - { - - this.sectionBreak = b; - - } - - private void initSectionBreaks (String t) - { - - if (t == null) - { - - return; - - } - - if (this.sectionBreak != null) - { - - int ind = t.indexOf (this.sectionBreak); - - while (ind != -1) - { - - this.doc.setParagraphAttributes (ind, - 1, - this.sectionBreakStyle, - false); - - Style ls = this.doc.addStyle (null, - null); - StyleConstants.setAlignment (ls, - StyleConstants.ALIGN_LEFT); - - this.doc.setCharacterAttributes (ind + this.sectionBreak.length (), - 1, - ls, - false); - - ind = t.indexOf (this.sectionBreak, - ind + this.sectionBreak.length () + 1); - - } - - } - - } - - public void setText (String t) - { - - throw new UnsupportedOperationException ("Not supported, use setTextWithMarkup"); - - } - - public void removeHighlight (Object o) - { - - this.getHighlighter ().removeHighlight (o); - - } - - public Object addHighlight (int start, - int end, - Highlighter.HighlightPainter painter, - boolean removeHighlightOnActivity) - { - - final Highlighter h = this.getHighlighter (); - - try - { - - final Object o = h.addHighlight (start, - end, - ((painter != null) ? painter : javax.swing.text.DefaultHighlighter.DefaultPainter)); - - if (removeHighlightOnActivity) - { - - final QTextEditor _this = this; - - this.addKeyListener (new KeyAdapter () - { - - public void keyPressed (KeyEvent ev) - { - - _this.removeHighlight (o); - - _this.removeKeyListener (this); - - } - - }); - - this.addMouseListener (new MouseAdapter () - { - - public void mousePressed (MouseEvent ev) - { - - _this.removeHighlight (o); - - _this.removeMouseListener (this); - - } - - }); - - - } - - return o; - - } catch (Exception e) - { - - return null; - - } - - } - - public void removeAllHighlights (Highlighter.HighlightPainter painter) - { - - Highlighter h = this.getHighlighter (); - - Highlighter.Highlight[] highlights = h.getHighlights (); - - if (painter == null) - { - - painter = javax.swing.text.DefaultHighlighter.DefaultPainter; - - } - - for (int k = highlights.length; --k >= 0;) - { - - Highlighter.Highlight hh = highlights[k]; - - if (hh.getPainter () == painter) - { - - h.removeHighlight (hh); - - } - - } - - } - - public void removeHighlightsForElement (Element el, - Highlighter.HighlightPainter painter) - { - - int i = el.getStartOffset (); - int j = el.getEndOffset (); - - if (i == j) - { - - return; - - } - - if (painter == null) - { - - painter = javax.swing.text.DefaultHighlighter.DefaultPainter; - - } - - Highlighter h = this.getHighlighter (); - - Highlighter.Highlight[] highlights = h.getHighlights (); - - for (int k = highlights.length; --k >= 0;) - { - - Highlighter.Highlight hh = highlights[k]; - - int s = hh.getStartOffset (); - - int e = hh.getEndOffset (); - - if (((i <= s) && (s <= j)) || - ((i <= e) && (e <= j))) - { - - if (hh.getPainter () == painter) - { - - h.removeHighlight (hh); - - } - - } - - } - - } - - public void setTextWithMarkup (StringWithMarkup text) - { - - boolean enabled = false; - - this.undoManager.setRecordUndos (false); - - if (this.spellChecker != null) - { - - enabled = this.spellChecker.isEnabled (); - - this.spellChecker.enable (false); - - } - - String t = null; - Markup markup = null; - - if (text != null) - { - - t = text.getText (); - markup = text.getMarkup (); - - } - - if (t != null) - { - - t = StringUtils.replaceString (t, - String.valueOf ('\r'), - ""); - - } - - //this.styles = new SimpleAttributeSet (); - - this.clearBoldItalicUnderline (); - - super.setText (t); - - //this.applyStyles (); - - this.initSectionBreaks (t); - - if (markup != null) - { - - //Markup m = new Markup (markup); - - markup.apply (this); - - } - - this.undoManager.setRecordUndos (true); - - if (this.spellChecker != null) - { - - this.spellChecker.enable (enabled); - - } - - } - - public void checkSpelling () - { - - if (this.spellChecker != null) - { - - if (this.spellChecker.isEnabled ()) - { - - this.spellChecker.checkAll (); - - } - - } - - } - - public void appendText (String t) - throws BadLocationException - { - - this.doc.insertString (this.doc.getEndPosition ().getOffset () - 1, - t, - null); - - } - - public void insertText (int where, - String t) - throws BadLocationException - { - - this.doc.insertString (where, - t, - null); - - } - - public void removeText (int where, - int length) - throws BadLocationException - { - - this.doc.remove (where, - length); - - this.removeAllHighlights (null); - - } - - public void setBackgroundColor (Color c) - { - - this.setBackground (c); - - } - - public Color getBackgroundColor () - { - - return this.getBackground (); - - } - - public static int getPrintFontSize (int size) - { - - return Math.round ((float) size / ((float) java.awt.Toolkit.getDefaultToolkit ().getScreenResolution () / 72f)); - - } - - public boolean isPositionAtTextEnd (int p) - { - - int cl = this.getText ().length (); - - if (cl == 0) - { - - return p == cl; - - } - - return p >= cl; - - } - -} diff --git a/src/com/quollwriter/ui/panels/AbstractEditableEditorPanel.java b/src/com/quollwriter/ui/panels/AbstractEditableEditorPanel.java deleted file mode 100644 index ff4afd46..00000000 --- a/src/com/quollwriter/ui/panels/AbstractEditableEditorPanel.java +++ /dev/null @@ -1,1066 +0,0 @@ -package com.quollwriter.ui.panels; - -import java.awt.*; -import java.awt.event.*; -import java.awt.font.*; - -import java.io.*; - -import java.text.*; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Random; -import java.util.Timer; -import java.util.Set; - -import javax.swing.*; -import javax.swing.border.*; -import javax.swing.event.*; -import javax.swing.text.*; -import javax.swing.undo.*; - -import com.gentlyweb.properties.*; - -import com.jgoodies.forms.builder.*; -import com.jgoodies.forms.factories.*; -import com.jgoodies.forms.layout.*; - -import com.quollwriter.*; - -import com.quollwriter.data.*; - -import com.quollwriter.text.*; -import com.quollwriter.synonyms.*; -import com.quollwriter.ui.sidebars.*; -import com.quollwriter.ui.*; -import com.quollwriter.ui.actionHandlers.*; -import com.quollwriter.ui.components.ActionAdapter; -import com.quollwriter.ui.components.DocumentAdapter; -import com.quollwriter.ui.components.StyleChangeAdapter; -import com.quollwriter.ui.components.StyleChangeEvent; -import com.quollwriter.ui.components.StyleChangeListener; -import com.quollwriter.ui.components.QTextEditor; -import com.quollwriter.ui.components.Runner; -import com.quollwriter.ui.components.TextStylable; -import com.quollwriter.ui.components.TextProperties; - -public abstract class AbstractEditableEditorPanel extends AbstractEditorPanel -{ - - public static final String SAVE_ACTION_NAME = "save"; - public static final String INSERT_SECTION_BREAK_ACTION_NAME = "insert-section-break"; - public static final String DELETE_CHAPTER_ACTION_NAME = "delete-chapter"; - - public AbstractEditableEditorPanel (AbstractProjectViewer pv, - Chapter c) - throws GeneralException - { - - super (pv, - c); - - final AbstractEditableEditorPanel _this = this; - - this.editor.setSectionBreak (Constants.SECTION_BREAK); - - this.actions.put (DELETE_CHAPTER_ACTION_NAME, - new DeleteChapterActionHandler ((Chapter) this.obj, - this.viewer)); - - this.actions.put (SAVE_ACTION_NAME, - new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - try - { - - _this.saveChapter (); - - } catch (Exception e) - { - - Environment.logError ("Unable to save chapter", - e); - - } - - } - - }); - - this.actions.put (INSERT_SECTION_BREAK_ACTION_NAME, - new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - try - { - - _this.insertSectionBreak (); - - } catch (Exception e) - { - - // Ignore. - - } - - } - - }); - - InputMap im = this.editor.getInputMap (JComponent.WHEN_IN_FOCUSED_WINDOW); - - im.put (KeyStroke.getKeyStroke (KeyEvent.VK_S, - Event.CTRL_MASK), - SAVE_ACTION_NAME); - - im = this.editor.getInputMap (JComponent.WHEN_FOCUSED); - - im.put (KeyStroke.getKeyStroke (KeyEvent.VK_ENTER, - Event.CTRL_MASK), - INSERT_SECTION_BREAK_ACTION_NAME); - - } - - public abstract void doFillPopupMenu (MouseEvent eve, - JPopupMenu p, - boolean compress); - - @Override - public void close () - { - - super.close (); - - } - - @Override - public void init () - throws GeneralException - { - - super.init (); - - final AbstractEditableEditorPanel _this = this; - /* TODO: Remove merged. -<<<<<<< HEAD -======= - - this.chapterInfo = new javax.swing.Timer (2000, - new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - new Thread (new Runnable () - { - - public void run () - { - - try - { - - Thread t = Thread.currentThread (); - t.setName ("Chapter counts for: " + _this.chapter.getName ()); - t.setPriority (Thread.MIN_PRIORITY); - - } catch (Exception e) { - - // Ignore. - - } - - try - { - - ChapterCounts cc = new ChapterCounts (_this.editor.getText ()); - cc.a4PageCount = UIUtils.getA4PageCountForChapter (_this.chapter, - _this.editor.getText ()); - - _this.setChapterCounts (cc); - - _this.setReadabilityIndices (_this.projectViewer.getReadabilityIndices (_this.editor.getText ())); - - _this.chapterInfoTimerLastRun = System.currentTimeMillis (); - - } catch (Exception e) { - - Environment.logError ("Unable to get chapter counts/readability for chapter: " + - _this.chapter, - e); - - } - - } - - }).start (); - - } - - }); - - this.chapterInfo.setRepeats (false); - this.chapterInfo.start (); ->>>>>>> refs/remotes/origin/master - */ - final DefaultStyledDocument doc = (DefaultStyledDocument) this.editor.getDocument (); - - doc.addDocumentListener (new DocumentAdapter () - { - - public void insertUpdate (DocumentEvent ev) - { - - final int offset = ev.getOffset (); - - if (ev.getLength () > 0) - { - - _this.viewer.fireProjectEvent (Chapter.OBJECT_TYPE, - ProjectEvent.EDIT, - _this.obj); - - } - - boolean add = false; - - try - { - - if (ev.getLength () == 1) - { - - if (offset == 0) - { - - Set its = _this.obj.getOutlineItemsAt (0); - - for (OutlineItem it : its) - { - - it.setTextPosition (editor.getDocument ().createPosition (it.getPosition () + 1)); - - } - - Set ss = _this.obj.getScenesAt (0); - - for (Scene s : ss) - { - - s.setTextPosition (editor.getDocument ().createPosition (s.getPosition () + 1)); - - } - - Set nn = _this.obj.getNotesAt (0); - - for (Note n : nn) - { - - n.setTextPosition (editor.getDocument ().createPosition (n.getPosition () + 1)); - - } - - } - - String t = doc.getText (offset, - ev.getLength ()); - - String nl = String.valueOf ('\n'); - - if (t.equals (nl)) - { - - String te = doc.getText (offset - Constants.SECTION_BREAK_FIND.length (), - Constants.SECTION_BREAK_FIND.length ()); - - if (te.equals (Constants.SECTION_BREAK_FIND)) - { - - add = true; - - } - - if (doc.getLogicalStyle (offset) == _this.editor.sectionBreakStyle) - { - - UIUtils.doLater (new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - Style ls = doc.addStyle (null, - null); - StyleConstants.setAlignment (ls, - StyleConstants.ALIGN_LEFT); - - doc.setParagraphAttributes (offset + 1, - 1, - ls, - false); - - } - - }); - - } - - } - - } - - } catch (Exception e) - { - - // Ignore. - - } - - if (add) - { - - UIUtils.doLater (new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - try - { - - String ins = String.valueOf ('\n') + String.valueOf ('\n') + Constants.SECTION_BREAK + String.valueOf ('\n') + String.valueOf ('\n'); - - doc.replace (offset - Constants.SECTION_BREAK_FIND.length (), - Constants.SECTION_BREAK_FIND.length () + 1, - ins, - _this.editor.sectionBreakStyle); - - doc.setParagraphAttributes (offset + 2, - Constants.SECTION_BREAK.length (), - _this.editor.sectionBreakStyle, - false); - - doc.setLogicalStyle (offset + 2, - _this.editor.sectionBreakStyle); - - Style ls = doc.addStyle (null, - null); - StyleConstants.setAlignment (ls, - StyleConstants.ALIGN_LEFT); - - doc.setParagraphAttributes (offset + Constants.SECTION_BREAK.length (), - 2, - ls, - false); - - } catch (Exception e) - { - - Environment.logError ("Unable to add section breaks", - e); - - } - - } - - }); - - } - - } - - public void removeUpdate (DocumentEvent ev) - { - - if (ev.getLength () > 0) - { - - _this.viewer.fireProjectEvent (Chapter.OBJECT_TYPE, - ProjectEvent.EDIT, - _this.obj); - - } - - final int offset = ev.getOffset (); - - if (doc.getLogicalStyle (offset) == _this.editor.sectionBreakStyle) - { - - UIUtils.doLater (new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - try - { - - doc.replace (offset - Constants.SECTION_BREAK_FIND.length (), - Constants.SECTION_BREAK_FIND.length (), - null, - null); - - } catch (Exception e) - { - - } - - } - - }); - - } - - } - - }); - - this.editor.getDocument ().addDocumentListener (new DocumentAdapter () - { - - public void changedUpdate (DocumentEvent ev) - { - - if (_this.isIgnoreDocumentChanges ()) - { - - return; - - } - - _this.setHasUnsavedChanges (true); - - } - - public void insertUpdate (DocumentEvent ev) - { - - if (_this.isIgnoreDocumentChanges ()) - { - - return; - - } - - _this.setHasUnsavedChanges (true); - - } - - public void removeUpdate (DocumentEvent ev) - { - - if (_this.isIgnoreDocumentChanges ()) - { - - return; - - } - - _this.setHasUnsavedChanges (true); - - } - - }); - - } - - public void insertSectionBreak () - { - - final AbstractEditorPanel _this = this; - - final DefaultStyledDocument doc = (DefaultStyledDocument) this.editor.getDocument (); - - final int offset = this.editor.getCaret ().getDot (); - - UIUtils.doLater (new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - try - { - - _this.editor.startCompoundEdit (); - - String ins = String.valueOf ('\n') + String.valueOf ('\n') + Constants.SECTION_BREAK + String.valueOf ('\n') + String.valueOf ('\n'); - - doc.insertString (offset, - ins, - _this.editor.sectionBreakStyle); - - doc.setParagraphAttributes (offset + 2, - Constants.SECTION_BREAK.length (), - _this.editor.sectionBreakStyle, - false); - - doc.setLogicalStyle (offset + 2, - _this.editor.sectionBreakStyle); - - _this.editor.endCompoundEdit (); - - } catch (Exception e) - { - - } - - } - - }); - - } - - @Override - public boolean saveUnsavedChanges () - throws Exception - { - - this.saveObject (); - - return true; - - } - - public void saveChapter () - throws Exception - { - - this.saveObject (); - - } - - public void saveObject () - throws Exception - { - - this.obj.setText (this.editor.getTextWithMarkup ()); - - super.saveObject (); - - } - - // TODO: Merge with TextArea.fillPopupMenu - private void addFormatItemsToPopupMenu (JPopupMenu popup, - boolean compress) - { - - String sel = this.editor.getSelectedText (); - - if (!sel.equals ("")) - { - - java.util.List prefix = new ArrayList (); - prefix.add (LanguageStrings.formatting); - prefix.add (LanguageStrings.format); - prefix.add (LanguageStrings.popupmenu); - prefix.add (LanguageStrings.items); - - if (compress) - { - - List buts = new ArrayList (); - buts.add (this.createButton (Constants.BOLD_ICON_NAME, - Constants.ICON_MENU, - Environment.getUIString (prefix, - LanguageStrings.bold, - LanguageStrings.tooltip), - //"Bold the selected text", - QTextEditor.BOLD_ACTION_NAME)); - buts.add (this.createButton (Constants.ITALIC_ICON_NAME, - Constants.ICON_MENU, - Environment.getUIString (prefix, - LanguageStrings.italic, - LanguageStrings.tooltip), - //"Italic the selected text", - QTextEditor.ITALIC_ACTION_NAME)); - buts.add (this.createButton (Constants.UNDERLINE_ICON_NAME, - Constants.ICON_MENU, - Environment.getUIString (prefix, - LanguageStrings.underline, LanguageStrings.tooltip), - //"Underline the selected text", - QTextEditor.UNDERLINE_ACTION_NAME)); - - popup.add (UIUtils.createPopupMenuButtonBar (Environment.getUIString (LanguageStrings.formatting, - LanguageStrings.format, - LanguageStrings.popupmenu, - LanguageStrings.title), - //"Format", - popup, - buts)); - - } else { - - JMenuItem mi = null; - - popup.addSeparator (); - - // Add the bold/italic/underline. - mi = this.createMenuItem (Environment.getUIString (prefix, - LanguageStrings.bold, - LanguageStrings.text), - //"Bold", - Constants.BOLD_ICON_NAME, - QTextEditor.BOLD_ACTION_NAME, - KeyStroke.getKeyStroke (KeyEvent.VK_B, - ActionEvent.CTRL_MASK)); - mi.setMnemonic (KeyEvent.VK_B); - mi.setFont (mi.getFont ().deriveFont (Font.BOLD)); - popup.add (mi); - - mi = this.createMenuItem (Environment.getUIString (prefix, - LanguageStrings.italic, - LanguageStrings.text), - //"Italic", - Constants.ITALIC_ICON_NAME, - QTextEditor.ITALIC_ACTION_NAME, - KeyStroke.getKeyStroke (KeyEvent.VK_I, - ActionEvent.CTRL_MASK)); - mi.setMnemonic (KeyEvent.VK_I); - mi.setFont (mi.getFont ().deriveFont (Font.ITALIC)); - popup.add (mi); - - mi = this.createMenuItem (Environment.getUIString (prefix, - LanguageStrings.underline, - LanguageStrings.text), - //"Underline", - Constants.UNDERLINE_ICON_NAME, - QTextEditor.UNDERLINE_ACTION_NAME, - KeyStroke.getKeyStroke (KeyEvent.VK_U, - ActionEvent.CTRL_MASK)); - mi.setMnemonic (KeyEvent.VK_U); - popup.add (mi); - - Map attrs = mi.getFont ().getAttributes (); - attrs.put (TextAttribute.UNDERLINE, - TextAttribute.UNDERLINE_LOW_ONE_PIXEL); - - mi.setFont (mi.getFont ().deriveFont (attrs)); - - } - - } - - } - - // TODO: Merge with TextArea.fillPopupMenu. - private void addEditItemsToPopupMenu (JPopupMenu popup, - boolean compress) - { - - JMenuItem mi = null; - - java.util.List prefix = new ArrayList (); - prefix.add (LanguageStrings.formatting); - prefix.add (LanguageStrings.edit); - prefix.add (LanguageStrings.popupmenu); - prefix.add (LanguageStrings.items); - - String sel = this.editor.getSelectedText (); - - if (compress) - { - - List buts = new ArrayList (); - - // Only add if there is something to cut. - if (!sel.equals ("")) - { - - buts.add (this.createButton (Constants.CUT_ICON_NAME, - Constants.ICON_MENU, - Environment.getUIString (prefix, - LanguageStrings.cut, - LanguageStrings.tooltip), - //"Cut the selected text", - QTextEditor.CUT_ACTION_NAME)); - buts.add (this.createButton (Constants.COPY_ICON_NAME, - Constants.ICON_MENU, - Environment.getUIString (prefix, - LanguageStrings.copy, - LanguageStrings.tooltip), - //"Copy the selected text", - QTextEditor.COPY_ACTION_NAME)); - - } - - if (UIUtils.clipboardHasContent ()) - { - - buts.add (this.createButton (Constants.PASTE_ICON_NAME, - Constants.ICON_MENU, - Environment.getUIString (prefix, - LanguageStrings.paste, - LanguageStrings.tooltip), - //"Paste", - QTextEditor.PASTE_ACTION_NAME)); - - } - - // Only add if there is an undo available. - buts.add (this.createButton (Constants.UNDO_ICON_NAME, - Constants.ICON_MENU, - Environment.getUIString (prefix, - LanguageStrings.undo, - LanguageStrings.tooltip), - //"Undo", - QTextEditor.UNDO_ACTION_NAME)); - buts.add (this.createButton (Constants.REDO_ICON_NAME, - Constants.ICON_MENU, - Environment.getUIString (prefix, - LanguageStrings.redo, - LanguageStrings.tooltip), - //"Redo", - QTextEditor.REDO_ACTION_NAME)); - - popup.add (UIUtils.createPopupMenuButtonBar (Environment.getUIString (LanguageStrings.formatting, - LanguageStrings.edit, - LanguageStrings.popupmenu, - LanguageStrings.title), - //"Edit", - popup, - buts)); - - } else { - - popup.addSeparator (); -/* - mi = this.createMenuItem ("Find", - Constants.FIND_ICON_NAME, - Constants.SHOW_FIND_ACTION, - KeyStroke.getKeyStroke (KeyEvent.VK_F, - ActionEvent.CTRL_MASK)); - mi.setMnemonic (KeyEvent.VK_F); - popup.add (mi); -*/ - if (!sel.equals ("")) - { - - mi = this.createMenuItem (Environment.getUIString (prefix, - LanguageStrings.cut, - LanguageStrings.text), - //"Cut", - Constants.CUT_ICON_NAME, - QTextEditor.CUT_ACTION_NAME, - KeyStroke.getKeyStroke (KeyEvent.VK_X, - ActionEvent.CTRL_MASK)); - mi.setMnemonic (KeyEvent.VK_X); - popup.add (mi); - - mi = this.createMenuItem (Environment.getUIString (prefix, - LanguageStrings.copy, - LanguageStrings.text), - //"Copy", - Constants.COPY_ICON_NAME, - QTextEditor.COPY_ACTION_NAME, - KeyStroke.getKeyStroke (KeyEvent.VK_C, - ActionEvent.CTRL_MASK)); - mi.setMnemonic (KeyEvent.VK_C); - popup.add (mi); - - } - - // Only show if there is something in the clipboard. - if (UIUtils.clipboardHasContent ()) - { - - mi = this.createMenuItem (Environment.getUIString (prefix, - LanguageStrings.paste, - LanguageStrings.text), - //"Paste", - Constants.PASTE_ICON_NAME, - QTextEditor.PASTE_ACTION_NAME, - KeyStroke.getKeyStroke (KeyEvent.VK_V, - ActionEvent.CTRL_MASK)); - mi.setMnemonic (KeyEvent.VK_V); - - popup.add (mi); - - } - - mi = this.createMenuItem (Environment.getUIString (prefix, - LanguageStrings.undo, - LanguageStrings.text), - //"Undo", - Constants.UNDO_ICON_NAME, - QTextEditor.UNDO_ACTION_NAME, - KeyStroke.getKeyStroke (KeyEvent.VK_Z, - ActionEvent.CTRL_MASK)); - mi.setMnemonic (KeyEvent.VK_Z); - popup.add (mi); - - mi = this.createMenuItem (Environment.getUIString (prefix, - LanguageStrings.redo, - LanguageStrings.text), - //"Redo", - Constants.REDO_ICON_NAME, - QTextEditor.REDO_ACTION_NAME, - KeyStroke.getKeyStroke (KeyEvent.VK_Y, - ActionEvent.CTRL_MASK)); - mi.setMnemonic (KeyEvent.VK_Y); - popup.add (mi); - - } - - } - - public void fillPopupMenu (final MouseEvent ev, - final JPopupMenu popup) - { - - final QTextEditor editor = this.editor; - final AbstractEditableEditorPanel _this = this; - - Point p = this.editor.getMousePosition (); - - this.lastMousePosition = p; - - JMenuItem mi = null; - - if (p != null) - { - - ActionAdapter addToDict = new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - editor.addWordToDictionary (ev.getActionCommand ()); - - _this.viewer.fireProjectEvent (ProjectEvent.PERSONAL_DICTIONARY, - ProjectEvent.ADD_WORD, - ev.getActionCommand ()); - - } - - }; - - TextIterator iter = new TextIterator (this.editor.getText ()); - - final Word w = iter.getWordAt (this.editor.viewToModel (p)); - - if (w != null) - { - - final String word = w.getText (); - - final int loc = w.getAllTextStartOffset (); - - java.util.List l = this.editor.getSpellCheckSuggestions (w); - - if (l != null) - { - - java.util.List prefix = new ArrayList (); - prefix.add (LanguageStrings.dictionary); - prefix.add (LanguageStrings.spellcheck); - prefix.add (LanguageStrings.popupmenu); - prefix.add (LanguageStrings.items); - - if (l.size () == 0) - { - - mi = new JMenuItem (Environment.getUIString (prefix, - LanguageStrings.add)); - //"Add to Dictionary"); - mi.setFont (mi.getFont ().deriveFont (Font.BOLD)); - mi.setActionCommand (word); - mi.addActionListener (addToDict); - - popup.add (mi, - 0); - - mi = new JMenuItem (Environment.getUIString (prefix, - LanguageStrings.nosuggestions)); - //"(No Spelling Suggestions)"); - mi.setFont (mi.getFont ().deriveFont (Font.BOLD)); - mi.setEnabled (false); - - popup.add (mi, - 0); - - } else - { - - JMenu more = new JMenu (Environment.getUIString (prefix, - LanguageStrings.more)); - //"More Suggestions"); - - int i = 0; - - for (i = 0; i < l.size (); i++) - { - - if (i == 5) - { - - popup.add (more, - 5); - - } - - final String suggestion = (String) l.get (i); - //final String suggestion = ((com.swabunga.spell.engine.Word) l.get (i)).getWord (); - - mi = new JMenuItem (suggestion); - mi.setFont (mi.getFont ().deriveFont (Font.BOLD)); - mi.setActionCommand (mi.getText ()); - mi.addActionListener (new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - String repWord = ev.getActionCommand (); - - _this.editor.replaceText (loc, - loc + word.length (), - repWord); - - _this.viewer.fireProjectEvent (ProjectEvent.SPELL_CHECK, - ProjectEvent.REPLACE, - ev.getActionCommand ()); - - } - - }); - - if (i < 5) - { - - popup.add (mi); - //0); - - } else - { - - more.add (mi); - - } - - } - - if (i > 5) - { - - i = 6; - - } - - mi = new JMenuItem (Environment.getUIString (prefix, - LanguageStrings.add)); - //"Add to Dictionary"); - mi.setActionCommand (word); - mi.addActionListener (addToDict); - - popup.add (mi, - i); - - } - - popup.addSeparator (); - - } else - { - - if ((this.viewer.synonymLookupsSupported ()) && - (ev.getSource () == this.editor)) - { - - if (Environment.isEnglish (_this.viewer.getSpellCheckLanguage ())) - { - - if ((word != null) && - (word.length () > 0)) - { - - //String mt = "No synonyms found for: " + word; - - try - { - - // See if there are any synonyms. - if (this.editor.getSynonymProvider ().hasSynonym (word)) - { - - mi = new JMenuItem (String.format (Environment.getUIString (LanguageStrings.synonyms, - LanguageStrings.popupmenu, - LanguageStrings.items, - LanguageStrings.find), - word)); - //mi = new JMenuItem ("Find synonyms for: " + word); - - mi.setIcon (Environment.getIcon ("find", - Constants.ICON_MENU)); - - mi.addActionListener (new FindSynonymsActionHandler (w, _this.editor)); - /* - word, - loc, // c - this.getChapter (), - _this)); -*/ - } else { - - mi = new JMenuItem (String.format (Environment.getUIString (LanguageStrings.synonyms, - LanguageStrings.popupmenu, - LanguageStrings.items, - LanguageStrings.nosynonyms), - word)); - //mi = new JMenuItem ("(No synonyms for: " + word + ")"); - mi.setFont (mi.getFont ().deriveFont (Font.BOLD)); - mi.setEnabled (false); - - } - - popup.add (mi); - - popup.addSeparator (); - - } catch (Exception e) { - - Environment.logError ("Unable to determine whether word: " + - word + - " has synonyms.", - e); - - } - - } - - } - - } - - } - - } - - } - - boolean compress = UserProperties.getAsBoolean (Constants.COMPRESS_CHAPTER_CONTEXT_MENU_PROPERTY_NAME); - - this.doFillPopupMenu (ev, - popup, - compress); - - this.addFormatItemsToPopupMenu (popup, - compress); - - this.addEditItemsToPopupMenu (popup, - compress); - - } - -} diff --git a/src/com/quollwriter/ui/panels/AbstractEditorPanel.java b/src/com/quollwriter/ui/panels/AbstractEditorPanel.java deleted file mode 100644 index 77e22232..00000000 --- a/src/com/quollwriter/ui/panels/AbstractEditorPanel.java +++ /dev/null @@ -1,1488 +0,0 @@ -package com.quollwriter.ui.panels; - -import java.awt.*; -import java.awt.event.*; -import java.awt.font.*; - -import java.io.*; - -import java.text.*; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Random; -import java.util.Timer; -import java.util.Set; -import java.util.TimerTask; - -import javax.swing.*; -import javax.swing.border.*; -import javax.swing.event.*; -import javax.swing.text.*; -import javax.swing.undo.*; - -import com.gentlyweb.properties.*; - -import com.jgoodies.forms.builder.*; -import com.jgoodies.forms.factories.*; -import com.jgoodies.forms.layout.*; - -import com.quollwriter.*; - -import com.quollwriter.data.*; -import com.quollwriter.events.*; -import com.quollwriter.text.*; -import com.quollwriter.synonyms.*; -import com.quollwriter.ui.sidebars.*; -import com.quollwriter.ui.*; -import com.quollwriter.ui.actionHandlers.*; -import com.quollwriter.ui.components.ActionAdapter; -import com.quollwriter.ui.components.DocumentAdapter; -import com.quollwriter.ui.components.StyleChangeAdapter; -import com.quollwriter.ui.components.StyleChangeEvent; -import com.quollwriter.ui.components.StyleChangeListener; -import com.quollwriter.ui.components.QTextEditor; -import com.quollwriter.ui.components.Runner; -import com.quollwriter.ui.components.TextStylable; -import com.quollwriter.ui.components.TextProperties; - -import static com.quollwriter.LanguageStrings.*; -import static com.quollwriter.Environment.getUIString; - -public abstract class AbstractEditorPanel extends ProjectObjectQuollPanel implements SpellCheckSupported, TextStylable, UserPropertyListener -{ - - public static final String TOGGLE_SPELLCHECK_ACTION_NAME = "toggle-spellcheck"; - public static final String TOGGLE_WORDCOUNTS_ACTION_NAME = "toggle-wordcounts"; - public static final String EDIT_TEXT_PROPERTIES_ACTION_NAME = "edit-text-properties"; - - protected QTextEditor editor = null; - private Border origEditorBorder = null; - protected ActionMap actions = null; - protected Point lastMousePosition = null; - protected JScrollPane scrollPane = null; - private boolean ignoreDocumentChange = false; - private boolean useTypewriterScrolling = false; - private ReadabilityIndices readability = null; - private ActionListener performAction = null; - private int scrollOffset = 0; - private Insets origEditorMargin = null; - private int softCaret = -1; - private Runnable wordCountUpdate = null; - private long lastWordCountUpdateTime = 0; - private boolean isScrolling = false; - - public AbstractEditorPanel(final AbstractProjectViewer pv, - final Chapter c) - throws GeneralException - { - - super (pv, - c); - - //this.chapter = c; - - final AbstractEditorPanel _this = this; - - DictionaryProvider2 dp = null; - - try - { - - dp = pv.getDictionaryProvider (); - - } catch (Exception e) - { - - throw new GeneralException ("Unable to get dictionary provider.", - e); - - } - - SynonymProvider sp = null; - - try - { - - sp = pv.getSynonymProvider (); - - } catch (Exception e) - { - - throw new GeneralException ("Unable to get synonym provider.", - e); - - } - - this.editor = new QTextEditor (dp, - pv.isSpellCheckingEnabled ()); - - this.origEditorBorder = this.editor.getBorder (); - - this.editor.setSynonymProvider (sp);//Environment.getSynonymProvider ()); - - this.editor.getDocument ().addDocumentListener (new DocumentListener () - { - - @Override - public void insertUpdate (DocumentEvent ev) - { - - _this.scheduleWordCountUpdate (); - - } - - @Override - public void changedUpdate (DocumentEvent ev) - { - - _this.scheduleWordCountUpdate (); - - } - - @Override - public void removeUpdate (DocumentEvent ev) - { - - _this.scheduleWordCountUpdate (); - - } - - - }); - - - // This ensures that the viewport is always in sync with the text area size. - this.editor.addKeyListener (new KeyAdapter () - { - - @Override - public void keyPressed (KeyEvent ev) - { - - // Get the caret. - if (_this.editor.getCaretPosition () >= _this.editor.getText ().length ()) - { - - Dimension d = _this.editor.getSize (); - - _this.getScrollPane ().getViewport ().setViewSize (new Dimension (d.width, - d.height + 200)); - - } - - } - - @Override - public void keyTyped (KeyEvent ev) - { - - if ((ev.getModifiers () & KeyEvent.CTRL_MASK) != 0) - { - - return; - - } - - Environment.playKeyStrokeSound (); - - } - }); - - this.editor.setAlignmentX (Component.LEFT_ALIGNMENT); - //this.editor.addMouseListener (this); - //this.initEditor (); - - this.actions = this.editor.getActionMap (); - - super.setActionMap (this.actions); - - this.actions.put (Constants.SHOW_FIND_ACTION, - new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.viewer.showFind (null); - - } - - }); - - this.actions.put (TOGGLE_SPELLCHECK_ACTION_NAME, - new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.viewer.setSpellCheckingEnabled (!_this.editor.isSpellCheckEnabled ()); - - } - - }); - - this.actions.put (TOGGLE_WORDCOUNTS_ACTION_NAME, - new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.viewer.viewWordCounts (); - - } - - }); - - this.actions.put (EDIT_TEXT_PROPERTIES_ACTION_NAME, - new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - try - { - - _this.showTextProperties (); - - } catch (Exception e) { - - Environment.logError ("Unable to show text properties", - e); - - UIUtils.showErrorMessage (_this, - Environment.getUIString (LanguageStrings.project, - LanguageStrings.editorpanel, - LanguageStrings.actions, - LanguageStrings.edittextproperties, - LanguageStrings.actionerror)); - //"Unable to show text properties."); - - } - - } - - }); - - InputMap im = this.editor.getInputMap (JComponent.WHEN_IN_FOCUSED_WINDOW); - - im.put (KeyStroke.getKeyStroke (KeyEvent.VK_E, - Event.CTRL_MASK), - EDIT_TEXT_PROPERTIES_ACTION_NAME); - im.put (KeyStroke.getKeyStroke (KeyEvent.VK_W, - Event.CTRL_MASK), - TOGGLE_WORDCOUNTS_ACTION_NAME); - im.put (KeyStroke.getKeyStroke (KeyEvent.VK_L, - Event.CTRL_MASK), - TOGGLE_SPELLCHECK_ACTION_NAME); - - im = this.editor.getInputMap (JComponent.WHEN_FOCUSED); - - this.addComponentListener (new ComponentAdapter () - { - - public void componentResized (ComponentEvent ev) - { - - if (_this.isReadyForUse ()) - { - - _this.scrollCaretIntoView (); - - } - - } - - - }); - - this.performAction = new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.performAction (ev); - - } - - }; - - } - - @Override - public void propertyChanged (UserPropertyEvent ev) - { - - TextProperties props = this.viewer.getTextProperties (); - - if (ev.getName ().equals (Constants.EDITOR_FONT_PROPERTY_NAME)) - { - - this.setFontFamily (props.getFontFamily ()); - - } - - if (ev.getName ().equals (Constants.EDITOR_FONT_SIZE_PROPERTY_NAME)) - { - - this.setFontSize (props.getFontSize ()); - - } - - if (ev.getName ().equals (Constants.EDITOR_BGCOLOR_PROPERTY_NAME)) - { - - this.setBackgroundColor (props.getBackgroundColor ()); - - } - - if (ev.getName ().equals (Constants.EDITOR_FONT_COLOR_PROPERTY_NAME)) - { - - this.setTextColor (props.getTextColor ()); - - } - - if (ev.getName ().equals (Constants.EDITOR_TEXT_BORDER_PROPERTY_NAME)) - { - - this.setTextBorder (props.getTextBorder ()); - - } - - if (ev.getName ().equals (Constants.EDITOR_ALIGNMENT_PROPERTY_NAME)) - { - - this.setAlignment (props.getAlignment ()); - - } - - if (ev.getName ().equals (Constants.EDITOR_INDENT_FIRST_LINE_PROPERTY_NAME)) - { - - this.setFirstLineIndent (props.getFirstLineIndent ()); - - } - - if (ev.getName ().equals (Constants.EDITOR_LINE_SPACING_PROPERTY_NAME)) - { - - this.setLineSpacing (props.getLineSpacing ()); - - } - - if (ev.getName ().equals (Constants.EDITOR_WRITING_LINE_COLOR_PROPERTY_NAME)) - { - - this.setWritingLineColor (props.getWritingLineColor ()); - - } - - if (ev.getName ().equals (Constants.EDITOR_HIGHLIGHT_WRITING_LINE_PROPERTY_NAME)) - { - - this.setHighlightWritingLine (props.isHighlightWritingLine ()); - - } - - } - - @Override - public AbstractProjectViewer getViewer () - { - - return super.getViewer (); - - } - - private void scheduleWordCountUpdate () - { - - final AbstractEditorPanel _this = this; - - if (this.wordCountUpdate != null) - { - - return; - - } - - this.wordCountUpdate = new Runnable () - { - - @Override - public void run () - { - - try - { - - _this.viewer.updateChapterCounts (_this.getChapter ()); - - _this.wordCountUpdate = null; - - } catch (Exception e) { - - Environment.logError ("Unable to determine word count for chapter: " + - _this.getChapter (), - e); - - } - - } - - }; - - this.viewer.schedule (this.wordCountUpdate, - 1 * 1000, - -1); - - - } - - public abstract JComponent getEditorWrapper (QTextEditor editor); - - public void setWritingLineColor (Color c) - { - - this.editor.setWritingLineColor (c); - - } - - @Override - public void close () - { - - } - - public void setHighlightWritingLine (boolean v) - { - - this.editor.setHighlightWritingLine (v); - - } - - public void showTextProperties () - throws GeneralException - { - - this.viewer.showTextProperties (); - - } - - public JButton createToolbarButton (String icon, - String toolTipText, - String actionCommand) - { - - return this.createButton (icon, - Constants.ICON_TOOLBAR, - toolTipText, - actionCommand); - - } - - public JButton createButton (String icon, - int iconType, - String toolTipText, - String actionCommand) - { - - JButton but = UIUtils.createButton (icon, - iconType, - toolTipText, - this.performAction); - - but.setActionCommand (actionCommand); - - return but; - - } - - public JButton createButton (String icon, - int iconType, - String toolTipText, - String actionCommand, - ActionListener list) - { - - JButton but = UIUtils.createButton (icon, - iconType, - toolTipText, - list); - - but.setActionCommand (actionCommand); - - return but; - - } - - public JMenuItem createMenuItem (String label, - String icon, - String actionCommand, - KeyStroke accel, - ActionListener list) - { - - JMenuItem mi = UIUtils.createMenuItem (label, - icon, - list); - - mi.setActionCommand (actionCommand); - - mi.setAccelerator (accel); - - return mi; - - - } - - public JMenuItem createMenuItem (String label, - String icon, - String actionCommand, - KeyStroke accel) - { - - JMenuItem mi = this.createMenuItem (label, - icon, - actionCommand); - - mi.setAccelerator (accel); - - return mi; - - - } - - public JMenuItem createMenuItem (String label, - String icon, - String actionCommand) - { - - JMenuItem mi = UIUtils.createMenuItem (label, - icon, - this.performAction); - - mi.setActionCommand (actionCommand); - - return mi; - - } - - public void addPerformActionListener (AbstractButton b) - { - - b.addActionListener (this.performAction); - - } - - public ActionListener getPerformActionListener () - { - - return this.performAction; - - } - - protected void setReadabilityIndices (ReadabilityIndices r) - { - - this.readability = r; - - } - - public ReadabilityIndices getReadabilityIndices () - { - - return this.readability; - - } - - public void setIgnoreDocumentChanges (boolean v) - { - - this.ignoreDocumentChange = v; - - } - - public boolean isIgnoreDocumentChanges () - { - - return this.ignoreDocumentChange; - - } - - public void init () - throws GeneralException - { - - final AbstractEditorPanel _this = this; - - final DefaultStyledDocument doc = (DefaultStyledDocument) this.editor.getDocument (); - - this.editor.setTextWithMarkup (this.getChapter ().getText ()); - - JComponent p = this.getEditorWrapper (this.editor); - p.setAlignmentX (Component.LEFT_ALIGNMENT); - - this.scrollPane = new JScrollPane (p); - this.scrollPane.setBorder (null); - this.scrollPane.setAlignmentX (Component.LEFT_ALIGNMENT); - this.scrollPane.getViewport ().setOpaque (false); - this.scrollPane.getVerticalScrollBar ().setUnitIncrement (20); - - this.origEditorMargin = this.editor.getMargin (); - this.add (this.scrollPane); - - this.scrollPane.addMouseWheelListener (new MouseWheelListener () - { - - public void mouseWheelMoved (MouseWheelEvent ev) - { - - if (_this.useTypewriterScrolling) - { - - try - { - - int c = ev.getWheelRotation (); - - Rectangle r = _this.editor.modelToView (_this.editor.getCaret ().getDot ()); - - int ny = r.y + (c * r.height); - - int d = _this.editor.viewToModel (new Point (r.x, - ny)); - - _this.editor.getCaret ().setDot (d); - - } catch (Exception e) { - - // Just ignore - - } - - } - - } - - }); - - this.editor.addStyleChangeListener (new StyleChangeAdapter () - { - - public void styleChanged (StyleChangeEvent ev) - { - - _this.initScrollBar (); - - } - - }); - - this.editor.addCaretListener (new CaretListener () - { - - - public void caretUpdate (final CaretEvent ev) - { - - UIUtils.doLater (new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - if (_this.useTypewriterScrolling) - { - - _this.updateViewportPositionForTypewriterScrolling (); - - } - - } - - }); - - } - - }); - - this.initEditor (); - - /* - *Experimental... not quite right for page-up. - final ActionListener origPageDown = this.editor.getActionMap ().get ("page-down"); - final ActionListener origPageUp = this.editor.getActionMap ().get ("page-up"); - - this.editor.getActionMap ().put ("page-up", - new TextAction ("here") - { - - public void actionPerformed (ActionEvent ev) - { - - try - { - - int c = _this.editor.getCaret ().getDot (); - - int l = _this.editor.getText ().length (); - - c--; - - if (c <= 0) - { - - return; - - } - - // Find the first non-whitespace. - for (int i = c; i > -1; i--) - { - - if (!Character.isWhitespace (_this.editor.getText ().charAt (i))) - { - - c = i; - - break; - } - - } - - // Find the first newline. - for (int i = c; i > -1; i--) - { - - if (_this.editor.getText ().charAt (i) == '\n') - { - - _this.editor.getCaret ().setDot (i + 1); - - _this.editor.scrollRectToVisible (_this.editor.modelToView (i + 1)); - - break; - - } - - } - - } catch (Exception e) { - - e.printStackTrace (); - - - } - } - - }); - - this.editor.getActionMap ().put ("page-down", - new TextAction ("here") - { - - public void actionPerformed (ActionEvent ev) - { - - try - { - - int c = _this.editor.getCaret ().getDot (); - - int l = _this.editor.getText ().length (); - - if (c >= l) - { - - return; - - } - - int n = _this.editor.getText ().indexOf ('\n', c); - - if (n > c) - { - - // Find the first non-whitespace. - for (int i = n; i < _this.editor.getText ().length (); i++) - { - - if (!Character.isWhitespace (_this.editor.getText ().charAt (i))) - { - - _this.editor.getCaret ().setDot (i); - - _this.editor.scrollRectToVisible (_this.editor.modelToView (i)); - - break; - - } - - } - - } - - } catch (Exception e) { - - e.printStackTrace (); - - - } - } - - }); - */ - } - - public void setSoftCaret (int c) - { - - this.softCaret = c; - - this.updateViewportPositionForTypewriterScrolling (); - - } - - public void updateViewportPositionForTypewriterScrolling () - { - - if (!this.useTypewriterScrolling) - { - - return; - - } - - final AbstractEditorPanel _this = this; - - UIUtils.doLater (new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - int dot = (_this.softCaret > -1 ? _this.softCaret : _this.editor.getCaret ().getDot ()); - - Rectangle r = null; - - try - { - - r = _this.editor.modelToView (dot); - - } catch (Exception e) { - - // Ignore. - return; - - } - - _this.softCaret = -1; - - if (r == null) - { - - return; - - } - - Insets i = _this.editor.getMargin (); - int hh = _this.scrollPane.getSize ().height / 2; - int y = r.y; - - if (i != null) - { - - y -= i.top; - - } - - if ((y - hh) < 0) - { - - _this.editor.setMargin (new Insets (-1 * (y - hh), - _this.origEditorMargin.left, - _this.origEditorMargin.bottom, - _this.origEditorMargin.right)); - - _this.scrollPane.getViewport ().setViewPosition (new Point (0, 0)); - - } else { - - if (y > (_this.editor.getSize ().height - hh - i.bottom - (r.height / 2))) - { - - _this.editor.setMargin (new Insets (_this.origEditorMargin.top, - _this.origEditorMargin.left, - //hh - (_this.editor.getSize ().height - y - i.bottom - (r.height / 2)), - hh - (_this.editor.getSize ().height - y - i.bottom - Math.round ((float) r.height / 2f)), - _this.origEditorMargin.right)); - - } else { - - _this.editor.setMargin (new Insets (_this.origEditorMargin.top, - _this.origEditorMargin.left, - _this.origEditorMargin.bottom, - _this.origEditorMargin.right)); - - } - - Point p = new Point (0, y - hh + (r.height /2)); - - _this.scrollPane.getViewport ().setViewPosition (p); - - } - - _this.validate (); - _this.repaint (); - - } - - }); - - } - - public void setUseTypewriterScrolling (boolean v) - { - - this.useTypewriterScrolling = v; - - if (!v) - { - - this.scrollPane.setVerticalScrollBarPolicy (ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED); - // Reset the margin. - this.editor.setMargin (this.origEditorMargin); - - } else { - - this.scrollPane.setVerticalScrollBarPolicy (ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER); - - } - - this.scrollCaretIntoView (); - - this.scrollPane.getViewport ().setViewSize (this.editor.getPreferredSize ()); - - this.editor.grabFocus (); - - } - - public Chapter getChapter () - { - - return this.getForObject (); - - } - - public QTextEditor getEditor () - { - - return this.editor; - - } - - public int getScrollOffset () - { - - return this.scrollPane.getVerticalScrollBar ().getValue (); - - } - - public void incrementScrollPositionBy (int p) - { - - this.scrollPane.getVerticalScrollBar ().setValue (this.scrollPane.getVerticalScrollBar ().getValue () + p); - - } - - public void scrollToPosition (final int p) - throws GeneralException - { - - if (this.useTypewriterScrolling) - { - - // Not compatible with typewriter scrolling. - return; - - } - - if (this.isScrolling) - { - - final AbstractEditorPanel _this = this; - - UIUtils.doLater (new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - try - { - - _this.scrollToPosition (p); - - } catch (Exception e) { - - Environment.logError ("Unable to scroll to: " + p, - e); - - } - - } - - }); - - return; - - } - - try - { - - this.isScrolling = true; - - Rectangle r = null; - - try - { - - r = this.editor.modelToView (p); - - } catch (Exception e) - { - - // BadLocationException! - throw new GeneralException ("Position: " + - p + - " is not valid.", - e); - - } - - if (r == null) - { - - throw new GeneralException ("Position: " + - p + - " is not valid."); - - } - - int y = r.y - r.height; - - if (y < 0) - { - - y = 0; - - } - - this.scrollPane.getVerticalScrollBar ().setValue (y); - - } finally { - - this.isScrolling = false; - - } - - } - - private void initScrollBar () - { - - int l = this.editor.getLineHeight (); - - JScrollBar sc = this.scrollPane.getVerticalScrollBar (); - - int o = sc.getValue (); - - sc.setUnitIncrement (l); - - sc.setValue ((int) (Math.floor (o / l) * l)); - - sc.setBlockIncrement (l); - - } - - public void setState (final Map s, - boolean hasFocus) - { - - final AbstractEditorPanel _this = this; - - UIUtils.doLater (new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - try - { - - JScrollBar sc = _this.scrollPane.getVerticalScrollBar (); - - int o = Integer.parseInt (s.get (Constants.LAST_EDITOR_SCROLL_POSITION_PROPERTY_NAME)); - - sc.setValue (o); - - int v = Integer.parseInt (s.get (Constants.LAST_EDITOR_CARET_POSITION_PROPERTY_NAME)); - - _this.editor.setSelectionStart (v); - _this.editor.setSelectionEnd (v); - _this.editor.getCaret ().setDot (v); - - } catch (Exception e) - { - - // Ignore it. - - } finally { - - _this.initScrollBar (); - - } - - } - - }); - - //this.scrollCaretIntoView (); - - if (hasFocus) - { - - this.editor.grabFocus (); - - } - - } - - public void getState (Map m) - { - - m.put (Constants.LAST_EDITOR_SCROLL_POSITION_PROPERTY_NAME, - this.scrollPane.getVerticalScrollBar ().getValue ()); - m.put (Constants.LAST_EDITOR_CARET_POSITION_PROPERTY_NAME, - this.editor.getSelectionStart ()); - - } - - public void initEditor (TextProperties props) - { - - this.ignoreDocumentChange = true; - - this.setLineSpacing (props.getLineSpacing ()); - this.setFontSize (props.getFontSize ()); - this.setFontFamily (props.getFontFamily ()); - this.setAlignment (props.getAlignment ()); - this.setFirstLineIndent (props.getFirstLineIndent ()); - - this.setBackgroundColor (props.getBackgroundColor ()); - this.setTextColor (props.getTextColor ()); - this.setWritingLineColor (props.getWritingLineColor ()); - this.setHighlightWritingLine (props.isHighlightWritingLine ()); - this.setTextBorder (props.getTextBorder ()); - - this.ignoreDocumentChange = false; - - // Add a listener for changes to the properties. - UserProperties.addListener (this); - - } - - public void initEditor () - { - - this.ignoreDocumentChange = true; - - TextProperties props = this.viewer.getTextProperties (); - - this.initEditor (props); - - this.ignoreDocumentChange = false; - - } - - public List getTopLevelComponents () - { - - List l = new ArrayList (); - l.add (this.editor); - - return l; - - } - - public void refresh () - { - - // No need to do anything. - - } - - public void setSynonymProvider (SynonymProvider sp) - { - - this.editor.setSynonymProvider (sp); - - } - - public void setDictionaryProvider (DictionaryProvider2 dp) - { - - this.editor.setDictionaryProvider (dp); - - } - - public void checkSpelling () - { - - this.editor.checkSpelling (); - - } - - public void setSpellCheckingEnabled (boolean v) - { - - this.editor.setSpellCheckEnabled (v); - - String type = (v ? "off" : "on"); - - this.setToolBarButtonIcon ("toggle-spellcheck", - getUIString (dictionary,spellcheck,buttons,(v ? off : on),tooltip), - //"Click to turn the spell checker " + type, - "spellchecker-turn-" + type); - - } - - @Override - public String getTitle () - { - - return this.obj.getName (); - - } - - @Override - public ImageIcon getIcon (int type) - { - - return Environment.getIcon (this.obj.getObjectType (), - type); - - } - - public void setCaretPosition (int dot) - { - - this.editor.getCaret ().setDot (dot); - - } - - public void setFontColor (Color c) - { - - this.ignoreDocumentChange = true; - - this.editor.setFontColor (c); - - this.editor.setCaretColor (c); - - this.ignoreDocumentChange = false; - - } - - public void setTextColor (Color c) - { - - this.setFontColor (c); - - } - - public void restoreFontColor () - { - - this.ignoreDocumentChange = true; - - this.editor.setFontColor (Color.black); - this.editor.setCaretColor (Color.black); - - this.ignoreDocumentChange = false; - - } - - public void restoreBackgroundColor () - { - - this.editor.setBackground (Color.white); - - } - - public void setBackgroundColor (Color c) - { - - this.editor.setBackground (c); - - } - - public Color getBackgroundColor () - { - - return this.editor.getBackground (); - - } - - public JScrollPane getScrollPane () - { - - return this.scrollPane; - - } - - public void scrollCaretIntoView () - { - - this.scrollCaretIntoView (null); - - } - - public void scrollCaretIntoView (final Runnable runAfterScroll) - { - - final AbstractEditorPanel _this = this; - - UIUtils.doLater (new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - try - { - - int c = _this.editor.getCaret ().getDot (); - - if (c > -1) - { - - _this.scrollToPosition (c); - - } - - _this.updateViewportPositionForTypewriterScrolling (); - - if (runAfterScroll != null) - { - - SwingUtilities.invokeLater (runAfterScroll); - - } - - } catch (Exception e) - { - - // Ignore it. - - } - - } - - }); - - } - - public TextProperties getTextProperties () - { - - return Environment.getProjectTextProperties (); - - } - - public void setFontSize (int v) - { - - this.ignoreDocumentChange = true; - - this.editor.setFontSize (UIUtils.getEditorFontSize (v)); - - this.ignoreDocumentChange = false; - - } - - public void setFontFamily (String name) - { - - this.ignoreDocumentChange = true; - - this.editor.setFontFamily (name); - - this.ignoreDocumentChange = false; - - } - - public void setAlignment (String v) - { - - this.ignoreDocumentChange = true; - - this.editor.setAlignment (v); - - this.ignoreDocumentChange = false; - - } - - public void setFirstLineIndent (boolean v) - { - - this.ignoreDocumentChange = true; - - this.editor.setFirstLineIndent (v); - - this.ignoreDocumentChange = false; - - } - - @Override - public void setTextBorder (int v) - { - - this.ignoreDocumentChange = true; - - this.editor.setBorder (new CompoundBorder (this.origEditorBorder, - UIUtils.createPadding (0, v, 0, v))); - - this.ignoreDocumentChange = false; - - } - - public void setLineSpacing (float v) - { - - this.ignoreDocumentChange = true; - - this.editor.setLineSpacing (v); - - this.ignoreDocumentChange = false; - - } - - public Point getLastMousePosition () - { - - return this.lastMousePosition; - - } - -} diff --git a/src/com/quollwriter/ui/panels/AssetViewPanel.java b/src/com/quollwriter/ui/panels/AssetViewPanel.java deleted file mode 100644 index 0bdf800e..00000000 --- a/src/com/quollwriter/ui/panels/AssetViewPanel.java +++ /dev/null @@ -1,528 +0,0 @@ -package com.quollwriter.ui.panels; - -import java.awt.*; -import java.awt.event.*; - -import java.io.*; - -import java.lang.reflect.*; - -import java.text.*; - -import java.util.HashMap; -import java.util.List; -import java.util.ArrayList; -import java.util.Map; -import java.util.Set; -import java.util.LinkedHashSet; -import java.util.Arrays; - -import javax.swing.*; -import javax.swing.border.*; -import javax.swing.event.*; -import javax.swing.text.*; -import javax.swing.text.html.*; -import javax.swing.tree.*; - -import com.gentlyweb.properties.*; - -import com.gentlyweb.utils.*; - -import com.jgoodies.forms.builder.*; -import com.jgoodies.forms.factories.*; -import com.jgoodies.forms.layout.*; - -import com.quollwriter.*; -import com.quollwriter.ui.*; -import com.quollwriter.data.*; -import com.quollwriter.ui.renderers.*; -import com.quollwriter.events.*; - -import com.quollwriter.ui.actionHandlers.*; -import com.quollwriter.ui.userobjects.*; -//import com.quollwriter.ui.components.*; -import com.quollwriter.ui.components.ActionAdapter; -import com.quollwriter.ui.components.QPopup; - -import static com.quollwriter.LanguageStrings.*; -import static com.quollwriter.Environment.getUIString; - -public class AssetViewPanel extends AbstractObjectViewPanel implements PropertyChangedListener, ProjectEventListener -{ - - private AppearsInChaptersEditPanel appearsInPanel = null; - - public AssetViewPanel (ProjectViewer pv, - Asset a) - throws GeneralException - { - - super (pv, - a); - - Environment.addUserProjectEventListener (this); - - } - - @Override - public ImageIcon getIcon (int type) - { - - int w = Environment.getIconPixelWidthForType (type); - - ImageIcon im = null; - - if (w == 24) - { - - im = this.getForObject ().getUserConfigurableObjectType ().getIcon24x24 (); - - } - - if (w == 16) - { - - im = this.getForObject ().getUserConfigurableObjectType ().getIcon16x16 (); - - } - - return im; - - } - - @Override - public void eventOccurred (ProjectEvent ev) - { - - if (ev.getType ().equals (ProjectEvent.USER_OBJECT_TYPE)) - { - - if (ev.getSource ().equals (this.getForObject ().getUserConfigurableObjectType ())) - { - - this.refresh (); - - } - - } - - } - - /** - * Get the edit details panel for the specified asset, callers MUST call "init" to finish the creation. - * - * @param a The asset. - * @param pv The project viewer. - * @returns The edit details panel. - * @throws GeneralException If the panel cannot be created. - */ - @Override - public AssetDetailsEditPanel getDetailEditPanel (ProjectViewer pv, - NamedObject n) - throws GeneralException - { - - final AssetViewPanel _this = this; - - final AssetDetailsEditPanel p = new AssetDetailsEditPanel ((Asset) n, - pv); - - p.addActionListener (new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - if (ev.getID () == EditPanel.EDIT_VISIBLE) - { - - _this.setHasUnsavedChanges (p, - true); - - } - - if ((ev.getID () == EditPanel.CANCELLED) || - (ev.getID () == EditPanel.VIEW_VISIBLE) || - (ev.getID () == EditPanel.SAVED)) - { - - _this.setHasUnsavedChanges (p, - false); - - } - - } - - }); - - return p; - - } - - public static ActionListener getEditAssetAction (final ProjectViewer pv, - final Asset a) - { - - return new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - // Display the object then edit it. - pv.viewObject (a, - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - AssetViewPanel p = (AssetViewPanel) pv.getQuollPanelForObject (a); - - if (p == null) - { - - Environment.logError ("Unable to edit asset: " + - a); - - UIUtils.showErrorMessage (pv, - String.format (getUIString (assets,edit,actionerror), - a.getObjectTypeName (), - a.getName ())); - - return; - - } - - p.editObject (); - - } - - }); - - } - - }; - - } - - public static ActionListener getDeleteAssetAction (final ProjectViewer pv, - final Asset a) - { - - return new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - List prefix = Arrays.asList (assets,delete,confirmpopup); - - UIUtils.createQuestionPopup (pv, - String.format (getUIString (prefix,title), - a.getObjectTypeName ()), - Constants.DELETE_ICON_NAME, - String.format (getUIString (prefix,text), - a.getObjectTypeName (), - a.getName ()), - getUIString (prefix,buttons,confirm), - getUIString (prefix,buttons,cancel), - //"Yes, delete it", - //null, - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - try - { - - pv.deleteObject (a); - - } catch (Exception e) { - - Environment.logError ("Unable to delete asset: " + - a, - e); - - UIUtils.showErrorMessage (pv, - String.format (getUIString (assets,delete,actionerror), - a.getObjectTypeName (), - a.getName ())); - - } - - } - - }, - null, - null, - null); - - } - - }; - - } - - public ActionListener getEditObjectAction (ProjectViewer pv, - NamedObject n) - { - - return AssetViewPanel.getEditAssetAction (pv, - (Asset) n); - - } - - public ActionListener getDeleteObjectAction (ProjectViewer pv, - NamedObject n) - { - - return AssetViewPanel.getDeleteAssetAction (pv, - (Asset) n); - - } - - public void doFillToolBar (JToolBar tb, - boolean fullScreen) - { - - List prefix = Arrays.asList (assets,view,toolbar); - - final AssetViewPanel _this = this; - - final JButton b = UIUtils.createToolBarButton (Constants.NEW_ICON_NAME, - getUIString (prefix,_new,tooltip), - //"Click to add a new " + Environment.getObjectTypeName (QCharacter.OBJECT_TYPE) + ", " + Environment.getObjectTypeName (Location.OBJECT_TYPE) + ", " + Environment.getObjectTypeName (QObject.OBJECT_TYPE) + " etc.", - "new", - null); - - ActionAdapter ab = new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - JPopupMenu m = new JPopupMenu (); - - UIUtils.addNewAssetItemsToPopupMenu (m, - b, - _this.viewer, - null, - null); - - Component c = (Component) ev.getSource (); - - m.show (c, - c.getX (), - c.getY ()); - - } - - }; - - b.addActionListener (ab); - - tb.add (b); - - JButton tagsb = UIUtils.createTagsMenuToolBarButton (this.obj, - this.viewer); - - tagsb.setToolTipText (String.format (getUIString (prefix,tags,tooltip), - //"Click to add/remove tags for this %1$s", - Environment.getObjectTypeName (this.obj))); - - tb.add (tagsb); - - tb.add (UIUtils.createToolBarButton ("delete", - String.format (getUIString (prefix,delete,tooltip), - this.obj.getObjectTypeName ()), - //"Click to delete this " + Environment.getObjectTypeName (this.obj.getObjectType ()), - "delete", - this.getDeleteObjectAction (this.viewer, - this.obj))); - - } - - public void doInit () - { - - this.obj.addPropertyChangedListener (this); - - } - - @Override - public void propertyChanged (PropertyChangedEvent ev) - { - - /* - EditPanel edPan = this.getDetailsPanel (); - - final Set objChangeEventTypes = edPan.getObjectChangeEventTypes (); - - if ((objChangeEventTypes == null) - || - (objChangeEventTypes.size () == 0) - ) - { - - return; - - } - - boolean update = false; - - for (String t : objChangeEventTypes) - { - - if (ev.getChangeType ().equals (t)) - { - - update = true; - - break; - - } - - } - - if (!update) - { - - return; - - } - - this.refresh (); -*/ - } - - public JComponent getBottomPanel () - { - - final AppearsInChaptersEditPanel ep = this.createAppearsInChaptersPanel (); - final AssetViewPanel _this = this; - - ep.init (); - - return ep; - - } - - public AppearsInChaptersEditPanel getAppearsInChaptersEditPanel () - { - - return this.appearsInPanel; - - } - - private AppearsInChaptersEditPanel createAppearsInChaptersPanel () - { - - this.appearsInPanel = new AppearsInChaptersEditPanel (this.viewer, - this.obj); - - return this.appearsInPanel; - - } - - @Override - public void doRefresh () - { - - this.getHeader ().setIcon (this.obj.getUserConfigurableObjectType ().getIcon24x24 ()); - - if (this.appearsInPanel != null) - { - - this.appearsInPanel.refresh (); - - } - - } - - @Override - public void close () - { - - this.obj.removePropertyChangedListener (this); - - } - - @Override - public void fillPopupMenu (MouseEvent ev, - JPopupMenu popup) - { - - List prefix = Arrays.asList (assets,view,popupmenu,items); - - // Don't show the popup when we are editing the details. - if (this.getDetailsPanel ().isEditing ()) - { - - popup.add (UIUtils.createMenuItem (getUIString (prefix,save), - Constants.SAVE_ICON_NAME, - this.getDetailsPanel ().getDoSaveAction ())); - - return; - - } - - final AssetViewPanel _this = this; - - popup.add (UIUtils.createMenuItem (getUIString (prefix,edit), - Constants.EDIT_ICON_NAME, - this.getEditObjectAction (this.viewer, - (Asset) this.obj))); - - popup.add (UIUtils.createTagsMenu (this.obj, - this.viewer)); - - popup.add (UIUtils.createMenuItem (getUIString (prefix,addfileordocument), - //"Add File/Document", - Constants.ADD_ICON_NAME, - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - _this.getObjectDocumentsEditPanel ().showAddDocument (); - - } - - })); - - popup.add (UIUtils.createMenuItem (getUIString (prefix,delete), - //"Delete", - Constants.DELETE_ICON_NAME, - this.getDeleteObjectAction (this.viewer, - (Asset) this.obj))); - - popup.addSeparator (); - - popup.add (UIUtils.createMenuItem (String.format (getUIString (prefix,editobjecttypeinfo), - //"Edit the %s information/fields", - this.obj.getObjectTypeName ()), - Constants.EDIT_ICON_NAME, - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - UIUtils.showObjectTypeEdit (_this.obj.getUserConfigurableObjectType (), - _this.viewer); - - } - - })); - - } - -} diff --git a/src/com/quollwriter/ui/panels/IdeaBoard.java b/src/com/quollwriter/ui/panels/IdeaBoard.java deleted file mode 100644 index 2edefce8..00000000 --- a/src/com/quollwriter/ui/panels/IdeaBoard.java +++ /dev/null @@ -1,2020 +0,0 @@ -package com.quollwriter.ui.panels; - -import java.awt.Color; -import java.awt.Component; -import java.awt.Dimension; -import java.awt.Graphics; -import java.awt.Graphics2D; -import java.awt.Image; -import java.awt.Paint; -import java.awt.Point; -import java.awt.Rectangle; -import java.awt.TexturePaint; -import java.awt.event.*; -import java.awt.image.BufferedImage; - -import java.io.*; - -import java.beans.*; - -import java.text.*; - -import java.util.Arrays; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.StringTokenizer; - -import javax.swing.*; -import javax.swing.border.*; -import javax.swing.event.*; - -import com.jgoodies.forms.factories.*; - -import static com.quollwriter.LanguageStrings.*; -import static com.quollwriter.Environment.getUIString; - -import com.quollwriter.*; -import com.quollwriter.ui.*; -import com.quollwriter.data.*; -import com.quollwriter.text.*; - -import com.quollwriter.events.*; - -import com.quollwriter.ui.actionHandlers.*; -import com.quollwriter.ui.components.ActionAdapter; -import com.quollwriter.ui.components.ChangeAdapter; -import com.quollwriter.ui.components.Header; -import com.quollwriter.ui.components.ImagePanel; -import com.quollwriter.ui.components.QPopup; -import com.quollwriter.ui.components.VerticalLayout; - - -public class IdeaBoard extends ProjectObjectQuollPanel -{ - - public static final String PANEL_ID = "ideaboard"; - - private static final Color lightGrey = UIUtils.getColor ("#aaaaaa"); - - public class IdeaBox extends Box - { - - private Idea idea = null; - private TypeBox typeBox = null; - private Box viewBox = null; - private AddEditBox editBox = null; - private JEditorPane shortDesc = null; - private JEditorPane fullDesc = null; - private IdeaBoard ideaBoard = null; - - public IdeaBox(Idea i, - TypeBox tb, - boolean showToolBar) - { - - super (BoxLayout.Y_AXIS); - - this.typeBox = tb; - this.idea = i; - - this.setAlignmentX (Component.LEFT_ALIGNMENT); - - this.createViewBox (showToolBar); - - this.editBox = new AddEditBox (i, - tb, - this); - - this.editBox.setAlignmentX (Component.LEFT_ALIGNMENT); - - this.add (editBox); - - } - - public Idea getIdea () - { - - return this.idea; - - } - - public void showViewBox () - { - - this.viewBox.setVisible (true); - this.editBox.setVisible (false); - - this.typeBox._repaint (); - - } - - private void createViewBox (boolean showToolBar) - { - - java.util.List prefix = Arrays.asList (ideaboard,ideas,view); - - final IdeaBox _this = this; - - this.viewBox = new Box (BoxLayout.Y_AXIS); - this.add (this.viewBox); - this.viewBox.setAlignmentX (Component.LEFT_ALIGNMENT); -/* - this.shortDesc = UIUtils.createHelpTextPane ((String) null, - this.typeBox.ideaBoard.getViewer ()); - */ - - this.shortDesc = UIUtils.createObjectDescriptionViewPane ((String) null, - this.typeBox.ideaBoard.getViewer ().getProject (), - this.typeBox.ideaBoard.getViewer (), - this.typeBox.ideaBoard); - - this.shortDesc.setBorder (UIUtils.createPadding (3, 5, 0, 5)); - this.viewBox.add (this.shortDesc); - this.shortDesc.setAlignmentX (Component.LEFT_ALIGNMENT); -/* - this.fullDesc = UIUtils.createHelpTextPane ((String) null, - this.typeBox.ideaBoard.getViewer ()); -*/ - this.fullDesc = UIUtils.createObjectDescriptionViewPane ((String) null, - this.typeBox.ideaBoard.getViewer ().getProject (), - this.typeBox.ideaBoard.getViewer (), - this.typeBox.ideaBoard); - - this.fullDesc.setBorder (UIUtils.createPadding (3, 5, 0, 5)); - this.updateViewText (); - - this.viewBox.add (this.fullDesc); - this.fullDesc.setAlignmentX (Component.LEFT_ALIGNMENT); - - this.fullDesc.setVisible (false); - - this.viewBox.setAlignmentX (Component.LEFT_ALIGNMENT); - - this.viewBox.setMinimumSize (new Dimension (300, - 50)); - - this.viewBox.add (Box.createVerticalStrut (3)); - - List buttons = new ArrayList (); - - // Create the actions bar. - JButton mb = new JButton (Environment.getIcon ("edit", - Constants.ICON_MENU)); - mb.setToolTipText (getUIString (prefix, LanguageStrings.buttons,edit,tooltip));//"Click to edit this item"); - mb.setOpaque (false); - mb.addActionListener (new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.viewBox.setVisible (false); - _this.editBox.setVisible (true); - _this.typeBox._repaint (); - - } - - }); - - buttons.add (mb); - - // mb = new JButton (Environment.getIcon (Link.OBJECT_TYPE, - // false)); - // mb.setToolTipText ("Click to link this item to other items/objects"); - // mb.setOpaque (false); - - // aah = this.getEditItemActionHandler (); - - // aah.setPopupOver (this.quollEditorPanel); //this.projectViewer.getEditorForChapter (it.getChapter ())); - // aah.setShowLinkTo (true); - // mb.addActionListener (aah); - // mb.addActionListener (aa); - // buttons.add (mb); - - mb = new JButton (Environment.getIcon (Constants.CONVERT_ICON_NAME, - Constants.ICON_MENU)); - mb.setToolTipText (getUIString (prefix, LanguageStrings.buttons,convert,tooltip)); - //Environment.replaceObjectNames ("Click to convert this idea to an item such as a {Chapter}, {Object} etc.")); - mb.setOpaque (false); - - mb.addActionListener (new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - JPopupMenu p = new JPopupMenu (); - - String oName = Environment.getObjectTypeName (Chapter.OBJECT_TYPE); - - JMenuItem mi = new JMenuItem (oName, - Environment.getIcon (Chapter.OBJECT_TYPE, - Constants.ICON_MENU)); - - char fc = Character.toUpperCase (oName.charAt (0)); - - mi.setMnemonic (fc); - //mi.setToolTipText (pref + fc); - - // Get the last chapter from the project. - final Chapter ch = _this.typeBox.ideaBoard.projectViewer.getProject ().getBook (0).getLastChapter (); - - Chapter newCh = new Chapter (ch.getBook (), - null); - - newCh.setDescription (_this.idea.getDescription ()); - - AddChapterActionHandler caa = new AddChapterActionHandler (ch.getBook (), - ch, - _this.typeBox.ideaBoard.projectViewer, - newCh); - - mi.addActionListener (caa); - - p.add (mi); - - UIUtils.addNewAssetItemsToPopupMenu (p, - _this.typeBox.ideaBoard, - _this.typeBox.ideaBoard.projectViewer, - null, - _this.idea.getDescriptionText ()); - - Component c = (Component) ev.getSource (); - - p.show (c, - 10, - 10); - - } - - }); - - buttons.add (mb); - - mb = new JButton (Environment.getIcon (Constants.DELETE_ICON_NAME, - Constants.ICON_MENU)); - mb.setOpaque (false); - mb.setToolTipText (getUIString (prefix, LanguageStrings.buttons,delete,tooltip)); - //"Click to delete this item"); - - mb.addActionListener (new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - Point p = SwingUtilities.convertPoint ((Component) ev.getSource (), - 0, - 0, - IdeaBoard.this.projectViewer); - - java.util.List prefix = Arrays.asList (ideaboard,ideas,delete,popup); - - UIUtils.createQuestionPopup (_this.typeBox.getIdeaBoard ().projectViewer, - getUIString (prefix,title), - //"Delete the {idea}?", - Constants.DELETE_ICON_NAME, - getUIString (prefix,text), - //"Please confirm you wish to delete this {idea}?", - getUIString (prefix, LanguageStrings.buttons,confirm), - //"Yes, delete it", - getUIString (prefix, LanguageStrings.buttons,cancel), - //null, - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - if (_this.typeBox.getIdeaBoard ().projectViewer.deleteIdea (_this.idea)) - { - - _this.idea.getType ().removeIdea (_this.idea); - - _this.typeBox.removeIdea (_this.idea); - - } - - } - - }, - null, - null, - p); - - } - - }); - - buttons.add (mb); - - JButton hideBut = new JButton (Environment.getIcon (Constants.UP_ICON_NAME, - Constants.ICON_MENU)); - hideBut.setOpaque (false); - hideBut.setToolTipText (getUIString (prefix, LanguageStrings.buttons,hide,tooltip));//"Click to hide"); - - buttons.add (hideBut); - - JToolBar tb = UIUtils.createButtonBar (buttons); - - tb.setAlignmentX (Component.LEFT_ALIGNMENT); - - final Box tbb = new Box (BoxLayout.X_AXIS); - tbb.setAlignmentX (Component.LEFT_ALIGNMENT); - tbb.setBorder (new EmptyBorder (3, - 3, - 0, - 3)); - tbb.add (tb); - tbb.add (Box.createHorizontalGlue ()); - - tbb.setVisible (showToolBar); - - this.viewBox.add (tbb); - - hideBut.addActionListener (new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.shortDesc.setVisible (true); - _this.fullDesc.setVisible (false); - tbb.setVisible (false); - - _this.typeBox._repaint (); - - } - - }); - - MouseEventHandler vis = new MouseEventHandler () - { - - @Override - public void handlePress (MouseEvent ev) - { - - _this.shortDesc.setVisible (false); - _this.fullDesc.setVisible (true); - tbb.setVisible (true); - - _this.typeBox._repaint (); - - } - - }; - - this.shortDesc.addMouseListener (vis); - - StarBar sb = new StarBar (); - - sb.setToolTipText (getUIString (prefix, LanguageStrings.buttons,rating,tooltip));//"Rate this item."); - sb.setSelected (this.idea.getRating ()); - - // Now add the property change listener. - sb.addPropertyChangeListener (StarBar.RATING, - new PropertyChangeAdapter () - { - - public void propertyChange (PropertyChangeEvent ev) - { - - if (!ev.getPropertyName ().equals (StarBar.RATING)) - { - - return; - - } - - _this.idea.setRating ((Integer) ev.getNewValue ()); - - _this.updateIdea (); - - _this.typeBox.getIdeaBoard ().getViewer ().fireProjectEvent (Idea.OBJECT_TYPE, - ProjectEvent.RATE); - - } - - }); - - tbb.add (sb); - - this.viewBox.add (Box.createVerticalStrut (3)); - - this.viewBox.setBorder (new MatteBorder (0, - 0, - 1, - 0, - Environment.getBorderColor ())); - - } - - public void saveIdea (StringWithMarkup text) - { - - if (!text.hasText ()) - { - - return; - - } - - this.idea.setDescription (text); - - this.updateIdea (); - - this.showViewBox (); - - } - - private void updateIdea () - { - - try - { - - this.typeBox.ideaBoard.projectViewer.saveObject (this.idea, - false); - - } catch (Exception e) - { - - Environment.logError ("Unable to update idea: " + - this.idea, - e); - - UIUtils.showErrorMessage (this.typeBox.ideaBoard, - getUIString (ideaboard,ideas,save,actionerror)); - //"Unable to update idea."); - - } - - this.updateViewText (); - - } - - private void updateViewText () - { - - StringWithMarkup sm = this.idea.getDescription (); - - Paragraph p = new Paragraph (sm.getText (), - 0); - - String firstSent = ""; - - if (p.getSentenceCount () > 0) - { - - firstSent = p.getFirstSentence ().markupAsHTML (sm.getMarkup ()); - - if (p.getSentenceCount () > 1) - { - - firstSent += getUIString (ideaboard,ideas,view,shorttext,more); - //" More..."; - - } - - } - - this.shortDesc.setText (firstSent); - - this.shortDesc.setToolTipText (getUIString (ideaboard,ideas,view,shorttext,tooltip)); - //"Click to show the full text"); - - this.fullDesc.setText (this.idea.getDescription ().getMarkedUpText ()); - - } - - } - - public class AddEditBox extends Box - { - - private Idea idea = null; - private TextArea text = null; - private TypeBox typeBox = null; - private IdeaBox ideaBox = null; - - public AddEditBox(final Idea i, - final TypeBox typeBox, - final IdeaBox ideaBox) - { - - super (BoxLayout.Y_AXIS); - - this.idea = i; - this.typeBox = typeBox; - this.ideaBox = ideaBox; - - this.setBorder (new CompoundBorder (new EmptyBorder (3, - 3, - 3, - 3), - UIUtils.createLineBorder ())); - - this.text = UIUtils.createTextArea (typeBox.getIdeaBoard ().projectViewer, - getUIString (ideaboard,ideas,_new, LanguageStrings.text,tooltip), - //"Enter your {Idea} here...", - 5, - -1); - this.text.getScrollPane ().setMaximumSize (this.text.getMaximumSize ()); - this.text.getScrollPane ().setPreferredSize (this.text.getPreferredSize ()); - this.text.setCanFormat (true); - this.text.setAutoGrabFocus (true); - this.text.setBorder (null); - - final AddEditBox _this = this; - - UIUtils.addDoActionOnReturnPressed (this.text, - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.save (); - - } - - }); - - this.initTextArea (); - - this.add (this.text); - - this.setVisible (false); - - //this.add (Box.createVerticalStrut (5)); - - JButton save = UIUtils.createButton (Constants.SAVE_ICON_NAME, - Constants.ICON_MENU, - getUIString (ideaboard,ideas,_new,buttons, LanguageStrings.save,tooltip), - //"Click to save the idea", - new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.save (); - - } - - }); - - JButton cancel = UIUtils.createButton (Constants.CANCEL_ICON_NAME, - Constants.ICON_MENU, - getUIString (ideaboard,ideas,_new,buttons, LanguageStrings.cancel,tooltip), - //"Click to cancel", - new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.typeBox.hideAdd (); - - if (i != null) - { - - ideaBox.showViewBox (); - - } - - } - - }); - - List buts = new ArrayList (); - - buts.add (save); - buts.add (cancel); - - JToolBar tb = UIUtils.createButtonBar (buts); - - tb.setAlignmentX (Component.LEFT_ALIGNMENT); - - Box buttons = new Box (BoxLayout.X_AXIS); - buttons.setAlignmentX (Component.LEFT_ALIGNMENT); - buttons.add (Box.createHorizontalGlue ()); - buttons.add (tb); - - buttons.setBorder (UIUtils.createTopLineWithPadding (3, 3, 3, 3)); - - this.add (buttons); - - } - - private void save () - { - - StringWithMarkup t = this.text.getTextWithMarkup (); - - if (!t.hasText ()) - { - - return; - - } - - if (this.idea == null) - { - - typeBox.createIdea (t); - - } else - { - - ideaBox.saveIdea (t); - - } - - this.text.clearText (); - - } - - public void setVisible (boolean v) - { - - super.setVisible (v); - - this.initTextArea (); - - } - - private void initTextArea () - { - - if (this.idea != null) - { - - this.text.setText (this.idea.getDescription ()); - - } - - } - - } - - public class TypeBox extends QPopup - { - - private Box ideaBox = null; - private AddEditBox addBox = null; - private JTextPane helpText = null; - private IdeaBoard ideaBoard = null; - private IdeaType ideaType = null; - - public TypeBox(IdeaType it, - IdeaBoard ideaBoard) - { - - super ("name", - null, - //((it.getIconType () == null) ? null : Environment.getIcon (it.getIconType (), - // Constants.ICON_POPUP)), - null); - - if (it.getIconType () != null) - { - - // TODO: Not a good hack... - if (it.getIconType ().startsWith ("asset:")) - { - - try - { - - UserConfigurableObjectType type = Environment.getUserConfigurableObjectType (Long.parseLong (it.getIconType ().substring ("asset:".length ()))); - - if (type != null) - { - - this.getHeader ().setIcon (type.getIcon16x16 ()); - - } - - } catch (Exception e) { - - Environment.logError ("Unable to get user object type for: " + - it.getIconType (), - e); - - } - - } else { - - this.getHeader ().setIcon (Environment.getIcon (it.getIconType (), - Constants.ICON_POPUP)); - - } - - } - - this.ideaType = it; - - this.setAllowRemoveOnEscape (false); - - this.ideaBoard = ideaBoard; - - this.setAlignmentX (Component.LEFT_ALIGNMENT); - this.setAlignmentY (Component.TOP_ALIGNMENT); - - final TypeBox _this = this; - - List buttons = new ArrayList (); - final JButton add = UIUtils.createButton ("add", - Constants.ICON_MENU, - getUIString (ideaboard,ideatypes,view,headercontrols,items,newidea,tooltip), - //"Click to add a new " + this.getIdeaTypeName () + " Idea", - null); - buttons.add (add); - - add.setVisible (false); - add.addMouseListener (new MouseEventHandler () - { - - @Override - public void mouseEntered (MouseEvent ev) - { - - add.setVisible (true); - - } - - @Override - public void mouseExited (MouseEvent ev) - { - - add.setVisible (false); - - } - - @Override - public void handlePress (MouseEvent ev) - { - - _this.showAdd (); - - } - - }); - - JComponent bb = UIUtils.createButtonBar (buttons); - bb.setBorder (null); - this.getHeader ().setControls (bb); - this.getHeader ().setPadding (new java.awt.Insets (4, 5, 4, 3)); - - this.ideaBox = new Box (BoxLayout.Y_AXIS); - - UIUtils.setAsButton (this.getHeader ()); - this.getHeader ().addMouseListener (new MouseEventHandler () - { - - @Override - public void mouseEntered (MouseEvent ev) - { - - add.setVisible (true); - - } - - @Override - public void mouseExited (MouseEvent ev) - { - - add.setVisible (false); - - } - - @Override - public void fillPopup (JPopupMenu p, - MouseEvent ev) - { - - JMenuItem mi = new JMenuItem (getUIString (ideaboard,ideatypes,view,popupmenu,items,newidea), - //"Add new Idea", - Environment.getIcon ("add", - Constants.ICON_MENU)); - mi.addActionListener (new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.showAdd (); - - } - - }); - - p.add (mi); - - JMenu sortMenu = new JMenu (getUIString (ideaboard,ideatypes,view,popupmenu,items,sort)); - //"Sort Ideas by"); - - p.add (sortMenu); - - ButtonGroup group = new ButtonGroup (); - - sortMenu.setIcon (Environment.getIcon (Constants.SORT_ICON_NAME, - Constants.ICON_MENU)); - - mi = new JRadioButtonMenuItem (getUIString (ideaboard,ideatypes,view,sortrating), - //"Rating", - Environment.getIcon (Constants.STAR_ICON_NAME, - Constants.ICON_MENU)); - - if (_this.ideaType.getSortBy ().equals (IdeaType.SORT_BY_RATING)) - { - - mi.setSelected (true); - - } - - group.add (mi); - - mi.addActionListener (new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.sortIdeas (IdeaType.SORT_BY_RATING); - - _this.ideaBoard.getViewer ().fireProjectEvent (Idea.OBJECT_TYPE, - ProjectEvent.SORT, - IdeaType.SORT_BY_RATING); - - } - - }); - - sortMenu.add (mi); - - mi = new JRadioButtonMenuItem (getUIString (ideaboard,ideatypes,view,sortdate), - //"Date Added", - Environment.getIcon (Constants.DATE_ICON_NAME, - Constants.ICON_MENU)); - - mi.addActionListener (new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.sortIdeas (IdeaType.SORT_BY_DATE); - - _this.ideaBoard.getViewer ().fireProjectEvent (Idea.OBJECT_TYPE, - ProjectEvent.SORT, - IdeaType.SORT_BY_DATE); - - } - - }); - - if (_this.ideaType.getSortBy ().equals (IdeaType.SORT_BY_DATE)) - { - - mi.setSelected (true); - - } - - sortMenu.add (mi); - - group.add (mi); - - mi = new JRadioButtonMenuItem (getUIString (ideaboard,ideatypes,view,sortalpha), - //"Alphabetical", - Environment.getIcon (Constants.SPELLCHECKER_ICON_NAME, - Constants.ICON_MENU)); - - mi.addActionListener (new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.sortIdeas (IdeaType.SORT_BY_TEXT); - - _this.ideaBoard.getViewer ().fireProjectEvent (Idea.OBJECT_TYPE, - ProjectEvent.SORT, - IdeaType.SORT_BY_TEXT); - - } - - }); - - if (_this.ideaType.getSortBy ().equals (IdeaType.SORT_BY_TEXT)) - { - - mi.setSelected (true); - - } - - sortMenu.add (mi); - - group.add (mi); - - String t = show; - - if (_this.ideaBox.isVisible ()) - { - - t = hide; - - } - - mi = new JMenuItem (getUIString (ideaboard,ideatypes,view,popupmenu,items,t)); - - mi.addActionListener (new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.showIdeas (!_this.ideaBox.isVisible ()); - - } - - }); - - p.add (mi); - - mi = new JMenuItem (getUIString (ideaboard,ideatypes,view,popupmenu,items,edit), - //"Edit the name of this type", - Environment.getIcon (Constants.EDIT_ICON_NAME, - Constants.ICON_MENU)); - - p.add (mi); - - mi.addActionListener (new EditIdeaTypeActionHandler (_this.ideaType, - _this.ideaBoard)); - - mi = new JMenuItem (getUIString (ideaboard,ideatypes,view,popupmenu,items,delete), - //"Delete this type of Idea", - Environment.getIcon (Constants.DELETE_ICON_NAME, - Constants.ICON_MENU)); - - p.add (mi); - - if (_this.ideaType.getIdeaCount () == 0) - { - - - mi.addActionListener (new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - // Just delete. - _this.ideaBoard.deleteIdeaType (_this.ideaType); - - } - - }); - - } else - { - - mi.addActionListener (new DeleteIdeaTypeActionHandler (_this.ideaType, - _this.ideaBoard)); - - } - - } - - @Override - public void handlePress (MouseEvent ev) - { - - _this.showIdeas (!_this.ideaBox.isVisible ()); - - } - - }); - - this.getHeader ().setToolTipText (getUIString (ideaboard,ideatypes,view, LanguageStrings.header,tooltip)); - //"Click to show/hide the Ideas"); - - Box content = new Box (BoxLayout.Y_AXIS); - content.setMinimumSize (new Dimension (300, - 50)); - content.setBackground (Color.WHITE); - content.setOpaque (true); - - this.ideaBox.setMinimumSize (new Dimension (300, - 50)); - - //this.ideaBox.setBackground (Color.WHITE); - this.ideaBox.setOpaque (false);//true); - this.setContent (content);//this.ideaBox); - - this.helpText = UIUtils.createHelpTextPane (getUIString (ideaboard,ideatypes,view,noideas), - //"You currently have no " + this.getIdeaTypeName () + " ideas recorded. To add a new Idea perform one of the actions below:
    • Use the plus button on the header.
    • Click anywhere in this box.
    • Right click on the header and select Add new Idea.
    ", - IdeaBoard.this.projectViewer); - - this.helpText.addMouseListener (new MouseAdapter () - { - - public void mouseClicked (MouseEvent ev) - { - - _this.showAdd (); - - } - }); - - content.add (this.helpText); - - //this.ideaBox.add (this.helpText); - - // Create the add box. - this.addBox = new AddEditBox (null, - this, - null); - - this.ideaBox.add (this.addBox); - - content.add (this.ideaBox); - - this.addIdeasToBox (); - - // Sort the boxes, done this way to prevent having to recreate the boxes. - - if (this.ideaType.getIdeaCount () == 0) - { - - this.showIdeas (false); - - } - - this.setBorder (new CompoundBorder (com.quollwriter.ui.components.UIUtils.internalPanelDropShadow, - new MatteBorder (1, 1, 1, 1, UIUtils.getBorderColor ()))); - - this.showHelpText (false); - - this.setBoxTitle (); - - } - - public void updateTitle () - { - - this.setBoxTitle (); - - } - - public IdeaBoard getIdeaBoard () - { - - return this.ideaBoard; - - } - - public void sortIdeas (String sortBy) - { - - this.ideaType.setSortBy (sortBy); - - try - { - - this.ideaBoard.projectViewer.saveObject (this.ideaType, - false); - - } catch (Exception e) - { - - Environment.logError ("Unable to update idea type: " + - this.ideaType + - ", cannot set sort type: " + - sortBy, - e); - - } - - this.addIdeasToBox (); - - } - - private void addIdeasToBox () - { - - int n = this.ideaBox.getComponentCount (); - - // Remove any component starting at 2. - for (int i = n - 1; i > 0; i--) - { - - this.ideaBox.remove (i); - - } - - List ideas = this.ideaType.getIdeas (); - - for (int i = ideas.size () - 1; i > -1; i--) - { - - Idea idea = ideas.get (i); - - this.addIdea (idea, - false); - - } - - this._repaint (); - - } - - private String getIdeaTypeName () - { - - return this.ideaType.getName (); - - } - - public boolean areIdeasVisible () - { - - return this.ideaBox.isVisible (); - - } - - public void showIdeas (boolean vis) - { - - this.showHelpText ((vis && (this.ideaType.getIdeaCount () == 0))); - - this.ideaBox.setVisible (vis); - - this.setBoxTitle (); - - } - - private void setBoxTitle () - { - - String suff = " (" + this.ideaType.getIdeaCount () + ")"; - - this.getHeader ().setTitle (this.getIdeaTypeName () + suff); - - } - - public Component.BaselineResizeBehavior getBaselineResizeBehavior () - { - return Component.BaselineResizeBehavior.CONSTANT_ASCENT; - } - - @Override public int getBaseline (int width, - int height) - { - return 0; - } - - public void hideAdd () - { - - // Only show help if there are no ideas. - this.showHelpText (this.ideaType.getIdeas ().size () == 0); - - this.addBox.setVisible (false); - - this._repaint (); - - } - - private void _repaint () - { - - if (this.getParent () != null) - { - - this.getParent ().validate (); - this.getParent ().repaint (); - - } - - } - - public void showAdd () - { - - this.showHelpText (false); - - this.ideaBox.setVisible (true); - - this.addBox.setVisible (true); - - this.setBoxTitle (); - - this._repaint (); - - } - - public void showHelpText (boolean v) - { - - this.helpText.setVisible (v);//this.ideaType.getIdeaCount () == 0); - - this._repaint (); - - } - - public void createIdea (StringWithMarkup text) - { - - if (!text.hasText ()) - { - - return; - - } - - text.update (text); - - Idea i = new Idea (); - i.setDescription (text); - i.setType (this.ideaType); - - // Ask the project viewer to save the new object. - try - { - - this.ideaBoard.projectViewer.addNewIdea (i); - - } catch (Exception e) - { - - Environment.logError ("Unable to save new idea: " + - i, - e); - - UIUtils.showErrorMessage (this, - getUIString (ideaboard,ideas,_new,actionerror)); - //"Unable to save new Idea."); - - return; - - } - - // Add the new idea to the list. - this.addIdea (i, - true); - - this.hideAdd (); - - this.showHelpText (false); - - } - - private void removeIdea (Idea i) - { - - int c = this.ideaBox.getComponentCount (); - - for (int x = 0; x < c; x++) - { - - Component cc = (Component) this.ideaBox.getComponent (x); - - if (cc instanceof IdeaBox) - { - - IdeaBox ib = (IdeaBox) cc; - - if (ib.getIdea () == i) - { - - this.ideaBox.remove (ib); - - this.ideaType.removeIdea (i); - - this.setBoxTitle (); - - this._repaint (); - - break; - - } - - } - - } - - } - - private void addIdea (Idea i, - boolean showToolBar) - { - - this.ideaBox.add (new IdeaBox (i, - this, - showToolBar), - 1); - - this.setBoxTitle (); - - } - - } - - private BackgroundImagePanel categories = null; - private Header header = null; - private JSplitPane splitPane = null; - private JScrollPane itemsScroll = null; - protected ProjectViewer projectViewer = null; - //private Paint background = null; - //private JComponent help = null; - private Object backgroundObject = null; - private QPopup backgroundSelectorPopup = null; - - private Map ideaTypes = new HashMap (); - - public IdeaBoard (ProjectViewer pv) - { - - super (pv, - pv.getProject ()); - - // Get the idea types. - this.projectViewer = pv; - - this.setBackground (UIUtils.getComponentColor ()); - this.setOpaque (true); - - } - - public String getPanelId () - { - - return PANEL_ID; - - } - - public void init () - throws GeneralException - { - - final IdeaBoard _this = this; - - // Add a panel with a flowlayout. - // FlowLayout layout = new FlowLayout (FlowLayout.CENTER, 10, 10); - - VerticalLayout layout = new VerticalLayout (7, - 7, - 300); - - // layout.setAlignOnBaseline (true); - //this.categories = new JPanel (layout) - - this.categories = new BackgroundImagePanel (layout); - this.categories.setToolTipText (getUIString (ideaboard,tooltip)); - //"Double click to add a new type of Idea. Right click to change the background."); - - //this.categories.setBackgroundObject (Environment.getProperty (Constants.DEFAULT_IDEA_BOARD_BG_IMAGE_PROPERTY_NAME)); - - this.categories.setBorder (new EmptyBorder (20, - 20, - 20, - 20)); - - this.categories.setBackground (null); - this.categories.setOpaque (false); - - final JScrollPane cscroll = new JScrollPane (this.categories); - - cscroll.setBorder (null); - - cscroll.setBorder (new EmptyBorder (1, 0, 0, 0)); - - cscroll.getVerticalScrollBar ().addAdjustmentListener (new AdjustmentListener () - { - - public void adjustmentValueChanged (AdjustmentEvent ev) - { - - if (cscroll.getVerticalScrollBar ().getValue () > 0) - { - - cscroll.setBorder (new MatteBorder (1, 0, 0, 0, - UIUtils.getInnerBorderColor ())); - - } else { - - cscroll.setBorder (new EmptyBorder (1, 0, 0, 0)); - - } - - } - - }); - - cscroll.setHorizontalScrollBarPolicy (ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); - cscroll.getVerticalScrollBar ().setUnitIncrement (20); - cscroll.setOpaque (false); - cscroll.setBackground (null); - - this.categories.addMouseListener (new MouseEventHandler () - { - - @Override - public void handleDoublePress (MouseEvent ev) - { - - new NewIdeaTypeActionHandler (_this).actionPerformed (new ActionEvent (_this, 0, "show")); - - } - - @Override - public void fillPopup (JPopupMenu p, - MouseEvent ev) - { - - JMenuItem add = new JMenuItem (getUIString (ideaboard,popupmenu,items,_new), - //"Add a new type of Idea", - Environment.getIcon ("add", - Constants.ICON_MENU)); - add.addActionListener (new NewIdeaTypeActionHandler (_this)); - - p.add (add); - - p.add (_this.getSelectBackgroundButton (true)); - - } - - }); - - java.util.List buts = new ArrayList (); - - buts.add (UIUtils.createButton ("add", - Constants.ICON_PANEL_ACTION, - getUIString (ideaboard,headercontrols,items,_new,tooltip), - //"Click to add a new type of Idea", - new NewIdeaTypeActionHandler (this))); - - buts.add (UIUtils.createHelpPageButton ("idea-board/overview", - Constants.ICON_PANEL_ACTION, - null)); - - this.header = UIUtils.createHeader (getUIString (ideaboard,title), - //"Idea Board", - Constants.PANEL_TITLE, - Constants.IDEA_ICON_NAME, - UIUtils.createButtonBar (buts)); - - this.add (this.header); - - // Get all the current idea types. - List its = this.projectViewer.getProject ().getIdeaTypes (); - - if (its.size () == 0) - { - - this.projectViewer.setIgnoreProjectEvents (true); - - // Add the default types, they are inserted in reverse since - // we insert at the top of the container rather than adding to the bottom. - this.addNewType (getUIString (objectnames,plural, Scene.OBJECT_TYPE), - //"{Scenes}"), - "scene", - false); - - this.addNewType (getUIString (ideaboard,ideatypes,defaulttypes,dialogue), - //"Dialogue", - "dialogue", - false); - - this.addNewType (getUIString (ideaboard,ideatypes,defaulttypes,other), - //"Other", - null, - false); - - for (UserConfigurableObjectType type : Environment.getAssetUserConfigurableObjectTypes (true)) - { - - this.addNewType (Environment.getObjectTypeNamePlural (type), - //type.getObjectTypeNamePlural (), - type.getObjectTypeId (), //getIcon16x16 (), - false); - - } - - this.addNewType (getUIString (objectnames,plural, Chapter.OBJECT_TYPE), - //"{Chapters}"), - "chapter", - false); - -/* - this.addNewType (Environment.replaceObjectNames ("{Locations}"), - "location", - false); - - this.addNewType (Environment.replaceObjectNames ("{Items}"), - "object", - false); - - this.addNewType (Environment.replaceObjectNames ("{Characters}"), - "character", - false); - - this.addNewType (Environment.replaceObjectNames ("{Chapters}"), - "chapter", - false); -*/ - this.projectViewer.setIgnoreProjectEvents (false); - - } else - { - - its = new ArrayList (its); - - Collections.reverse (its); - - for (IdeaType it : its) - { - - this.addType (it); - - } - - } - - this.add (cscroll); - - } - - public boolean hasTypeWithName (String n) - { - - Iterator iter = ideaTypes.keySet ().iterator (); - - while (iter.hasNext ()) - { - - IdeaType it = iter.next (); - - if (it.getName ().equalsIgnoreCase (n)) - { - - return true; - - } - - } - - return false; - - } - - private AbstractButton getSelectBackgroundButton (boolean showText) - { - - final IdeaBoard _this = this; - - AbstractButton mi = null; - - if (showText) - { - - mi = new JMenuItem (getUIString (ideaboard,popupmenu,items,selectbackground)); - //"Select a background image/color"); - - } else - { - - mi = new JButton (); - UIUtils.setAsButton (mi); - mi.setOpaque (false); - mi.setToolTipText (getUIString (ideaboard,toolbar,buttons,selectbackground,tooltip)); - //"Click to show/hide the background image/color selector"); - - } - - mi.setIcon (Environment.getIcon ("bg-select", - (showText ? Constants.ICON_MENU : Constants.ICON_TOOLBAR))); - - mi.addActionListener (new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.showBackgroundSelector (); - - } - - }); - - return mi; - - } - - public void showBackgroundSelector () - { - - final IdeaBoard _this = this; - - if (this.backgroundSelectorPopup == null) - { - - this.backgroundSelectorPopup = BackgroundSelector.getBackgroundSelectorPopup (new ChangeAdapter () - { - - public void stateChanged (ChangeEvent ev) - { - - BackgroundChangeEvent bce = (BackgroundChangeEvent) ev; - - if (!bce.getValue ().equals (_this.categories.getBackgroundObject ())) - { - - _this.projectViewer.fireProjectEvent (ProjectEvent.IDEA_BOARD, - ProjectEvent.CHANGE_BACKGROUND); - - } - - _this.setBoardBackground (bce.getValue ()); - - } - - }, - new Dimension (75, - 75), - this.backgroundObject); - - this.backgroundSelectorPopup.setDraggable (this); - - this.projectViewer.addPopup (this.backgroundSelectorPopup, - true, - false); - - } else - { - - if (this.backgroundSelectorPopup.isVisible ()) - { - - this.backgroundSelectorPopup.setVisible (false); - - return; - - } - - } - - this.projectViewer.showPopupAt (this.backgroundSelectorPopup, - new Point (100, - 100), - true); - - ((BackgroundSelector) this.backgroundSelectorPopup.getContent ()).setSelected (this.backgroundObject); - - } - - public void setBoardOpacity (float v) - { - - this.categories.setBackgroundOpacity (v); - - } - - public void setBoardBackground (Object o) - { - - this.categories.setBackgroundObject (o); - - } - - public void addNewType (String name, - String iconType, - boolean showAdd) - throws GeneralException - { - - IdeaType it = new IdeaType (); - it.setName (name); - it.setIconType (iconType); - - this.projectViewer.getProject ().addIdeaType (it); - - this.projectViewer.addNewIdeaType (it); - - TypeBox cb = this.addType (it); - - if (showAdd) - { - - cb.showAdd (); - - } - - } - - public void updateIdeaType (IdeaType type) - { - - this.projectViewer.updateIdeaType (type); - - TypeBox tb = this.ideaTypes.get (type); - - tb.updateTitle (); - - } - - public void deleteIdeaType (IdeaType type) - { - - if (this.projectViewer.deleteIdeaType (type)) - { - - TypeBox ic = this.ideaTypes.get (type); - - this.categories.remove (ic); - - this.ideaTypes.remove (type); - - this.repaint (); - - } - - } - - private TypeBox addType (IdeaType type) - { - - TypeBox ic = new TypeBox (type, - this); - - this.ideaTypes.put (type, - ic); - - this.categories.add (ic, - 0); - - return ic; - - } - - public void fillPopupMenu (final MouseEvent ev, - final JPopupMenu popup) - { - - } - - public boolean saveUnsavedChanges () - throws Exception - { - - this.saveObject (); - - return true; - - } - - @Override - public void close () - { - - } - - public void getState (Map m) - { - - String bg = this.categories.getBackgroundObjectAsString (); - - // Legacy < v2 - m.remove ("backgroundImage"); - - m.put ("background", - bg); - - m.put ("opacity", - String.valueOf (this.categories.getBackgroundOpacity ())); - - // Get all the type boxes that are "open". - StringBuilder sb = new StringBuilder (); - - Iterator iter = ideaTypes.entrySet ().iterator (); - - while (iter.hasNext ()) - { - - Map.Entry en = (Map.Entry) iter.next (); - - IdeaType it = (IdeaType) en.getKey (); - TypeBox b = (TypeBox) en.getValue (); - - if (b.areIdeasVisible ()) - { - - if (sb.length () > 0) - { - - sb.append (","); - - } - - sb.append (it.getKey ()); - - } - - } - - if (sb.length () > 0) - { - - m.put ("openTypes", - sb.toString ()); - - } - - } - - public void setState (final Map s, - boolean hasFocus) - { - - String bg = s.get ("background"); - - // Legacy < v2 - if (bg == null) - { - - bg = s.get ("backgroundImage"); - - if (bg != null) - { - - bg = "bg:" + bg; - - } - - } - - if (bg == null) - { - - bg = "bg:" + Environment.getProperty (Constants.DEFAULT_IDEA_BOARD_BG_IMAGE_PROPERTY_NAME); - - } - - try - { - - this.setBoardBackground (bg); - - } catch (Exception e) { - - Environment.logError ("Unable to set board background to: " + - bg, - e); - - this.setBoardBackground ("bg:" + Environment.getProperty (Constants.DEFAULT_IDEA_BOARD_BG_IMAGE_PROPERTY_NAME)); - - } - - String op = s.get ("opacity"); - - float opv = 0.7f; - - try - { - - opv = Float.parseFloat (op); - - } catch (Exception e) { - - // Ignore. - - } - - this.setBoardOpacity (opv); - - // Open the types. - String openTypes = s.get ("openTypes"); - - if (openTypes != null) - { - - Map m = new HashMap (); - - Iterator iter = this.ideaTypes.entrySet ().iterator (); - - while (iter.hasNext ()) - { - - Map.Entry en = (Map.Entry) iter.next (); - - IdeaType it = (IdeaType) en.getKey (); - TypeBox b = (TypeBox) en.getValue (); - - m.put (it.getKey (), - b); - - } - - StringTokenizer t = new StringTokenizer (openTypes, - ","); - - while (t.hasMoreTokens ()) - { - - try - { - - long k = Long.parseLong (t.nextToken ().trim ()); - - TypeBox b = m.get (k); - - if (b != null) - { - - b.showIdeas (true); - - } - - } catch (Exception e) - { - - // Ignore. - - } - - } - - } - - this.validate (); - this.repaint (); - - this.setReadyForUse (true); - - } - - public void fillToolBar (JToolBar acts, - boolean fullScreen) - { - - JButton add = new JButton (Environment.getIcon ("add", - Constants.ICON_TOOLBAR)); - add.setToolTipText (getUIString (ideaboard,toolbar,buttons,_new,tooltip)); - //"Click to add a new type of Idea"); - add.setOpaque (false); - UIUtils.setAsButton (add); - add.addActionListener (new NewIdeaTypeActionHandler (this)); - acts.add (add); - - acts.add (this.getSelectBackgroundButton (false)); - - //acts.add (this.getSelectOpacityButton (false)); - - JButton helpBut = UIUtils.createHelpPageButton ("idea-board/overview", - Constants.ICON_TOOLBAR, - null); - - acts.add (helpBut); - - } - - @Override - public String getTitle () - { - - return getUIString (ideaboard,title); - //"Idea Board"; - - } - - @Override - public ImageIcon getIcon (int type) - { - - return Environment.getIcon ("idea", - type); - - } - - public List getTopLevelComponents () - { - - return new ArrayList (); - - } - - @Override - public void refresh () - { - - - } - -} diff --git a/src/com/quollwriter/ui/panels/QuollEditorPanel.java b/src/com/quollwriter/ui/panels/QuollEditorPanel.java deleted file mode 100644 index a97380ba..00000000 --- a/src/com/quollwriter/ui/panels/QuollEditorPanel.java +++ /dev/null @@ -1,2208 +0,0 @@ -package com.quollwriter.ui.panels; - -import java.awt.*; -import java.awt.im.*; -import java.awt.event.*; - -import java.io.*; - -import java.text.*; - -import java.util.ArrayList; -import java.util.List; - -import javax.swing.*; -import javax.swing.border.*; -import javax.swing.event.*; -import javax.swing.text.*; -import javax.swing.undo.*; -import java.awt.datatransfer.*; - -import com.gentlyweb.properties.*; - -import com.jgoodies.forms.builder.*; -import com.jgoodies.forms.factories.*; -import com.jgoodies.forms.layout.*; - -import com.quollwriter.*; -import com.quollwriter.events.*; -import com.quollwriter.ui.*; -import com.quollwriter.data.*; - -import com.quollwriter.text.*; -import com.quollwriter.text.rules.*; - -import com.quollwriter.ui.actionHandlers.*; -import com.quollwriter.ui.components.ActionAdapter; -import com.quollwriter.ui.components.Header; -import com.quollwriter.ui.components.ImagePanel; -import com.quollwriter.ui.components.QTextEditor; -import com.quollwriter.ui.components.ScrollablePanel; -import com.quollwriter.ui.components.BlockPainter; -import com.quollwriter.ui.renderers.*; - -import com.swabunga.spell.engine.*; -import com.swabunga.spell.event.*; - -public class QuollEditorPanel extends AbstractEditableEditorPanel implements ChapterItemViewer, ProjectEventListener -{ - - public static final String SHOW_WORD_CLOUD_ACTION_NAME = "show-word-cloud"; - public static final String CHAPTER_INFO_ACTION_NAME = "chapter-info"; - public static final String PROBLEM_FINDER_ACTION_NAME = "problem-finder"; - public static final String SPLIT_CHAPTER_ACTION_NAME = "split-chapter"; - public static final String SET_EDIT_COMPLETE_ACTION_NAME = "set-edit-complete"; - public static final String REMOVE_EDIT_POINT_ACTION_NAME = "remove-edit-point"; - - public static final String NEW_CHAPTER_ACTION_NAME = "new" + Chapter.OBJECT_TYPE; - public static final String NEW_SCENE_ACTION_NAME = "new" + Scene.OBJECT_TYPE; - public static final String NEW_OUTLINE_ITEM_ACTION_NAME = "new" + OutlineItem.OBJECT_TYPE; - public static final String NEW_NOTE_ACTION_NAME = "new" + Note.OBJECT_TYPE; - public static final String NEW_EDIT_NEEDED_NOTE_ACTION_NAME = "new-edit-needed-" + Note.OBJECT_TYPE; - - public static final String TAB = String.valueOf ('\t'); - - public static final String SECTION_BREAK_FIND = "***"; - public static final String SECTION_BREAK = "*" + TAB + TAB + "*" + TAB + TAB + "*"; - - private static final CutNPasteTransferHandler cnpTransferHandler = new CutNPasteTransferHandler (); - - private IconColumn iconColumn = null; - protected ProjectViewer projectViewer = null; - private Box problemFinderPanel = null; - private ProblemFinder problemFinder = null; - private JLabel ignoredProblemsLabel = null; - private int lastCaret = -1; - private ChapterItemTransferHandler chItemTransferHandler = null; - private BlockPainter highlight = null; - - public QuollEditorPanel(ProjectViewer pv, - Chapter c) - throws GeneralException - { - - super (pv, - c); - - this.projectViewer = pv; - - this.viewer.addProjectEventListener (this); - - final QuollEditorPanel _this = this; - - DefaultIconProvider iconProv = new DefaultIconProvider () - { - - @Override - public ImageIcon getIcon (DataObject d, - int type) - { - - if (d instanceof Note) - { - - Note n = (Note) d; - - if (n.isEditNeeded ()) - { - - return super.getIcon (Constants.EDIT_NEEDED_NOTE_ICON_NAME, - type); - - } - - } - - return super.getIcon (d, - type); - - } - - - }; - - this.highlight = new BlockPainter (Environment.getHighlightColor ()); - - this.iconColumn = new IconColumn (this, - c, - this.projectViewer.getIconProvider (), - this.projectViewer.getChapterItemViewPopupProvider ()); - - //this.iconColumn.addMouseListener (this); - - this.iconColumn.addMouseListener (new MouseEventHandler () - { - - public void handleDoublePress (MouseEvent ev) - { - - java.util.List prefix = new ArrayList<> (); - prefix.add (LanguageStrings.iconcolumn); - prefix.add (LanguageStrings.doubleclickmenu); - prefix.add (LanguageStrings.items); - - JPopupMenu popup = new JPopupMenu (); - - // Convert the mouse position to a point in the text. - - String pref = Environment.getUIString (LanguageStrings.general,LanguageStrings.shortcutprefix); - - JMenuItem mi = null; - - mi = UIUtils.createMenuItem (Environment.getUIString (prefix, - Scene.OBJECT_TYPE), - Scene.OBJECT_TYPE, - _this.getActionListenerForTextPosition (NEW_SCENE_ACTION_NAME, - ev.getPoint ()), - null, - null); - - popup.add (mi); - - // TODO: Abstract this. - mi.setMnemonic (Character.toUpperCase (Environment.getObjectTypeName (Scene.OBJECT_TYPE).charAt (0))); - mi.setToolTipText (pref + "S"); - - mi = UIUtils.createMenuItem (Environment.getUIString (prefix, - OutlineItem.OBJECT_TYPE), - OutlineItem.OBJECT_TYPE, - _this.getActionListenerForTextPosition (NEW_OUTLINE_ITEM_ACTION_NAME, - ev.getPoint ()), - null, - null); - - popup.add (mi); - - mi.setMnemonic (Character.toUpperCase (Environment.getObjectTypeName (OutlineItem.OBJECT_TYPE).charAt (0))); - mi.setToolTipText (pref + "O"); - - mi = UIUtils.createMenuItem (Environment.getUIString (prefix, - Note.OBJECT_TYPE), - Note.OBJECT_TYPE, - _this.getActionListenerForTextPosition (NEW_NOTE_ACTION_NAME, - ev.getPoint ()), - null, - null); - - popup.add (mi); - - mi.setMnemonic (Character.toUpperCase (Environment.getObjectTypeName (Note.OBJECT_TYPE).charAt (0))); - mi.setToolTipText (pref + "N"); - - mi = UIUtils.createMenuItem (Environment.getUIString (prefix, - Note.EDIT_NEEDED_OBJECT_TYPE), - Constants.EDIT_NEEDED_NOTE_ICON_NAME, - _this.getActionListenerForTextPosition (NEW_EDIT_NEEDED_NOTE_ACTION_NAME, - ev.getPoint ()), - null, - null); - - popup.add (mi); - - mi.setMnemonic ('E'); - mi.setToolTipText (pref + "E"); - - popup.show ((Component) ev.getSource (), - ev.getPoint ().x, - ev.getPoint ().y); - - } - - }); - - final java.util.List prefix = new ArrayList<> (); - prefix.add (LanguageStrings.project); - prefix.add (LanguageStrings.editorpanel); - prefix.add (LanguageStrings.actions); - - this.chItemTransferHandler = new ChapterItemTransferHandler (this.getIconColumn ()); - - this.setTransferHandler (this.chItemTransferHandler); - - this.actions.put (SPLIT_CHAPTER_ACTION_NAME, - new ActionAdapter () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - new SplitChapterActionHandler (_this.obj, - _this.projectViewer).actionPerformed (ev); - - } - - }); - - this.actions.put (REMOVE_EDIT_POINT_ACTION_NAME, - new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.projectViewer.removeChapterEditPosition (_this.obj); - - } - - }); - - this.actions.put (SET_EDIT_COMPLETE_ACTION_NAME, - new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.projectViewer.setChapterEditComplete (_this.obj, - true); - - } - - }); - - this.actions.put (NEW_CHAPTER_ACTION_NAME, - new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.performAction (ev, - NEW_CHAPTER_ACTION_NAME, - -1); - - } - - }); - - this.actions.put (NEW_SCENE_ACTION_NAME, - new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.performAction (ev, - NEW_SCENE_ACTION_NAME, - -1); - - } - - }); - - this.actions.put (NEW_OUTLINE_ITEM_ACTION_NAME, - new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.performAction (ev, - NEW_OUTLINE_ITEM_ACTION_NAME, - -1); - - } - - }); - - this.actions.put (NEW_NOTE_ACTION_NAME, - new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.performAction (ev, - NEW_NOTE_ACTION_NAME, - -1); - - } - - }); - - this.actions.put (NEW_EDIT_NEEDED_NOTE_ACTION_NAME, - new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.performAction (ev, - NEW_EDIT_NEEDED_NOTE_ACTION_NAME, - -1); - - } - - }); - - this.actions.put (CHAPTER_INFO_ACTION_NAME, - new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - try - { - - _this.projectViewer.viewChapterInformation (_this.obj); - - } catch (Exception e) - { - - Environment.logError ("Unable to show chapter information for: " + - _this.obj, - e); - - UIUtils.showErrorMessage (_this, - Environment.getUIString (LanguageStrings.project, - LanguageStrings.actions, - LanguageStrings.showchapterinfo, - LanguageStrings.actionerror)); - //Environment.replaceObjectNames ("Unable to show {chapter}.")); - - } - - } - - }); - - this.actions.put (SHOW_WORD_CLOUD_ACTION_NAME, - new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - try - { - - _this.projectViewer.viewWordCloud (); - - } catch (Exception e) - { - - Environment.logError ("Unable to show word cloud", - e); - - UIUtils.showErrorMessage (_this, - Environment.replaceObjectNames ("Unable to show word cloud.")); - - } - - } - - }); - - this.actions.put (PROBLEM_FINDER_ACTION_NAME, - new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.showProblemFinder (); - - } - - }); - - InputMap im = this.editor.getInputMap (JComponent.WHEN_IN_FOCUSED_WINDOW); - - // Remove ctrl+shift+O from the when_focused set since it conflicts. - this.editor.getInputMap (JComponent.WHEN_FOCUSED).put (KeyStroke.getKeyStroke ("ctrl shift O"), - "none"); - - im.put (KeyStroke.getKeyStroke ("ctrl shift S"), - NEW_SCENE_ACTION_NAME); - - im.put (KeyStroke.getKeyStroke ("ctrl shift O"), - NEW_OUTLINE_ITEM_ACTION_NAME); - im.put (KeyStroke.getKeyStroke ("ctrl shift N"), - NEW_NOTE_ACTION_NAME); - im.put (KeyStroke.getKeyStroke ("ctrl shift E"), - NEW_EDIT_NEEDED_NOTE_ACTION_NAME); - im.put (KeyStroke.getKeyStroke ("ctrl shift P"), - PROBLEM_FINDER_ACTION_NAME); - - this.editor.setTransferHandler (QuollEditorPanel.cnpTransferHandler); - - } - - public int getTextPositionForMousePosition (Point p) - { - - Point pp = p; - - if (this.iconColumn.getMousePosition () != null) - { - - pp = new Point (0, - p.y); - - } - - return this.editor.viewToModel (pp); - - } - - public ActionListener getActionListenerForTextPosition (final String actionName, - final Point p) - { - - final QuollEditorPanel _this = this; - - final int pos = this.getTextPositionForMousePosition (p); - - return new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.performAction (ev, - actionName, - pos); - - } - - }; - - } - - - public ChapterItemTransferHandler getChapterItemTransferHandler () - { - - return this.chItemTransferHandler; - - } - - public JComponent getEditorWrapper (QTextEditor q) - { - - q.setMaximumSize (new Dimension (Integer.MAX_VALUE, Integer.MAX_VALUE)); - - q.setMinimumSize (new Dimension (200, 200)); - q.setAlignmentY (Component.TOP_ALIGNMENT); - q.setAlignmentX (Component.LEFT_ALIGNMENT); - - this.iconColumn.setAlignmentY (Component.TOP_ALIGNMENT); - this.iconColumn.setAlignmentX (Component.LEFT_ALIGNMENT); - this.iconColumn.setMinimumSize (new Dimension (50, 200)); - this.iconColumn.setPreferredSize (new Dimension (50, 200)); - this.iconColumn.setMaximumSize (new Dimension (50, Integer.MAX_VALUE)); - - JPanel p = new ScrollablePanel (new BorderLayout ()); - p.setOpaque (false); - - p.add (this.iconColumn, - BorderLayout.WEST); - p.add (q, - BorderLayout.CENTER); - - return p; - - } - - public void showProblemFinderRuleConfig () - { - - this.projectViewer.showProblemFinderRuleConfig (); - - } - - @Override - public void fillToolBar (JToolBar acts, - final boolean fullScreen) - { - - java.util.List prefix = new ArrayList (); - prefix.add (LanguageStrings.project); - prefix.add (LanguageStrings.editorpanel); - prefix.add (LanguageStrings.toolbar); - - final QuollEditorPanel _this = this; - - acts.add (this.createToolbarButton (Constants.SAVE_ICON_NAME, - Environment.getUIString (prefix, - LanguageStrings.save, - LanguageStrings.tooltip), - //"Click to save the {Chapter} text", - SAVE_ACTION_NAME)); - - this.doFillToolBar (acts); - - acts.add (this.createToolbarButton (Constants.WORDCOUNT_ICON_NAME, - Environment.getUIString (prefix, - LanguageStrings.wordcount, - LanguageStrings.tooltip), - //"Click to view the word counts and readability indices", - TOGGLE_WORDCOUNTS_ACTION_NAME)); - - if (this.projectViewer.isSpellCheckingEnabled ()) - { - - acts.add (this.createToolbarButton ("spellchecker-turn-off", - Environment.getUIString (prefix, - LanguageStrings.spellcheckoff, - LanguageStrings.tooltip), - //"Click to turn the spell checker " + type, - TOGGLE_SPELLCHECK_ACTION_NAME)); - - } else { - - acts.add (this.createToolbarButton ("spellchecker-turn-on", - Environment.getUIString (prefix, - LanguageStrings.spellcheckon, - LanguageStrings.tooltip), - //"Click to turn the spell checker " + type, - TOGGLE_SPELLCHECK_ACTION_NAME)); - - } - - acts.add (this.createToolbarButton (Constants.DELETE_ICON_NAME, - Environment.getUIString (prefix, - LanguageStrings.delete, - LanguageStrings.tooltip), - //"Click to delete this {Chapter}", - DELETE_CHAPTER_ACTION_NAME)); - - // Add a tools menu. - final JButton b = UIUtils.createToolBarButton ("tools", - Environment.getUIString (prefix, - LanguageStrings.tools, - LanguageStrings.tooltip), - //"Click to view the tools such as Print, Find Problems and Edit the text properties", - "tools", - null); - - ActionAdapter ab = new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - java.util.List prefix = new ArrayList<> (); - prefix.add (LanguageStrings.project); - prefix.add (LanguageStrings.editorpanel); - prefix.add (LanguageStrings.tools); - - JPopupMenu m = new JPopupMenu (); -/* - _this.doFillToolsPopupMenu (ev, - m); -*/ - JMenuItem mi = null; - - // Need a more elegant way of handling this, maybe via cue.language? - if (_this.viewer.isLanguageEnglish ()) - { - - m.add (_this.createMenuItem (Environment.getUIString (prefix, - LanguageStrings.problemfinder, - LanguageStrings.text), - //"Find Problems", - Constants.PROBLEM_FINDER_ICON_NAME, - PROBLEM_FINDER_ACTION_NAME, - KeyStroke.getKeyStroke (KeyEvent.VK_P, - ActionEvent.CTRL_MASK | ActionEvent.SHIFT_MASK))); - - } - - m.add (_this.createMenuItem (Environment.getUIString (prefix, - LanguageStrings.textproperties, - LanguageStrings.text), - //"Edit Text Properties", - Constants.EDIT_PROPERTIES_ICON_NAME, - EDIT_TEXT_PROPERTIES_ACTION_NAME, - KeyStroke.getKeyStroke (KeyEvent.VK_E, - ActionEvent.CTRL_MASK))); - - m.add (_this.createMenuItem (Environment.getUIString (prefix, - LanguageStrings.find, - LanguageStrings.text), - //"Find", - Constants.FIND_ICON_NAME, - Constants.SHOW_FIND_ACTION, - KeyStroke.getKeyStroke (KeyEvent.VK_F, - ActionEvent.CTRL_MASK))); - - m.add (_this.createMenuItem (Environment.getUIString (prefix, - LanguageStrings.print, - LanguageStrings.text), - //"Print {Chapter}", - Constants.PRINT_ICON_NAME, - QTextEditor.PRINT_ACTION_NAME, - KeyStroke.getKeyStroke (KeyEvent.VK_P, - ActionEvent.CTRL_MASK))); - - m.show (b, - 10, - 10); - - } - - }; - - b.addActionListener (ab); - - acts.add (b); - - } - - private void doFillToolBar (JToolBar acts) - { - - final QuollEditorPanel _this = this; - - ActionAdapter aa = new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.performAction (ev); - - } - - }; - - java.util.List prefix = new ArrayList<> (); - prefix.add (LanguageStrings.project); - prefix.add (LanguageStrings.editorpanel); - prefix.add (LanguageStrings.toolbar); - - final JButton b = UIUtils.createToolBarButton (Constants.NEW_ICON_NAME, - Environment.getUIString (prefix, - LanguageStrings._new, - LanguageStrings.tooltip), - //"Click to add a new {Outlineitem}, {Character}, {Note}, {Object} etc.", - "new", - null); - - ActionAdapter ab = new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - JPopupMenu m = new JPopupMenu (); - - _this.addNewItemsForPopupMenu (m, - b, - -1, - false); - - Component c = (Component) ev.getSource (); - - m.show (c, - 10, - 10); - - } - - }; - - b.addActionListener (ab); - - acts.add (b); - acts.add (this.createToolbarButton (Constants.INFO_ICON_NAME, - Environment.getUIString (prefix, - LanguageStrings.showchapterinfo, - LanguageStrings.tooltip), - //"Click to view/edit the {chapter} information", - CHAPTER_INFO_ACTION_NAME)); - - } - - private void performAction (ActionEvent ev, - String c, - int pos) - { - - if (c == null) - { - - return; - - } - - if (c.equals (NEW_CHAPTER_ACTION_NAME)) - { - - Action a = this.projectViewer.getAction (ProjectViewer.NEW_CHAPTER_ACTION, - this.obj); - - if (a != null) - { - - a.actionPerformed (ev); - - } - - return; - - } - - if (c.equals (NEW_SCENE_ACTION_NAME)) - { - - Scene s = new Scene (-1, - this.obj); - - new ChapterItemActionHandler (s, - this, - AbstractFormPopup.ADD, - pos).actionPerformed (ev); - - return; - - } - - if (c.equals (NEW_OUTLINE_ITEM_ACTION_NAME)) - { - - OutlineItem o = new OutlineItem (-1, - this.obj); - - new ChapterItemActionHandler (o, - this, - AbstractFormPopup.ADD, - pos).actionPerformed (ev); - - return; - - } - - if (c.equals (NEW_NOTE_ACTION_NAME)) - { - - new NoteActionHandler (this.obj, - this, - pos).actionPerformed (ev); - - return; - - } - - if (c.equals (NEW_EDIT_NEEDED_NOTE_ACTION_NAME)) - { - - Note n = new Note (0, this.obj); - n.setType (Note.EDIT_NEEDED_NOTE_TYPE); - - new NoteActionHandler (this.obj, - this, - n, - pos).actionPerformed (ev); - - return; - - } - - } - - private void performAction (ActionEvent ev, - int pos) - { - - String c = ev.getActionCommand (); - - this.performAction (ev, - c, - pos); - - } - - private void addNewItemsForPopupMenu (final JComponent popup, - Component showAt, - int pos, - boolean compress) - { - - final QuollEditorPanel _this = this; - - final PositionActionAdapter aa = new PositionActionAdapter (pos) - { - - public void actionPerformed (ActionEvent ev) - { - - _this.performAction (ev, - this.pos); - - } - - }; - - java.util.List prefix = new ArrayList<> (); - prefix.add (LanguageStrings.project); - prefix.add (LanguageStrings.editorpanel); - prefix.add (LanguageStrings.popupmenu); - prefix.add (LanguageStrings._new); - prefix.add (LanguageStrings.items); - - if (compress) - { - - List buts = new ArrayList<> (); - - buts.add (this.createButton (Scene.OBJECT_TYPE, - Constants.ICON_MENU, - Environment.getUIString (prefix, - Scene.OBJECT_TYPE, - LanguageStrings.tooltip), - //String.format ("Add a new {%s}", Scene.OBJECT_TYPE), - NEW_SCENE_ACTION_NAME, - aa)); - - buts.add (this.createButton (OutlineItem.OBJECT_TYPE, - Constants.ICON_MENU, - Environment.getUIString (prefix, - OutlineItem.OBJECT_TYPE, - LanguageStrings.tooltip), - //String.format ("Add a new {%s}", OutlineItem.OBJECT_TYPE), - NEW_OUTLINE_ITEM_ACTION_NAME, - aa)); - - buts.add (this.createButton (Note.OBJECT_TYPE, - Constants.ICON_MENU, - Environment.getUIString (prefix, - Note.OBJECT_TYPE, - LanguageStrings.tooltip), - //String.format ("Add a new {%s}", Note.OBJECT_TYPE), - NEW_NOTE_ACTION_NAME, - aa)); - - buts.add (this.createButton ("edit-needed-note", - Constants.ICON_MENU, - Environment.getUIString (prefix, - Note.EDIT_NEEDED_OBJECT_TYPE, - LanguageStrings.tooltip), - //String.format ("Add a new Edit Needed Note"), - NEW_EDIT_NEEDED_NOTE_ACTION_NAME, - aa)); - - buts.add (this.createButton (Chapter.OBJECT_TYPE, - Constants.ICON_MENU, - Environment.getUIString (prefix, - Chapter.OBJECT_TYPE, - LanguageStrings.tooltip), - //String.format ("Add a new {%s}", Chapter.OBJECT_TYPE), - NEW_CHAPTER_ACTION_NAME, - aa)); - - if (popup instanceof JPopupMenu) - { - - JPopupMenu pm = (JPopupMenu) popup; - - pm.addSeparator (); - - popup.add (UIUtils.createPopupMenuButtonBar (Environment.getUIString (LanguageStrings.project, - LanguageStrings.editorpanel, - LanguageStrings.popupmenu, - LanguageStrings._new, - LanguageStrings.text), - //"New", - pm, - buts)); - - UIUtils.addNewAssetItemsAsToolbarToPopupMenu (pm, - null, - (ProjectViewer) this.projectViewer, - null, - null); - - pm.addSeparator (); - - } - - } else { - - String pref = Environment.getUIString (LanguageStrings.general,LanguageStrings.shortcutprefix); - - //"Shortcut: Ctrl+Shift+"; - - JMenuItem mi = null; - - mi = this.createMenuItem (Environment.getUIString (prefix, - Scene.OBJECT_TYPE, - LanguageStrings.text), -//Environment.getObjectTypeName (Scene.OBJECT_TYPE), - Scene.OBJECT_TYPE, - NEW_SCENE_ACTION_NAME, - null, - aa); - - popup.add (mi); - - mi.setMnemonic ('S'); - mi.setToolTipText (pref + "S"); - - mi = this.createMenuItem (Environment.getUIString (prefix, - OutlineItem.OBJECT_TYPE, - LanguageStrings.text), - //Environment.getObjectTypeName (OutlineItem.OBJECT_TYPE), - OutlineItem.OBJECT_TYPE, - NEW_OUTLINE_ITEM_ACTION_NAME, - null, - aa); - - popup.add (mi); - - mi.setMnemonic ('O'); - mi.setToolTipText (pref + "O"); - - mi = this.createMenuItem (Environment.getUIString (prefix, - Note.OBJECT_TYPE, - LanguageStrings.text), - //Environment.getObjectTypeName (Note.OBJECT_TYPE), - Note.OBJECT_TYPE, - NEW_NOTE_ACTION_NAME, - null, - aa); - - popup.add (mi); - - mi.setMnemonic ('N'); - mi.setToolTipText (pref + "N"); - - mi = this.createMenuItem (Environment.getUIString (prefix, - Note.EDIT_NEEDED_OBJECT_TYPE, - LanguageStrings.text), - //Note.EDIT_NEEDED_NOTE_TYPE + " " + Environment.getObjectTypeName (Note.OBJECT_TYPE), - Constants.EDIT_NEEDED_NOTE_ICON_NAME, - NEW_EDIT_NEEDED_NOTE_ACTION_NAME, - null, - aa); - - popup.add (mi); - - mi = this.createMenuItem (Environment.getUIString (prefix, - Chapter.OBJECT_TYPE, - LanguageStrings.text), - //Environment.getObjectTypeName (Chapter.OBJECT_TYPE), - Chapter.OBJECT_TYPE, - NEW_CHAPTER_ACTION_NAME, - null, - aa); - - popup.add (mi); - - mi.setMnemonic ('E'); - mi.setToolTipText (pref + "E"); - - UIUtils.addNewAssetItemsToPopupMenu (popup, - showAt, - this.projectViewer, - null, - null); - - } - - } - - public void showIconColumn (boolean v) - { - - this.iconColumn.setVisible (v); - - this.validate (); - this.repaint (); - - } - - public void setEditPosition (Point mouseP) - { - - try - { - - this.projectViewer.setChapterEditPosition (this.obj, - this.editor.viewToModel (mouseP)); - - } catch (Exception e) { - - Environment.logError ("Unable to set edit position for chapter: " + - this.obj, - e); - - UIUtils.showErrorMessage (this.projectViewer, - Environment.getUIString (LanguageStrings.project, - LanguageStrings.editorpanel, - LanguageStrings.actions, - LanguageStrings.seteditposition, - LanguageStrings.actionerror)); - //"Unable to set edit position."); - - } - - } - - public void doFillPopupMenu (final MouseEvent ev, - final JPopupMenu popup, - boolean compress) - { - - final QuollEditorPanel _this = this; - - // Get the mouse position, don't get it later since the mouse could have moved. - Point mP = this.editor.getMousePosition (); - - if (mP == null) - { - - mP = this.iconColumn.getMousePosition (); - - } - - final Point mouseP = mP; - - int pos = this.getTextPositionForMousePosition (ev.getPoint ()); - - // This is needed to move to the correct character, the call above seems to get the character - // before what was clicked on. - // pos++; - - java.util.List prefix = new ArrayList (); - prefix.add (LanguageStrings.project); - prefix.add (LanguageStrings.editorpanel); - prefix.add (LanguageStrings.popupmenu); - prefix.add (Chapter.OBJECT_TYPE); - prefix.add (LanguageStrings.items); - - JMenuItem mi = null; - - if (compress) - { - - List buts = new ArrayList (); - - buts.add (this.createButton (Constants.SAVE_ICON_NAME, - Constants.ICON_MENU, - Environment.getUIString (prefix, - LanguageStrings.save, - LanguageStrings.tooltip), - //"Save {Chapter}", - SAVE_ACTION_NAME)); - - if ((this.editor.getCaret ().getDot () > 0) - || - (this.editor.getSelectionStart () > 0) - ) - { - - if (this.editor.getCaret ().getDot () < this.editor.getTextWithMarkup ().getText ().length ()) - { - - buts.add (this.createButton (Constants.CHAPTER_SPLIT_ICON_NAME, - Constants.ICON_MENU, - Environment.getUIString (prefix, - LanguageStrings.splitchapter, - LanguageStrings.tooltip), - //"Split {Chapter}", - SPLIT_CHAPTER_ACTION_NAME)); - - } - - } - - buts.add (this.createButton (Constants.PROBLEM_FINDER_ICON_NAME, - Constants.ICON_MENU, - //"Find Problems", - Environment.getUIString (prefix, - LanguageStrings.problemfinder, - LanguageStrings.tooltip), - PROBLEM_FINDER_ACTION_NAME)); - - buts.add (this.createButton (Constants.EDIT_PROPERTIES_ICON_NAME, - Constants.ICON_MENU, - Environment.getUIString (prefix, - LanguageStrings.textproperties, - LanguageStrings.tooltip), - //"Edit Text Properties", - EDIT_TEXT_PROPERTIES_ACTION_NAME)); - - buts.add (this.createButton (Constants.FIND_ICON_NAME, - Constants.ICON_MENU, - Environment.getUIString (prefix, - LanguageStrings.find, - LanguageStrings.tooltip), - //"Find", - Constants.SHOW_FIND_ACTION)); - - popup.add (UIUtils.createPopupMenuButtonBar (Environment.getUIString (LanguageStrings.project, - LanguageStrings.editorpanel, - LanguageStrings.popupmenu, - Chapter.OBJECT_TYPE, - LanguageStrings.compresstext), - //Environment.replaceObjectNames ("{Chapter}"), - popup, - buts)); - - buts = new ArrayList (); - - buts.add (UIUtils.createButton (Constants.EDIT_IN_PROGRESS_ICON_NAME, - Constants.ICON_MENU, - Environment.getUIString (prefix, - LanguageStrings.seteditposition, - LanguageStrings.tooltip), - //"Set Edit Point", - new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.setEditPosition (mouseP); - - } - - })); - - if (this.obj.getEditPosition () > 0) - { - - buts.add (this.createButton (Constants.REMOVE_EDIT_POINT_ICON_NAME, - Constants.ICON_MENU, - Environment.getUIString (prefix, - LanguageStrings.removeeditposition, - LanguageStrings.tooltip), - //"Remove Edit Point", - REMOVE_EDIT_POINT_ACTION_NAME)); - - } - - if (!this.obj.isEditComplete ()) - { - - buts.add (this.createButton (Constants.EDIT_COMPLETE_ICON_NAME, - Constants.ICON_MENU, - Environment.getUIString (prefix, - LanguageStrings.seteditcomplete, - LanguageStrings.tooltip), - //"Set as Edit Complete", - SET_EDIT_COMPLETE_ACTION_NAME)); - - } - - popup.add (UIUtils.createPopupMenuButtonBar (null, - popup, - buts)); - - this.addNewItemsForPopupMenu (popup, - this, - pos, - compress); - - } else { - - // Save. - - mi = this.createMenuItem (Environment.getUIString (prefix, - LanguageStrings.save, - LanguageStrings.text), - //"Save {Chapter}", - Constants.SAVE_ICON_NAME, - SAVE_ACTION_NAME, - KeyStroke.getKeyStroke (KeyEvent.VK_S, - ActionEvent.CTRL_MASK)); - mi.setMnemonic (KeyEvent.VK_S); - - popup.add (mi); - - JMenu m = new JMenu (Environment.getUIString (LanguageStrings.project, - LanguageStrings.editorpanel, - LanguageStrings.popupmenu, - Chapter.OBJECT_TYPE, - LanguageStrings.text)); - //Environment.replaceObjectNames ("{Chapter} Edit")); - m.setIcon (Environment.getIcon (Constants.EDIT_ICON_NAME, - Constants.ICON_MENU)); - - popup.add (m); - - if ((this.editor.getCaret ().getDot () > 0) - || - (this.editor.getSelectionStart () > 0) - ) - { - - if (this.editor.getCaret ().getDot () < this.editor.getTextWithMarkup ().getText ().length ()) - { - - m.add (this.createMenuItem (Environment.getUIString (prefix, - LanguageStrings.splitchapter, - LanguageStrings.text), - //"Split {Chapter}", - Constants.CHAPTER_SPLIT_ICON_NAME, - SPLIT_CHAPTER_ACTION_NAME, - null)); - - } - - } - - mi = UIUtils.createMenuItem (Environment.getUIString (prefix, - LanguageStrings.seteditposition, - LanguageStrings.text), - //"Set Edit Point", - Constants.EDIT_IN_PROGRESS_ICON_NAME, - new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.setEditPosition (mouseP); - - } - - }); - - m.add (mi); - - if (this.obj.getEditPosition () > 0) - { - - m.add (this.createMenuItem (Environment.getUIString (prefix, - LanguageStrings.removeeditposition, - LanguageStrings.text), - //"Remove Edit Point", - Constants.REMOVE_EDIT_POINT_ICON_NAME, - REMOVE_EDIT_POINT_ACTION_NAME, - null)); - - } - - if (!this.obj.isEditComplete ()) - { - - m.add (this.createMenuItem (Environment.getUIString (prefix, - LanguageStrings.seteditcomplete, - LanguageStrings.text), - //"Set as Edit Complete", - Constants.EDIT_COMPLETE_ICON_NAME, - SET_EDIT_COMPLETE_ACTION_NAME, - null)); - - } - - popup.add (this.createMenuItem (Environment.getUIString (prefix, - LanguageStrings.problemfinder, - LanguageStrings.text), - //"Find Problems", - Constants.PROBLEM_FINDER_ICON_NAME, - PROBLEM_FINDER_ACTION_NAME, - null)); - - JMenu nm = new JMenu (Environment.getUIString (LanguageStrings.project, - LanguageStrings.editorpanel, - LanguageStrings.popupmenu, - LanguageStrings._new, - LanguageStrings.text)); - //"New"); - nm.setIcon (Environment.getIcon (Constants.NEW_ICON_NAME, - Constants.ICON_MENU)); - - popup.add (nm); - - this.addNewItemsForPopupMenu (nm, - this, - pos, - compress); - - popup.add (this.createMenuItem (Environment.getUIString (prefix, - LanguageStrings.textproperties, - LanguageStrings.text), - //"Edit Text Properties", - Constants.EDIT_PROPERTIES_ICON_NAME, - EDIT_TEXT_PROPERTIES_ACTION_NAME, - null)); - - mi = this.createMenuItem (Environment.getUIString (prefix, - LanguageStrings.find, - LanguageStrings.text), - //"Find", - Constants.FIND_ICON_NAME, - Constants.SHOW_FIND_ACTION, - KeyStroke.getKeyStroke (KeyEvent.VK_F, - ActionEvent.CTRL_MASK)); - mi.setMnemonic (KeyEvent.VK_F); - - popup.add (mi); - - } - - } - - public IconColumn getIconColumn () - { - - return this.iconColumn; - - } - - public QTextEditor getEditor () - { - - return this.editor; - - } - - public void removeItem (ChapterItem c) - { - - this.iconColumn.removeItem (c); - - } - - public void addItem (ChapterItem c) - throws GeneralException - { - - this.iconColumn.addItem (c); - - } - - public void scrollToItem (ChapterItem i) - throws GeneralException - { - - this.scrollToPosition (i.getPosition ()); - - } - - public void editNote (final Note n) - { - - final QuollEditorPanel _this = this; - - UIUtils.doLater (new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - try - { - - - _this.scrollToItem (n); - - new NoteActionHandler (n, - _this).actionPerformed (new ActionEvent (_this, - 0, - "edit")); - - } catch (Exception e) { - - Environment.logError ("Unable to edit item: " + - n, - e); - - UIUtils.showErrorMessage (_this, - String.format (Environment.getUIString (LanguageStrings.edititem, - LanguageStrings.actionerror), - Environment.getObjectTypeName (n))); - - } - - } - - }); - - } - - public void editScene (final Scene s) - { - - final QuollEditorPanel _this = this; - - UIUtils.doLater (new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - try - { - - _this.scrollToItem (s); - - new ChapterItemActionHandler (s, - _this, - AbstractFormPopup.EDIT, - s.getPosition ()).actionPerformed (new ActionEvent (_this, - 0, - "edit")); - } catch (Exception e) { - - Environment.logError ("Unable to edit item: " + - s, - e); - - UIUtils.showErrorMessage (_this, - String.format (Environment.getUIString (LanguageStrings.edititem, - LanguageStrings.actionerror), - Environment.getObjectTypeName (s))); - - } - - } - - }); - - } - - public void editOutlineItem (final OutlineItem n) - { - - final QuollEditorPanel _this = this; - - UIUtils.doLater (new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - try - { - - _this.scrollToItem (n); - - new ChapterItemActionHandler (n, - _this, - AbstractFormPopup.EDIT, - n.getPosition ()).actionPerformed (new ActionEvent (this, - 0, - "edit")); - } catch (Exception e) { - - Environment.logError ("Unable to show item: " + - n, - e); - - UIUtils.showErrorMessage (_this, - String.format (Environment.getUIString (LanguageStrings.edititem, - LanguageStrings.actionerror), - Environment.getObjectTypeName (n))); -/* - UIUtils.showErrorMessage (_this, - "Unable to show item, please contact Quoll Writer support for assistance."); -*/ - } - - } - - }); - - } - - public void showItem (final ChapterItem n) - { - - final QuollEditorPanel _this = this; - - UIUtils.doLater (new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - try - { - - _this.scrollToItem (n); - - _this.iconColumn.showItem (n); - - } catch (Exception e) { - - Environment.logError ("Unable to show item: " + - n, - e); - - UIUtils.showErrorMessage (_this, - String.format (Environment.getUIString (LanguageStrings.viewitem, - LanguageStrings.actionerror), - Environment.getObjectTypeName (n))); - //"Unable to show item, please contact Quoll Writer support for assistance."); - - } - - } - - }); - - } - - public List getTopLevelComponents () - { - - List l = new ArrayList (); - l.add (this.iconColumn); - l.add (this.editor); - - return l; - - } - - public void refresh (NamedObject n) - { - - // No need to do anything. - - } - - public void setSpellCheckingEnabled (boolean v) - { - - this.editor.setSpellCheckEnabled (v); - - String type = (v ? "off" : "on"); - - String tooltip = Environment.getUIString (LanguageStrings.dictionary, - LanguageStrings.spellcheck, - LanguageStrings.buttons, - (v ? "off" : "on"), - LanguageStrings.tooltip); - - this.setToolBarButtonIcon ("toggle-spellcheck", - tooltip, - //"Click turn the spell checker " + type, - "spellchecker-turn-" + type); - - } - - public void reinitIconColumn () - throws GeneralException - { - - try - { - - this.iconColumn.init (); - - } catch (Exception e) { - - throw new GeneralException ("Unable to init icon column", - e); - - } - - } - - - @Override - public void init () - throws GeneralException - { - - super.init (); - - final java.util.List prefix = new ArrayList<> (); - prefix.add (LanguageStrings.project); - prefix.add (LanguageStrings.editorpanel); - prefix.add (LanguageStrings.actions); - prefix.add (LanguageStrings.problemfinder); - - final QuollEditorPanel _this = this; - - this.problemFinderPanel = new Box (BoxLayout.Y_AXIS); - this.problemFinderPanel.setOpaque (true); - this.problemFinderPanel.setBackground (UIUtils.getComponentColor ()); - this.problemFinderPanel.setBorder (new MatteBorder (1, - 0, - 0, - 0, - Environment.getBorderColor ())); - - java.util.List hbuts = new ArrayList (); - - hbuts.add (UIUtils.createButton ("config", - Constants.ICON_MENU, - Environment.getUIString (prefix, - LanguageStrings.headercontrols, - LanguageStrings.items, - LanguageStrings.config, - LanguageStrings.tooltip), - //"Click to configure the text rules.", - new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.showProblemFinderRuleConfig (); - - } - - })); - - ActionAdapter finishAction = new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.problemFinderPanel.setVisible (false); - - _this.problemFinder.reset (); - - _this.editor.setHighlightWritingLine (_this.projectViewer.isHighlightWritingLine ()); - - _this.editor.grabFocus (); - - } - - }; - - hbuts.add (UIUtils.createButton (Constants.CANCEL_ICON_NAME, - Constants.ICON_MENU, - Environment.getUIString (prefix, - LanguageStrings.headercontrols, - LanguageStrings.items, - LanguageStrings.cancel, - LanguageStrings.tooltip), - //"Click to stop looking for problems.", - finishAction)); - - hbuts.add (UIUtils.createHelpPageButton ("chapters/problem-finder", - Constants.ICON_MENU, - null)); - - JToolBar tb = UIUtils.createButtonBar (hbuts); - - tb.setBorder (UIUtils.createPadding (0, 0, 0, 5)); - - Header h = UIUtils.createHeader (Environment.getUIString (prefix, - LanguageStrings.title), - //"Find Problems", - Constants.SUB_PANEL_TITLE, - Constants.PROBLEM_FINDER_ICON_NAME, - tb); - - this.problemFinderPanel.add (h); - this.problemFinderPanel.setVisible (false); - this.problemFinderPanel.setAlignmentX (Component.LEFT_ALIGNMENT); - - this.problemFinder = new ProblemFinder (this, - // This is a duplicate reference that overlaps with parent viewer reference. - // TODO: Resolve the duplication, make generic and fix this class with ProjectViewer. - this.projectViewer); - this.problemFinder.setAlignmentX (Component.LEFT_ALIGNMENT); - - this.problemFinderPanel.add (this.problemFinder); - - Box buts = new Box (BoxLayout.X_AXIS); - - buts.setAlignmentX (Component.LEFT_ALIGNMENT); - - JButton cbut = null; - - JButton prev = new JButton (Environment.getIcon ("previous", - Constants.ICON_MENU)); - prev.addActionListener (new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - try - { - - _this.problemFinder.previous (); - - _this.updateIgnoredProblemsLabel (); - - } catch (Exception e) - { - - Environment.logError ("Unable to goto previous.", - e); - - UIUtils.showErrorMessage (_this, - Environment.getUIString (prefix, - LanguageStrings.previouserror)); - //"Unable to go to previous."); - - } - - } - - }); - - prev.setToolTipText (Environment.getUIString (prefix, - LanguageStrings.buttons, - LanguageStrings.previous, - LanguageStrings.tooltip)); - //"Go back to the problem(s)"); - - buts.add (prev); - buts.add (Box.createHorizontalStrut (5)); - - JButton next = UIUtils.createButton (Environment.getUIString (prefix, - LanguageStrings.buttons, - LanguageStrings.next, - LanguageStrings.text), - //"Next", - "next"); - - next.addActionListener (new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - try - { - - _this.problemFinder.next (); - - _this.updateIgnoredProblemsLabel (); - - _this.problemFinderPanel.setMaximumSize (new Dimension (Short.MAX_VALUE, - _this.problemFinderPanel.getPreferredSize ().height)); - - } catch (Exception e) - { - - Environment.logError ("Unable to goto next problem", - e); - - UIUtils.showErrorMessage (_this, - Environment.getUIString (prefix, - LanguageStrings.nexterror)); - //"Unable to go to next sentence."); - - } - - } - - }); - - next.setToolTipText (Environment.getUIString (prefix, - LanguageStrings.buttons, - LanguageStrings.next, - LanguageStrings.tooltip)); - //"Find the next problem(s)"); - next.setHorizontalTextPosition (SwingConstants.LEFT); - - buts.add (next); - - buts.add (Box.createHorizontalStrut (5)); - - JButton finish = UIUtils.createButton (Environment.getUIString (prefix, - LanguageStrings.buttons, - LanguageStrings.finish, - LanguageStrings.text), - //"Finish", - finishAction); - - finish.setToolTipText (Environment.getUIString (prefix, - LanguageStrings.buttons, - LanguageStrings.finish, - LanguageStrings.tooltip)); - //"Stop looking for problems"); - finish.setHorizontalTextPosition (SwingConstants.LEFT); - - buts.add (finish); - - this.ignoredProblemsLabel = UIUtils.createClickableLabel ("", - Environment.getIcon ("warning", - Constants.ICON_MENU)); - this.ignoredProblemsLabel.setVisible (false); - this.ignoredProblemsLabel.setBorder (UIUtils.createPadding (0, 10, 0, 0)); - - this.updateIgnoredProblemsLabel (); - - this.ignoredProblemsLabel.addMouseListener (new MouseEventHandler () - { - - @Override - public void handlePress (MouseEvent ev) - { - - int s = _this.problemFinder.getIgnoredIssues ().size (); - - String pl = (s > 1 ? "s" :""); - - UIUtils.createQuestionPopup (_this.projectViewer, - Environment.getUIString (prefix, - LanguageStrings.unignore, - LanguageStrings.confirmpopup, - LanguageStrings.title), - //"Un-ignore " + s + " problem" + pl, - Constants.PROBLEM_FINDER_ICON_NAME, - String.format (Environment.getUIString (prefix, - LanguageStrings.unignore, - LanguageStrings.confirmpopup, - LanguageStrings.text), - Environment.formatNumber (s)), - //"Please confirm you wish to un-ignore the " + - //s + - //" problem" + pl + "?", - Environment.getUIString (prefix, - LanguageStrings.unignore, - LanguageStrings.confirmpopup, - LanguageStrings.confirm), - //"Yes, un-ignore " + (s == 1 ? "it" : "them"), - null, - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.problemFinder.removeAllIgnores (); - - _this.updateIgnoredProblemsLabel (); - - } - - }, - null, - null, - null); - - } - - }); - - buts.add (this.ignoredProblemsLabel); - buts.add (Box.createHorizontalGlue ()); - - buts.setBorder (UIUtils.createPadding (10, 10, 7, 10)); - - this.problemFinderPanel.add (buts); - - this.add (this.problemFinderPanel); - - this.reinitIconColumn (); - - this.setReadyForUse (true); - - } - - public void showProblemFinder () - { - - if (!this.projectViewer.isLanguageFunctionAvailable ()) - { - - return; - - } - - // Disable typewriter scrolling when the problem finder is active. - this.setUseTypewriterScrolling (false); - this.editor.setHighlightWritingLine (false); - - this.problemFinderPanel.setMaximumSize (new Dimension (Short.MAX_VALUE, - this.problemFinderPanel.getPreferredSize ().height)); - - this.problemFinderPanel.setVisible (true); - - this.projectViewer.fireProjectEvent (ProjectEvent.PROBLEM_FINDER, - ProjectEvent.SHOW); - - try - { - - this.problemFinder.start (); - - } catch (Exception e) - { - - Environment.logError ("Unable to start problem finding", - e); - - UIUtils.showErrorMessage (this, - Environment.getUIString (LanguageStrings.project, - LanguageStrings.editorpanel, - LanguageStrings.actions, - LanguageStrings.problemfinder, - LanguageStrings.actionerror)); - //"Unable to open problem finding panel"); - - return; - - } - - /* - try - { - - this.problemFinder.next (); - - } catch (Exception e) { - - Environment.logError ("Unable to start problem finding", - e); - - UIUtils.showErrorMessage (this, - "Unable to start problem finding"); - - return; - - } - */ - } - - public int getIconColumnXOffset (ChapterItem i) - { - - int xOffset = 36; - - if (i instanceof OutlineItem) - { - - xOffset = 22; - - } - - return xOffset; - - } - - public void removeItemHighlightTextFromEditor (ChapterItem it) - { - - this.editor.removeAllHighlights (this.highlight); - - } - - public void highlightItemTextInEditor (ChapterItem it) - { - - this.editor.removeAllHighlights (this.highlight); - this.editor.addHighlight (it.getStartPosition (), - it.getEndPosition (), - this.highlight, - false); - - } - - private void updateIgnoredProblemsLabel () - { - - if (this.ignoredProblemsLabel == null) - { - - return; - - } - - int s = this.problemFinder.getIgnoredIssues ().size (); - - if (s > 0) - { - - this.ignoredProblemsLabel.setVisible (true); - - java.util.List prefix = new ArrayList<> (); - prefix.add (LanguageStrings.project); - prefix.add (LanguageStrings.editorpanel); - prefix.add (LanguageStrings.actions); - prefix.add (LanguageStrings.problemfinder); - prefix.add (LanguageStrings.ignored); - - String t = null; - - if (s == 1) - { - - t = Environment.getUIString (prefix, - LanguageStrings.single); - - } else { - - t = String.format (Environment.getUIString (prefix, - LanguageStrings.plural), - Environment.formatNumber (s)); - - } - - this.ignoredProblemsLabel.setText (t); - //Environment.replaceObjectNames (s + " problem" + (s > 1 ? "s" : "") + " currently ignored in this {chapter}, click to un-ignore.")); - - } else { - - this.ignoredProblemsLabel.setVisible (false); - - } - - this.validate (); - this.repaint (); - - } - - @Override - public void eventOccurred (ProjectEvent ev) - { - - if (ProjectEvent.PROBLEM_FINDER.equals (ev.getType ())) - { - - this.updateIgnoredProblemsLabel (); - - } - - } - - @Override - public void close () - { - - super.close (); - - this.problemFinder.saveIgnores (); - - this.viewer.removeProjectEventListener (this); - - } -/* - public ProblemFinderRuleConfig getProblemFinderRuleConfig () - { - - return this.problemFinderRuleConfig; - - } -*/ - public void removeIgnoreCheckboxesForRule (Rule r) - { - - if (this.problemFinder != null) - { - - this.problemFinder.removeCheckboxesForRule (r); - - } - - } - - public void restoreBackgroundColor () - { - - super.restoreBackgroundColor (); - - this.iconColumn.setBackground (IconColumn.defaultBGColor); - - } - - public void setBackgroundColor (Color c) - { - - super.setBackgroundColor (c); - - if ((c.equals (Color.white)) - || - (c.equals (UIUtils.getComponentColor ())) - ) - { - - this.iconColumn.setBackground (IconColumn.defaultBGColor); - - } else - { - - this.iconColumn.setBackground (c); - - } - - } - - private static class CutNPasteTransferHandler extends TransferHandler - { - public void exportToClipboard(JComponent comp, Clipboard clipboard, - int action) - throws IllegalStateException - { - - if (comp instanceof JTextComponent) - { - - JTextComponent text = (JTextComponent)comp; - int p0 = text.getSelectionStart(); - int p1 = text.getSelectionEnd(); - if (p0 != p1) { - try { - Document doc = text.getDocument(); - String srcData = doc.getText(p0, p1 - p0); - - StringSelection contents =new StringSelection(srcData); - - // this may throw an IllegalStateException, - // but it will be caught and handled in the - // action that invoked this method - clipboard.setContents(contents, null); - - if (action == TransferHandler.MOVE) { - doc.remove(p0, p1 - p0); - } - } catch (BadLocationException ble) {} - } - } - } - - public boolean importData(JComponent comp, Transferable t) - { - - if (comp instanceof JTextComponent) { - DataFlavor flavor = getFlavor(t.getTransferDataFlavors()); - - if (flavor != null) { - InputContext ic = comp.getInputContext(); - if (ic != null) { - ic.endComposition(); - } - try { - String data = (String)t.getTransferData(flavor); - - ((JTextComponent)comp).replaceSelection(data); - return true; - } catch (UnsupportedFlavorException ufe) { - } catch (IOException ioe) { - } - } - } - return false; - } - - public boolean canImport(JComponent comp, - DataFlavor[] transferFlavors) - { - - JTextComponent c = (JTextComponent)comp; - if (!(c.isEditable() && c.isEnabled())) { - return false; - } - return (getFlavor(transferFlavors) != null); - } - - public int getSourceActions(JComponent c) - { - - return NONE; - - } - - private DataFlavor getFlavor(DataFlavor[] flavors) - { - if (flavors != null) { - for (int counter = 0; counter < flavors.length; counter++) { - if (flavors[counter].equals(DataFlavor.stringFlavor)) { - return flavors[counter]; - } - } - } - return null; - } - } - - -} diff --git a/src/com/quollwriter/ui/sidebars/Finder.java b/src/com/quollwriter/ui/sidebars/Finder.java deleted file mode 100644 index ad548e11..00000000 --- a/src/com/quollwriter/ui/sidebars/Finder.java +++ /dev/null @@ -1,454 +0,0 @@ -package com.quollwriter.ui.sidebars; - -import java.awt.Component; -import java.awt.Dimension; -import java.awt.Point; -import java.awt.Toolkit; -import java.awt.event.*; - -import java.util.List; -import java.util.ArrayList; -import java.util.Map; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.Set; - -import javax.swing.*; -import javax.swing.border.*; -import javax.swing.tree.*; -import javax.swing.text.*; -import javax.swing.event.*; - -import com.gentlyweb.utils.*; - -import com.quollwriter.*; -import com.quollwriter.ui.*; -import com.quollwriter.ui.panels.*; -import com.quollwriter.data.*; -import com.quollwriter.ui.renderers.*; -import com.quollwriter.ui.components.QTextEditor; -import com.quollwriter.ui.components.ActionAdapter; - -public class Finder extends AbstractSideBar implements TreeSelectionListener -{ - - public static final String ID = "find"; - - private JTextField text = null; - private Object highlightId = null; - private QTextEditor highlightedEditor = null; - private Box content = null; - private JLabel noMatches = null; - private String currentSearch = null; - private Set results = null; - - public Finder (AbstractProjectViewer v) - { - - super (v); - - } - - @Override - public String getId () - { - - return ID; - - } - - public void setText (String t) - { - - this.text.setText (t); - - this.search (); - - } - - @Override - public boolean canClose () - { - - return true; - - } - - @Override - public String getTitle () - { - - return Environment.getUIString (LanguageStrings.objectfinder, - LanguageStrings.sidebar, - LanguageStrings.title) + (this.currentSearch != null ? ": " + this.currentSearch : ""); - - } - - @Override - public void onHide () - { - - //this.clearHighlight (); - - } - - @Override - public void onClose () - { - - this.removeListeners (); - - } - - private void removeListeners () - { - - // Remove the listeners. - if (this.results != null) - { - - for (FindResultsBox b : this.results) - { - - b.getTree ().removeTreeSelectionListener (this); - - } - - } - - } - - public String getIconType () - { - - return Constants.FIND_ICON_NAME; - - } - - public List getHeaderControls () - { - - return null; - - } - - public JComponent getContent () - { - - Box b = new Box (BoxLayout.Y_AXIS); - - final Finder _this = this; - - this.text = UIUtils.createTextField (); - this.text.setBorder (new CompoundBorder (UIUtils.createPadding (5, 10, 5, 10), - this.text.getBorder ())); - - this.viewer.fireProjectEvent (ProjectEvent.FIND, - ProjectEvent.SHOW); - - KeyAdapter vis = new KeyAdapter () - { - - private Timer searchT = new Timer (750, - new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.search (); - - } - - }); - - public void keyPressed (KeyEvent ev) - { - - this.searchT.setRepeats (false); - this.searchT.stop (); - - // If enter was pressed then search, don't start the timer. - if (ev.getKeyCode () == KeyEvent.VK_ENTER) - { - - _this.search (); - return; - - } - - this.searchT.start (); - - } - - }; - - this.text.addKeyListener (vis); - this.text.setMaximumSize (new Dimension (Short.MAX_VALUE, - this.text.getPreferredSize ().height)); - - b.add (this.text); - - this.content = new Box (BoxLayout.Y_AXIS); - this.content.setAlignmentX (Component.LEFT_ALIGNMENT); - this.content.setOpaque (false); - - this.content.setMinimumSize (new Dimension (250, - 250)); - - this.noMatches = UIUtils.createInformationLabel (Environment.getUIString (LanguageStrings.objectfinder, - LanguageStrings.novalue)); - //"No matches found."); - - this.noMatches.setVisible (false); - - this.noMatches.setBorder (UIUtils.createPadding (5, 10, 0, 5)); - - b.add (this.noMatches); - - b.add (this.wrapInScrollPane (this.content)); - - return b; - - } - - @Override - public void init (String saveState) - throws GeneralException - { - - super.init (saveState); - - } - - public void setFindText (String text) - { - - if (text != null) - { - - if (text.trim ().length () == 0) - { - - return; - - } - - this.text.setText (text); - - this.search (); - - } - - } - - @Override - public void onShow () - { - - this.text.grabFocus (); - - } - - private void search () - { - - this.removeListeners (); - - this.content.removeAll (); - - this.clearHighlight (); - - String t = this.text.getText ().trim (); - - if (t.length () == 0) - { - - this.setTitle (this.getTitle ()); - - this.currentSearch = null; - - return; - - } - - this.results = this.viewer.findText (t); - - boolean expandSearchResults = UserProperties.getAsBoolean (Constants.SHOW_EACH_CHAPTER_FIND_RESULT_PROPERTY_NAME); - - for (FindResultsBox r : this.results) - { - - r.getTree ().addTreeSelectionListener (this); - - r.init (); - - if (expandSearchResults) - { - - r.exapndAllResultsInTree (); - - } - - this.content.add (r); - - } - - this.noMatches.setVisible (this.results.size () == 0); - - this.currentSearch = t; - - this.setTitle (this.getTitle ()); - - this.validate (); - this.repaint (); - - } - - @Override - public void valueChanged (TreeSelectionEvent ev) - { - - if (this.results == null) - { - - return; - - } - - if (!ev.isAddedPath ()) - { - - return; - - } - - for (FindResultsBox b : this.results) - { - - if (ev.getSource () == b.getTree ()) - { - - continue; - - } - - b.clearSelectedItemInTree (); - - } - - } - - public void clearHighlight () - { -/* - if (this.highlightedEditor != null) - { - - this.highlightedEditor.removeHighlight (this.highlightId); - - } -*/ - } -/* - public JButton[] getButtons () - { - - final Finder _this = this; - - JButton b = new JButton ("Finish"); - - b.addActionListener (new ActionAdapter () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.clearHighlight (); - - _this.close (); - - } - - }); - - JButton[] buts = new JButton[1]; - buts[0] = b; - - return buts; - - } -*/ -/* - public void showSegment (final Object o, - final Segment s) - { - - this.clearHighlight (); - - if (o instanceof Chapter) - { - - final Chapter c = (Chapter) o; - - final Finder _this = this; - - this.viewer.viewObject ((DataObject) o, - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - AbstractEditorPanel p = null; - - if (_this.viewer instanceof ProjectViewer) - { - - ProjectViewer pv = (ProjectViewer) _this.viewer; - - p = pv.getEditorForChapter (c); - - } - - if (_this.viewer instanceof WarmupsViewer) - { - - WarmupsViewer wv = (WarmupsViewer) _this.viewer; - - p = wv.getEditorForWarmup (c); - - } - - try - { - - p.scrollToPosition (s.getBeginIndex ()); - - } catch (Exception e) { - - Environment.logError ("Unable to scroll to: " + s.getBeginIndex (), - e); - - return; - - } - - final QTextEditor ed = p.getEditor (); - - _this.highlightId = ed.addHighlight (s.getBeginIndex (), - s.getEndIndex (), - null, - true); - - _this.highlightedEditor = ed; - - } - - }); - - } - - } -*/ -} diff --git a/src/com/quollwriter/ui/sidebars/ProblemFinderSideBar.java b/src/com/quollwriter/ui/sidebars/ProblemFinderSideBar.java deleted file mode 100644 index 9999942f..00000000 --- a/src/com/quollwriter/ui/sidebars/ProblemFinderSideBar.java +++ /dev/null @@ -1,684 +0,0 @@ -package com.quollwriter.ui.sidebars; - -import java.util.List; -import java.util.ArrayList; -import java.util.Set; -import java.util.HashSet; -import java.util.Map; -import java.util.LinkedHashMap; -import java.util.Enumeration; -import java.util.Iterator; - -import java.awt.Component; -import java.awt.Dimension; -import java.awt.event.*; - -import javax.swing.*; -import javax.swing.tree.*; -import javax.swing.event.*; - -import com.quollwriter.ui.*; -import com.quollwriter.text.*; -import com.quollwriter.data.*; -import com.quollwriter.*; -import com.quollwriter.events.*; -import com.quollwriter.ui.components.ScrollableBox; - -public class ProblemFinderSideBar extends AbstractSideBar implements DocumentListener, ProjectEventListener -{ - - public static final String ID = "problemfinder"; - //private static final String TITLE_PREFIX = "Find Problems"; - - private ChapterProblemResultsBox results = null; - private Rule rule = null; - private Box content = null; - private JLabel noMatches = null; - private JLabel ruleSummary = null; - private JLabel ignoredProblemsLabel = null; - private JLabel searchingLabel = null; - private java.util.Timer updateTimer = null; - private Set ignored = null; - - public ProblemFinderSideBar (ProjectViewer v, - Rule r) - { - - super (v); - - this.rule = r; - - v.addProjectEventListener (this); - - } - - @Override - public String getId () - { - - return ID; - - } - - @Override - public void sideBarHidden (SideBarEvent ev) - { - - super.sideBarHidden (ev); - - if (this.results != null) - { - - this.results.clearHighlight (); - - } - - } - - @Override - public void eventOccurred (ProjectEvent ev) - { - - if (ev.getType ().equals (ProjectEvent.PROBLEM_FINDER)) - { - - this.find (); - - } - - } - - @Override - public boolean canClose () - { - - return true; - - } - - @Override - public String getTitle () - { - - return Environment.getUIString (LanguageStrings.project, - LanguageStrings.sidebar, - LanguageStrings.problemfinder, - LanguageStrings.title); - - } - - @Override - public void onHide () - { - - } - - @Override - public void onClose () - { - - this.viewer.removeChapterDocumentListener (this); - this.updateTimer.cancel (); - this.viewer.removeProjectEventListener (this); - - } - - @Override - public String getIconType () - { - - return Constants.PROBLEM_FINDER_ICON_NAME; - - } - - @Override - public List getHeaderControls () - { - - final ProblemFinderSideBar _this = this; - - final List prefix = new ArrayList (); - prefix.add (LanguageStrings.project); - prefix.add (LanguageStrings.sidebar); - prefix.add (LanguageStrings.problemfinder); - prefix.add (LanguageStrings.headercontrols); - prefix.add (LanguageStrings.items); - - List buts = new ArrayList (); - - JButton but = UIUtils.createButton ("refresh", - Constants.ICON_SIDEBAR, - Environment.getUIString (prefix, - LanguageStrings.findall, - LanguageStrings.tooltip), - //"Click to find all problems for this rule", - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - _this.find (); - - } - - }); - - buts.add (but); - - but = UIUtils.createButton (Constants.OPTIONS_ICON_NAME, - Constants.ICON_SIDEBAR, - Environment.getUIString (prefix, - LanguageStrings.options, - LanguageStrings.tooltip), - //"Click to view the the options", - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - JMenuItem mi = null; - - JPopupMenu popup = new JPopupMenu (); - - popup.add (UIUtils.createMenuItem (Environment.getUIString (prefix, - LanguageStrings.options, - LanguageStrings.popupmenu, - LanguageStrings.items, - LanguageStrings.edit, - LanguageStrings.tooltip), - //"Edit this rule", - Constants.EDIT_ICON_NAME, - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - ProblemFinderRuleConfig config = _this.viewer.getProblemFinderRuleConfig (); - - _this.viewer.showProblemFinderRuleConfig (); - - config.editRule (_this.rule, - false); - - } - - })); - - popup.add (UIUtils.createMenuItem (Environment.getUIString (prefix, - LanguageStrings.options, - LanguageStrings.popupmenu, - LanguageStrings.items, - LanguageStrings.view, - LanguageStrings.tooltip), - //"Show the Problem Finder rules", - Constants.VIEW_ICON_NAME, - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.viewer.showProblemFinderRuleConfig (); - - } - - })); - - JComponent s = (JComponent) ev.getSource (); - - popup.show (s, - s.getWidth () / 2, - s.getHeight ()); - - } - - }); - - buts.add (but); - - return buts; - - } - - public JComponent getContent () - { - - final ProblemFinderSideBar _this = this; - - Box b = new Box (BoxLayout.Y_AXIS); - - this.content = new Box (BoxLayout.Y_AXIS); - this.content.setAlignmentX (Component.LEFT_ALIGNMENT); - this.content.setOpaque (false); - - this.content.setMinimumSize (new Dimension (250, - 250)); - - this.noMatches = UIUtils.createInformationLabel (Environment.getUIString (LanguageStrings.project, - LanguageStrings.sidebar, - LanguageStrings.problemfinder, - LanguageStrings.notfound)); - //"No problems found."); - - this.noMatches.setVisible (false); - - this.noMatches.setBorder (UIUtils.createPadding (5, 10, 0, 5)); - - this.ruleSummary = UIUtils.createInformationLabel (this.rule.getSummary ()); - - this.ruleSummary.setBorder (UIUtils.createPadding (5, 10, 5, 5)); - - b.add (this.ruleSummary); - - this.ignoredProblemsLabel = UIUtils.createClickableLabel ("", - Environment.getIcon ("warning", - Constants.ICON_MENU)); - - this.ignoredProblemsLabel.setBorder (UIUtils.createPadding (5, 5, 5, 5)); - - this.ignoredProblemsLabel.addMouseListener (new MouseEventHandler () - { - - @Override - public void handlePress (MouseEvent ev) - { - - List prefix = new ArrayList (); - prefix.add (LanguageStrings.project); - prefix.add (LanguageStrings.sidebar); - prefix.add (LanguageStrings.problemfinder); - prefix.add (LanguageStrings.unignore); - - int s = _this.ignored.size (); - String pl = (s > 1 ? "s" : ""); - - UIUtils.createQuestionPopup (_this.viewer, - Environment.getUIString (prefix, - LanguageStrings.confirmpopup, - LanguageStrings.title), - Constants.PROBLEM_FINDER_ICON_NAME, - String.format (Environment.getUIString (prefix, - LanguageStrings.confirmpopup, - LanguageStrings.text), - s, - _this.rule.getSummary ()), - Environment.getUIString (prefix, - LanguageStrings.confirmpopup, - LanguageStrings.confirm), - //String.format ("Yes, un-ignore %s", - // (s == 1 ? "it" : "them")), - null, - new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - Set chaps = new HashSet (); - - for (Issue ig : _this.ignored) - { - - ig.getChapter ().getProblemFinderIgnores ().remove (ig); - - chaps.add (ig.getChapter ()); - - } - - try - { - - for (Chapter c : chaps) - { - - _this.viewer.saveProblemFinderIgnores (c); - - } - - } catch (Exception e) { - - Environment.logError ("Unable to update problem finder ignores", - e); - - UIUtils.showErrorMessage (_this.viewer, - Environment.getUIString (prefix, - LanguageStrings.actionerror)); - //"Unable to update problem finder ignores."); - - } - - _this.viewer.fireProjectEvent (ProjectEvent.PROBLEM_FINDER, - ProjectEvent.UNIGNORE); - - _this.find (); - - } - - }, - null, - null, - null); - - } - - }); - - this.ignoredProblemsLabel.setVisible (false); - - b.add (this.ignoredProblemsLabel); - - this.searchingLabel = UIUtils.createLoadingLabel (Environment.getUIString (LanguageStrings.project, - LanguageStrings.sidebar, - LanguageStrings.problemfinder, - LanguageStrings.loading)); - //"Finding problems... please wait..."); - this.searchingLabel.setBorder (UIUtils.createPadding (5, 5, 5, 5)); - - this.searchingLabel.setVisible (false); - - b.add (this.searchingLabel); - - b.add (this.noMatches); - - b.add (this.wrapInScrollPane (this.content, - true)); - - return b; - - } - - @Override - public void init (String saveState) - throws GeneralException - { - - super.init (saveState); - - this.viewer.addChapterDocumentListener (this); - - // Find all the matches. - this.find (); - - } - - @Override - public void insertUpdate (DocumentEvent ev) - { - - this.find (); - - } - - @Override - public void changedUpdate (DocumentEvent ev) - { - - this.find (); - - } - - @Override - public void removeUpdate (DocumentEvent ev) - { - - this.find (); - - } - - public void setRule (Rule r) - { - - this.rule = r; - - this.ruleSummary.setText (this.rule.getSummary ()); - - this.find (); - - } - - private void update (final Map> probs, - final Set ignored) - { - - final ProblemFinderSideBar _this = this; - - this.searchingLabel.setVisible (false); - - boolean expandSearchResults = false; - - java.util.List openPaths = new ArrayList (); - - if (this.results != null) - { - - Enumeration paths = this.results.getTree ().getExpandedDescendants (new TreePath (this.results.getTree ().getModel ().getRoot ())); - - if (paths != null) - { - - while (paths.hasMoreElements ()) - { - - openPaths.add (paths.nextElement ()); - - } - - } - - } else { - - expandSearchResults = UserProperties.getAsBoolean (Constants.SHOW_EACH_CHAPTER_FIND_RESULT_PROPERTY_NAME); - - } - - this.content.removeAll (); - - this.ignored = ignored; - - this.ignoredProblemsLabel.setVisible (this.ignored.size () > 0); - - List prefix = new ArrayList (); - prefix.add (LanguageStrings.project); - prefix.add (LanguageStrings.sidebar); - prefix.add (LanguageStrings.problemfinder); - prefix.add (LanguageStrings.ignored); - - if (ignored.size () > 0) - { - - int s = ignored.size (); - - String t = ""; - - if (s == 1) - { - - t = Environment.getUIString (prefix, - LanguageStrings.single); - //"%s problem%s for this rule has been ignored, click to un-ignore it."; - - } else { - - t = String.format (Environment.getUIString (prefix, - LanguageStrings.plural), - Environment.formatNumber (s)); - //"%s problem%s for this rule have been ignored, click to un-ignore them."; - - } - - this.ignoredProblemsLabel.setText (t); - - } - - // Remove the ignored. - // This is very inefficient and may need some pre-filtering such as putting the ignored - // into chapter groups. - for (Issue igi : ignored) - { - - Chapter igc = igi.getChapter (); - - if (igc != null) - { - - Set issues = probs.get (igc); - - Iterator iter = issues.iterator (); - - while (iter.hasNext ()) - { - - Issue i = iter.next (); - - if (igi.equals (i)) - { - - iter.remove (); - - } - - } - - if (issues.size () == 0) - { - - probs.remove (igc); - - } - - } - - } - - ChapterProblemResultsBox r = new ChapterProblemResultsBox (Environment.getUIString (LanguageStrings.project, - LanguageStrings.sidebar, - LanguageStrings.problemfinder, - LanguageStrings.results, - LanguageStrings.title), - //"Found", - null, - Chapter.OBJECT_TYPE, - this.viewer, - probs); - - this.results = r; - - r.init (); - - DefaultTreeModel dtm = (DefaultTreeModel) this.results.getTree ().getModel (); - - DefaultMutableTreeNode root = (DefaultMutableTreeNode) dtm.getRoot (); - - for (TreePath p : openPaths) - { - - this.results.getTree ().expandPath (UIUtils.getTreePathForUserObject (root, - ((DefaultMutableTreeNode) p.getLastPathComponent ()).getUserObject ())); - - } - - this.content.add (r); - - if (expandSearchResults) - { - - r.exapndAllResultsInTree (); - - } - - this.noMatches.setVisible (probs.size () == 0); - - this.setTitle (this.getTitle ()); - - this.validate (); - this.repaint (); - - } - - public void find () - { - - boolean immediate = (this.updateTimer == null); - - if (!immediate) - { - - this.updateTimer.cancel (); - - } - - this.searchingLabel.setVisible (true); - this.ignoredProblemsLabel.setVisible (false); - - if (this.results != null) - { - - this.results.clearHighlight (); - this.results.setVisible (false); - - } - - this.updateTimer = new java.util.Timer ("problem-finder-side-bar", true); - - final ProblemFinderSideBar _this = this; - - this.updateTimer.schedule (new java.util.TimerTask () - { - - @Override - public void run () - { - - Thread.currentThread ().setPriority (Thread.MIN_PRIORITY); - - Set _ignored = new HashSet (); - - try - { - - _ignored = _this.viewer.getProblemFinderIgnores (_this.rule); - - } catch (Exception e) { - - Environment.logError ("Unable to get problem finder ignores for rule: " + - _this.rule, - e); - - } - - final Set ignored = _ignored; - final Map> probs = _this.viewer.getProblemsForAllChapters (_this.rule); - - UIUtils.doLater (new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - _this.update (probs, - ignored); - - } - - }); - - } - - }, - (immediate ? 0 : 750)); - - } - - @Override - public void onShow () - { - - } - -} diff --git a/src/com/quollwriter/ui/sidebars/ProjectSideBar.java b/src/com/quollwriter/ui/sidebars/ProjectSideBar.java deleted file mode 100644 index 7ec002a5..00000000 --- a/src/com/quollwriter/ui/sidebars/ProjectSideBar.java +++ /dev/null @@ -1,2004 +0,0 @@ -package com.quollwriter.ui.sidebars; - -import java.awt.CardLayout; -import java.awt.Component; -import java.awt.Dimension; -import java.awt.Container; -import java.awt.Insets; -import java.awt.image.*; -import java.awt.event.*; - -import java.awt.dnd.*; -import java.awt.datatransfer.*; - -import java.util.Map; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.ArrayList; -import java.util.Set; -import java.util.HashSet; -import java.util.LinkedHashSet; -import java.util.StringTokenizer; -import java.util.Collection; -import java.util.TreeMap; - -import javax.swing.*; -import javax.swing.tree.*; -import javax.swing.border.*; - -import com.quollwriter.*; -import com.quollwriter.ui.*; -import com.quollwriter.ui.userobjects.*; -import com.quollwriter.ui.actionHandlers.*; -import com.quollwriter.data.*; -import com.quollwriter.events.*; -import com.quollwriter.data.editors.*; -import com.quollwriter.editors.ui.*; -import com.quollwriter.ui.components.Dragger; -import com.quollwriter.ui.components.DragListener; -import com.quollwriter.ui.components.DragEvent; -import com.quollwriter.ui.components.Header; -import com.quollwriter.ui.components.ScrollableBox; -import com.quollwriter.ui.components.ColorPainter; -import com.quollwriter.ui.components.QPopup; - -import static com.quollwriter.LanguageStrings.*; -import static com.quollwriter.Environment.getUIString; - -public class ProjectSideBar extends AbstractSideBar -{ - - private JScrollPane content = null; - private JComponent contentBox = null; - - public static DataFlavor COMPONENT_FLAVOR = null; - private Set legacyAssetObjTypes = null; - - public ProjectSideBar (ProjectViewer v) - { - - super (v); - - this.contentBox = new Box (BoxLayout.Y_AXIS); - - this.contentBox.setOpaque (false); - this.contentBox.setAlignmentX (Component.LEFT_ALIGNMENT); - this.contentBox.setMaximumSize (new Dimension (Short.MAX_VALUE, - Short.MAX_VALUE)); - - this.content = this.wrapInScrollPane (this.contentBox); - - final ProjectSideBar _this = this; - - this.content.setTransferHandler (new TransferHandler () - { - - @Override - public boolean canImport (TransferSupport support) - { - - if (!support.isDrop ()) - { - - return false; - } - - boolean canImport = support.isDataFlavorSupported (COMPONENT_FLAVOR); - - return canImport; - } - - @Override - public boolean importData (TransferSupport support) - { - - if (!canImport (support)) - { - - return false; - } - - Component[] components; - - try - { - components = (Component[]) support.getTransferable ().getTransferData (COMPONENT_FLAVOR); - - } catch (Exception e) { - - return false; - } - - // Item being transfered. - Component component = components[0]; - - _this.contentBox.add (component); - - _this.contentBox.revalidate (); - _this.contentBox.repaint (); - - for (AccordionItem it : _this.getAccordionItems ()) - { - - _this.setSelected (it, - false); - - } - - return true; - - } - - @Override - public void exportDone (JComponent c, - Transferable t, - int action) - { - - } - - }); - - this.contentBox.setToolTipText (Environment.getUIString (LanguageStrings.project, - LanguageStrings.sidebar, - LanguageStrings.tooltip)); - //"Double click to add a new type of Object, right click to see the menu."); - this.contentBox.addMouseListener (new MouseEventHandler () - { - - @Override - public void handleDoublePress (MouseEvent ev) - { - - UIUtils.showAddNewObjectType (_this.viewer); - - } - @Override - public void fillPopup (JPopupMenu m, - MouseEvent ev) - { - - _this.addAddSectionMenu (m, - null); - - } - - }); - - try - { - COMPONENT_FLAVOR = new DataFlavor(DataFlavor.javaJVMLocalObjectMimeType + ";class=\"" + Component[].class.getName() + "\""); - } - catch(Exception e) - { - - } - - Set aObjTypes = new HashSet (); - - aObjTypes.add (QCharacter.OBJECT_TYPE); - aObjTypes.add (Location.OBJECT_TYPE); - aObjTypes.add (QObject.OBJECT_TYPE); - aObjTypes.add (ResearchItem.OBJECT_TYPE); - - this.legacyAssetObjTypes = aObjTypes; - - } - - @Override - public void onHide () - { - - } - - @Override - public void onShow () - { - - } - - public void onClose () - { - - - } - - public boolean removeOnClose () - { - - return false; - - } - - public String getActiveTitle () - { - - return getUIString (project,sidebar,title); - //"{Project}"; - - } - - public String getTitle () - { - - return null; - - } - - public String getActiveIconType () - { - - return Project.OBJECT_TYPE; - - } - - public String getIconType () - { - - return null; - - } - - public Dimension getMinimumSize () - { - - return new Dimension (UIUtils.getScreenScaledWidth (250), - 200); - - } - - @Override - public List getHeaderControls () - { - - return null; - - } - - public boolean canClose () - { - - return false; - - } - - public JComponent getContent () - { - - return this.content; - - } - - public void panelShown (MainPanelEvent ev) - { - - this.setObjectSelectedInSidebar (ev.getForObject ()); - - } - - public void setObjectSelectedInSidebar (DataObject d) - { - - for (AccordionItem ai : this.getAccordionItems ()) - { - - if (ai instanceof ProjectObjectsAccordionItem) - { - - ProjectObjectsAccordionItem pai = (ProjectObjectsAccordionItem) ai; - - pai.clearSelectedItemInTree (); - - if (d != null) - { - - if (d.getObjectType ().equals (pai.getId ())) - { - - pai.setObjectSelectedInTree (d); - - } - - } - } - - } - - } - - private ProjectObjectsAccordionItem getProjectObjectsAccordionItem (String objType) - { - - Set ais = this.getAccordionItems (); - - for (AccordionItem ai : ais) - { - - if (ai.getId ().equals (objType)) - { - - if (ai instanceof ProjectObjectsAccordionItem) - { - - ProjectObjectsAccordionItem pai = (ProjectObjectsAccordionItem) ai; - - return pai; - - } - - } - - } - - return null; - - } - - public void reloadTreeForObjectType (String objType) - { - - ProjectObjectsAccordionItem pai = this.getProjectObjectsAccordionItem (objType); - - if (pai == null) - { - - return; - - } - - pai.update (); - - } - - public void showObjectInTree (String treeObjType, - NamedObject obj) - { - - JTree tree = this.getTreeForObjectType (treeObjType); - - if (tree == null) - { - - return; - - } - - DefaultTreeModel dtm = (DefaultTreeModel) tree.getModel (); - - DefaultMutableTreeNode root = (DefaultMutableTreeNode) dtm.getRoot (); - - tree.expandPath (UIUtils.getTreePathForUserObject (root, - obj)); - - } - - public JTree getTreeForObjectType (String objType) - { - - ProjectObjectsAccordionItem pai = this.getProjectObjectsAccordionItem (objType); - - if (pai == null) - { - - return null; - - } - - return pai.getTree (); - - } - - @Override - public String getSaveState () - { - - Map ss = new HashMap (); - - StringBuilder ats = new StringBuilder (); - - Set ais = this.getAccordionItems (); - - Map aisState = new LinkedHashMap (); - - Set aiIds = new LinkedHashSet (); - - ss.put ("ids", aiIds); - ss.put ("aistate", aisState); - - for (AccordionItem ai : ais) - { - - if (ai.getId () != null) - { - - aiIds.add (ai.getId ()); - - aisState.put (ai.getId (), - ai.getSaveState ()); - - } - - } - - try - { - - return JSONEncoder.encode (ss); - - } catch (Exception e) { - - Environment.logError ("Unable to encode state: " + - aisState, - e); - - return ""; - - } -/* - if (ai.isContentVisible ()) - { - - if (ats.length () > 0) - { - - ats.append ("|"); - - } - - ats.append (ai.getId ()); - - } - - } - - return ats.toString (); - */ - } - - public JComponent getContentBox () - { - - return this.contentBox; - - } - - public void addAccordionItem (AccordionItem item) - { - - this.addAccordionItem (item, - null); - - } - - private int getIndex (Component c) - { - - Component[] comps = this.contentBox.getComponents (); - - for (int i = 0; i < comps.length; i++) - { - - Component comp = comps[i]; - - if (c == comp) - { - - return i; - - } - - } - - return -1; - - } - - private void setSelected (AccordionItem it, - boolean val) - { - - Header h = it.getHeader (); - - if (!val) - { - - h.setTitleColor (UIUtils.getTitleColor ()); - h.setPaintProvider (new ColorPainter (UIUtils.getComponentColor ())); - - } else { - - h.setTitleColor (UIManager.getColor ("Tree.selectionForeground")); - h.setPaintProvider (new ColorPainter (UIManager.getColor ("Tree.selectionBackground"))); - - } - - this.validate (); - this.repaint (); - - } - - - public void addAccordionItem (final AccordionItem item, - final String belowObjType) - { - - int ind = -1; - - if (belowObjType != null) - { - - AccordionItem ai = this.getAccordionItemForObjectType (belowObjType); - - if (ai != null) - { - - ind = this.getIndex (ai); - - } - - } - - item.getHeader ().setPadding (new Insets (0, 0, 2, 0)); - item.getHeader ().getLabel ().setBorder (UIUtils.createPadding (0, 5, 0, 0)); - - item.setBorder (UIUtils.createPadding (0, 0, 3, 0)); - - if ((ind > -1) - && - (ind < this.contentBox.getComponentCount ()) - ) - { - - this.contentBox.add (item, - ind + 1); - - } else { - - this.contentBox.add (item); - - } - - final ProjectSideBar _this = this; - - // Used to initiate the drag. - MouseEventHandler listener = new MouseEventHandler () - { - - @Override - public void mouseDragged(MouseEvent e) - { - - JComponent c = (JComponent) e.getSource (); - TransferHandler handler = item.getTransferHandler (); - handler.setDragImage (UIUtils.getImageOfComponent (item.getHeader (), - item.getHeader ().getWidth (), - item.getHeader ().getHeight ())); - - handler.exportAsDrag (item, - e, - TransferHandler.MOVE); - - } - - }; - - // TODO: Make this a single instance. - TransferHandler transferHandler = new TransferHandler () - { - - private JComponent getParentOfType (JComponent comp, - Class cl) - { - - if (cl.isAssignableFrom (comp.getClass ())) - { - - return comp; - - } - - while ((comp = (JComponent) comp.getParent ()) != null) - { - - if (cl.isAssignableFrom (comp.getClass ())) - { - - return comp; - - } - - } - - return null; - - } - - private int getIndex (Component c) - { - - Component[] comps = _this.contentBox.getComponents (); - - for (int i = 0; i < comps.length; i++) - { - - Component comp = comps[i]; - - if (c == comp) - { - - return i; - - } - - } - - return -1; - - } - - @Override - public boolean canImport (TransferSupport support) - { - - if (!support.isDrop ()) - { - - return false; - } - - boolean canImport = support.isDataFlavorSupported (COMPONENT_FLAVOR); - - support.setShowDropLocation (false); - - return canImport; - } - - @Override - public boolean importData (TransferSupport support) - { - - if (!canImport (support)) - { - - return false; - } - - Component[] components; - - try - { - components = (Component[]) support.getTransferable ().getTransferData (COMPONENT_FLAVOR); - - } catch (Exception e) { - - return false; - } - - // Item being transfered. - final Component component = components[0]; - - AccordionItem it = (AccordionItem) this.getParentOfType ((JComponent) support.getComponent (), - AccordionItem.class); - - // Add the item below where we are. - int ind = this.getIndex (it); - - _this.contentBox.add (component, - ind); - - _this.contentBox.revalidate (); - _this.contentBox.repaint (); - - for (AccordionItem _it : _this.getAccordionItems ()) - { - - _this.setSelected (_it, - false); - - } - - UIUtils.doLater (new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - _this.contentBox.scrollRectToVisible (component.getBounds ()); - - } - - }); - - return true; - - } - /* - @Override - public java.awt.Image getDragImage () - { - - JComponent c = item.getHeader (); - - this.dragImage = UIUtils.getImageOfComponent (c, - c.getWidth (), - c.getHeight ()); - - return this.dragImage; - - } - */ - @Override - public int getSourceActions (JComponent c) - { - /* - c = item.getHeader (); - - this.dragImage = UIUtils.getImageOfComponent (c, - c.getWidth (), - c.getHeight ()); - - this.setDragImage (this.dragImage); - */ - return MOVE; - - } - - @Override - public Transferable createTransferable (final JComponent c) - { - - return new Transferable () - { - - @Override - public Object getTransferData (DataFlavor flavor) - { - - Component[] components = new Component[1]; - components[0] = c; - return components; - - } - - @Override - public DataFlavor[] getTransferDataFlavors() - { - - DataFlavor[] flavors = new DataFlavor[1]; - flavors[0] = COMPONENT_FLAVOR; - return flavors; - - } - - @Override - public boolean isDataFlavorSupported (DataFlavor flavor) - { - - return flavor.equals (COMPONENT_FLAVOR); - - } - - }; - } - - @Override - public void exportDone (JComponent c, - Transferable t, - int action) - { - - } - - }; - - DropTargetListener dropTargetListener = new DropTargetAdapter () - { - - @Override - public void dragOver (DropTargetDragEvent ev) - { - - java.awt.Point mp = _this.content.getMousePosition (); - - if (mp == null) - { - - return; - - } - - int a = _this.content.getVerticalScrollBar ().getUnitIncrement (); - - java.awt.Point vp = _this.content.getViewport ().getViewPosition (); - - if (mp.y <= 5 * a) - { - - int newy = vp.y - (a / 2); - - if (newy < 0) - { - - newy = 0; - - } - - _this.content.getViewport ().setViewPosition (new java.awt.Point (vp.x, newy)); - - return; - - } - - int h = _this.content.getViewport ().getExtentSize ().height; - - if (mp.y >= (h - (5 * a))) - { - - int newy = vp.y + (a / 2); - - if (newy > (vp.y + h)) - { - - newy = (vp.y + h); - - } - - _this.content.getViewport ().setViewPosition (new java.awt.Point (vp.x, newy)); - - return; - - } - - } - - @Override - public void drop (DropTargetDropEvent ev) - { - - for (AccordionItem it : _this.getAccordionItems ()) - { - - _this.setSelected (it, - false); - - } - - } - - @Override - public void dragEnter (DropTargetDragEvent ev) - { - - try - { - - if (ev.getTransferable ().getTransferData (COMPONENT_FLAVOR) == null) - { - - return; - - } - - } catch (Exception e) { - - return; - - } - - for (AccordionItem it : _this.getAccordionItems ()) - { - - _this.setSelected (it, - false); - - } - - //Point l = ev.getLocation (); - - AccordionItem it = (AccordionItem) ev.getDropTargetContext ().getComponent (); - - _this.setSelected (it, - true); - - } - - }; - - item.setTransferHandler (transferHandler); - - item.init (); - - item.getHeader ().addMouseMotionListener (listener); - - try - { - - item.getDropTarget ().addDropTargetListener (dropTargetListener); - item.getHeader ().getDropTarget ().addDropTargetListener (dropTargetListener); - item.getContent ().getDropTarget ().addDropTargetListener (dropTargetListener); - - } catch (Exception e) { - - } - - } - - private AssetAccordionItem getAssetAccordionItemForObjectType (UserConfigurableObjectType type) - { - - Component[] comps = this.contentBox.getComponents (); - - for (int i = 0; i < comps.length; i++) - { - - Component comp = comps[i]; - - if (comp instanceof AssetAccordionItem) - { - - AssetAccordionItem pi = (AssetAccordionItem) comp; - - if (pi.getUserConfigurableObjectType ().equals (type)) - { - - return pi; - - } - - } - - } - - return null; - - } - - private AccordionItem getAccordionItemForObjectType (String objType) - { - - Component[] comps = this.contentBox.getComponents (); - - for (int i = 0; i < comps.length; i++) - { - - Component comp = comps[i]; - - if (comp instanceof AccordionItem) - { - - AccordionItem pi = (AccordionItem) comp; - - if (pi.getId ().equals (objType)) - { - - return pi; - - } - - } - - } - - return null; - - } - - public void removeTagSection (Tag tag) - { - - this.removeSection (TaggedObjectAccordionItem.ID_PREFIX + tag.getKey ()); - - } - - public void removeSection (UserConfigurableObjectType objType) - { - - if (objType.isAssetObjectType ()) - { - - AssetAccordionItem aai = this.getAssetAccordionItemForObjectType (objType); - - if (aai != null) - { - - this.contentBox.remove (aai); - - this.validate (); - this.repaint (); - - } - - } - - } - - private void removeSection (String objType) - { - - AccordionItem ai = this.getAccordionItemForObjectType (objType); - - if (ai != null) - { - - this.contentBox.remove (ai); - - this.validate (); - this.repaint (); - - } - - } - - private Set getAccordionItems () - { - - Set ret = new LinkedHashSet (); - - Component[] comps = this.contentBox.getComponents (); - - for (int i = 0; i < comps.length; i++) - { - - Component comp = comps[i]; - - if (comp instanceof AccordionItem) - { - - AccordionItem pi = (AccordionItem) comp; - - ret.add (pi); - - } - - } - - return ret; - - } - - private void addAddSectionMenu (final JPopupMenu m, - final String belowObjType) - { - - final ProjectSideBar _this = this; - - if (m.getComponentCount () > 0) - { - - m.addSeparator (); - - } - - List prefix = new ArrayList (); - prefix.add (LanguageStrings.project); - prefix.add (LanguageStrings.sidebar); - prefix.add (LanguageStrings.headerpopupmenu); - prefix.add (LanguageStrings.items); - - m.add (UIUtils.createMenuItem (Environment.getUIString (prefix, - LanguageStrings.addtag), - //"Add/Manage the Tag(s)", - Constants.EDIT_ICON_NAME, - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - _this.viewer.showEditTags (); - - } - - })); - - m.add (UIUtils.createMenuItem (Environment.getUIString (prefix, - LanguageStrings.newobject), - //"Add new Type of Object", - Constants.NEW_ICON_NAME, - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - UIUtils.showAddNewObjectType (_this.viewer); - - } - - })); - - // Get all the sections currently not visible. - Set defSections = this.getSections (Constants.DEFAULT_PROJECT_SIDEBAR_SECTIONS_PROPERTY_NAME); - - // Get all the user asset types. - Set types = Environment.getAssetUserConfigurableObjectTypes (false); - - for (UserConfigurableObjectType t : types) - { - - defSections.add (t.getObjectTypeId ()); - - } - - Set tags = null; - - try - { - - tags = Environment.getAllTags (); - - } catch (Exception e) { - - tags = new HashSet (); - - Environment.logError ("Unable to get all tags", - e); - - } - - for (Tag t : tags) - { - - defSections.add (TaggedObjectAccordionItem.ID_PREFIX + t.getKey ()); - - } - - for (AccordionItem ai : this.getAccordionItems ()) - { - - defSections.remove (ai.getId ()); - - } - - if (defSections.size () > 0) - { - - JMenu sm = new JMenu (Environment.getUIString (prefix, - LanguageStrings.addsection, - (belowObjType != null ? LanguageStrings.below : LanguageStrings.normal))); - //"Add section" + (belowObjType != null ? " below" : "")); - - for (final String sect : defSections) - { - - // TODO: Need a better way to handle this. - String mName = this.getMenuNameForObjectType (sect); - - if (mName == null) - { - - continue; - - } - - sm.add (UIUtils.createMenuItem (Environment.replaceObjectNames (mName), - this.getMenuIconForObjectType (sect), - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - AccordionItem it = _this.createAccordionItemForObjectType (sect); - - _this.addAccordionItem (it, - belowObjType); - - _this.validate (); - _this.repaint (); - - if (belowObjType != null) - { - - // Scroll the item into view. - _this.contentBox.scrollRectToVisible (it.getBounds (null)); - - } - - } - - })); - - } - - // Only add the section menu if there are children. - if (sm.getMenuComponentCount () > 0) - { - - m.add (sm); - - } - - } - - } - - private void addHideSectionMenuItem (final JPopupMenu m, - final String objType) - { - - List prefix = new ArrayList (); - prefix.add (LanguageStrings.project); - prefix.add (LanguageStrings.sidebar); - prefix.add (LanguageStrings.headerpopupmenu); - prefix.add (LanguageStrings.items); - - final ProjectSideBar _this = this; - - m.add (UIUtils.createMenuItem (Environment.getUIString (prefix, - LanguageStrings.hidesection), - //"Hide this section", - Constants.CLOSE_ICON_NAME, - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - _this.removeSection (objType); - - } - - })); - - } - - private String getMenuNameForObjectType (String objType) - { - - String name = null; - int count = -1; - - if (objType.startsWith (TaggedObjectAccordionItem.ID_PREFIX)) - { - - long key = 0; - - try - { - - key = Long.parseLong (objType.substring (TaggedObjectAccordionItem.ID_PREFIX.length ())); - - } catch (Exception e) { - - // Ignore. - Environment.logError ("Unable to get key for: " + - objType, - e); - - return null; - - } - - Tag tag = null; - - try - { - - tag = Environment.getTagByKey (key); - - } catch (Exception e) { - - Environment.logError ("Unable to get type for: " + - key, - e); - - return null; - - } - - count = this.viewer.getProject ().getAllObjectsWithTag (tag).size (); - - name = tag.getName (); - - } - - if (ProjectEditor.OBJECT_TYPE.equals (objType)) - { - - name = "{Editors}"; - - Set eds = this.viewer.getProject ().getProjectEditors (); - - if (eds != null) - { - - count = eds.size (); - - } - - } - - if (Note.OBJECT_TYPE.equals (objType)) - { - - name = Environment.getObjectTypeNamePlural (objType); - - count = this.viewer.getProject ().getAllNamedChildObjects (Note.class).size (); - - } - - if (Chapter.OBJECT_TYPE.equals (objType)) - { - - UserConfigurableObjectType utype = Environment.getUserConfigurableObjectType (objType); - - name = utype.getObjectTypeNamePlural (); - - count = this.viewer.getProject ().getAllNamedChildObjects (Chapter.class).size (); - - } - - if (this.legacyAssetObjTypes.contains (objType)) - { - - UserConfigurableObjectType utype = Environment.getUserConfigurableObjectType (objType); - - if (utype == null) - { - - return null; - - } - - name = utype.getObjectTypeNamePlural (); - - count = this.viewer.getProject ().getAllNamedChildObjects (utype).size (); - - } - - if (objType.startsWith (AssetAccordionItem.ID_PREFIX)) - { - - long key = 0; - - try - { - - key = Long.parseLong (objType.substring (AssetAccordionItem.ID_PREFIX.length ())); - - } catch (Exception e) { - - // Ignore. - Environment.logError ("Unable to get key for: " + - objType, - e); - - return null; - - } - - UserConfigurableObjectType t = null; - - try - { - - t = Environment.getUserConfigurableObjectType (key); - - } catch (Exception e) { - - Environment.logError ("Unable to get type for: " + - key, - e); - - return null; - - } - - name = t.getObjectTypeNamePlural (); - - count = this.viewer.getProject ().getAllNamedChildObjects (t).size (); - - } - - if (count > -1) - { - - name = String.format ("%s (%s)", - name, - Environment.formatNumber (count)); - - } - - return name; - - } - - private ImageIcon getMenuIconForObjectType (String objType) - { - - if (objType.startsWith (TaggedObjectAccordionItem.ID_PREFIX)) - { - - objType = Constants.TAG_ICON_NAME; - - } - - if (objType.startsWith (AssetAccordionItem.ID_PREFIX)) - { - - long key = 0; - - try - { - - key = Long.parseLong (objType.substring (AssetAccordionItem.ID_PREFIX.length ())); - - } catch (Exception e) { - - // Ignore. - Environment.logError ("Unable to get key for: " + - objType, - e); - - return null; - - } - - UserConfigurableObjectType t = null; - - try - { - - t = Environment.getUserConfigurableObjectType (key); - - } catch (Exception e) { - - Environment.logError ("Unable to get type for: " + - key, - e); - - return null; - - } - - if (t != null) - { - - return t.getIcon16x16 (); - - } - - } - - if (ProjectEditor.OBJECT_TYPE.equals (objType)) - { - - objType = Constants.EDIT_ICON_NAME; - - } - - if (this.legacyAssetObjTypes.contains (objType)) - { - - return Environment.getUserConfigurableObjectType (objType).getIcon16x16 (); - - } - - return Environment.getIcon (objType, - Constants.ICON_MENU); - - } - - public AccordionItem createAssetAccordionItem (final UserConfigurableObjectType type) - { - - // Type can be null, i.e. it has been deleted elsewhere. - if (type == null) - { - - return null; - - } - - if (!type.isAssetObjectType ()) - { - - throw new IllegalArgumentException ("Type is not for assets: " + - type); - - } - - final ProjectSideBar _this = this; - - return new AssetAccordionItem (type, - this.viewer) - { - - @Override - public void fillHeaderPopupMenu (JPopupMenu m, - MouseEvent ev) - { - - super.fillHeaderPopupMenu (m, - ev); - - _this.addAddSectionMenu (m, - type.getObjectTypeId ()); - - _this.addHideSectionMenuItem (m, - type.getObjectTypeId ()); - - m.add (UIUtils.createMenuItem (String.format (Environment.getUIString (LanguageStrings.project, - LanguageStrings.sidebar, - LanguageStrings.assets, - LanguageStrings.headerpopupmenu, - LanguageStrings.items, - LanguageStrings.deleteall), - type.getObjectTypeNamePlural ()), - //"Delete all " + type.getObjectTypeNamePlural (), - Constants.DELETE_ICON_NAME, - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - new YesDeleteConfirmTextInputActionHandler (viewer, - null) - { - - @Override - public String getHelp () - { - - return String.format (Environment.getUIString (LanguageStrings.assets, - LanguageStrings.deleteall, - LanguageStrings.text), - type.getObjectTypeNamePlural ()); -/* - String.format ("To delete all %s please enter the word Yes into the box below.

    Warning! All %s you have created will be deleted and %s won't be available in your other {projects}.", - type.getObjectTypeNamePlural (), - type.getObjectTypeNamePlural (), - type.getObjectTypeNamePlural ()); - */ - } - - @Override - public String getDeleteType () - { - - return type.getObjectTypeNamePlural (); - - } - - public boolean onConfirm (String v) - throws Exception - { - - try - { - - _this.viewer.deleteAllAssetsOfType (type); - - } catch (Exception e) { - - Environment.logError ("Unable to remove all: " + - type, - e); - - UIUtils.showErrorMessage (_this.viewer, - getUIString (assets,deleteall,actionerror)); - //String.format ("Unable to remove all %1$s.", - // type.getObjectTypeNamePlural ())); - - return false; - - } - - try - { - - Environment.removeUserConfigurableObjectType (type); - - } catch (Exception e) { - - Environment.logError ("Unable to remove user object type: " + - type, - e); - - UIUtils.showErrorMessage (_this.viewer, - Environment.getUIString (LanguageStrings.assets, - LanguageStrings.deleteall, - LanguageStrings.actionerror)); - //"Unable to remove object."); - - return false; - - } - - _this.removeSection (type); - - return true; - - } - - }.actionPerformed (new ActionEvent (type, 1, "show")); - - } - - })); - - } - - }; - - } - - private AccordionItem createAccordionItemForObjectType (final String objType) - { - - final ProjectSideBar _this = this; - - if (objType.equals (Chapter.OBJECT_TYPE)) - { - - return new ChaptersAccordionItem (this.viewer) - { - - @Override - public void fillHeaderPopupMenu (JPopupMenu m, - MouseEvent ev) - { - - super.fillHeaderPopupMenu (m, - ev); - - _this.addHideSectionMenuItem (m, - objType); - - _this.addAddSectionMenu (m, - objType); - - } - - }; - - } - - if (objType.equals (ProjectEditor.OBJECT_TYPE)) - { - - return new ProjectEditorsAccordionItem (this.viewer) - { - - @Override - public void fillHeaderPopupMenu (JPopupMenu m, - MouseEvent ev) - { - - super.fillHeaderPopupMenu (m, - ev); - - _this.addHideSectionMenuItem (m, - objType); - - _this.addAddSectionMenu (m, - objType); - - } - - }; - - } - - if (objType.startsWith (TaggedObjectAccordionItem.ID_PREFIX)) - { - - long key = 0; - - try - { - - key = Long.parseLong (objType.substring (TaggedObjectAccordionItem.ID_PREFIX.length ())); - - } catch (Exception e) { - - // Ignore. - Environment.logError ("Unable to get key for: " + - objType, - e); - - return null; - - } - - Tag tag = null; - - try - { - - tag = Environment.getTagByKey (key); - - } catch (Exception e) { - - Environment.logError ("Unable to get type for: " + - key, - e); - - return null; - - } - - if (tag == null) - { - - return null; - - } - - return new TaggedObjectAccordionItem (tag, - this.viewer) - { - - @Override - public void fillHeaderPopupMenu (JPopupMenu m, - MouseEvent ev) - { - - super.fillHeaderPopupMenu (m, - ev); - - _this.addHideSectionMenuItem (m, - objType); - - _this.addAddSectionMenu (m, - objType); - - } - - }; - - } - - if (objType.startsWith (AssetAccordionItem.ID_PREFIX)) - { - - long key = 0; - - try - { - - key = Long.parseLong (objType.substring (AssetAccordionItem.ID_PREFIX.length ())); - - } catch (Exception e) { - - // Ignore. - Environment.logError ("Unable to get key for: " + - objType, - e); - - return null; - - } - - UserConfigurableObjectType t = null; - - try - { - - t = Environment.getUserConfigurableObjectType (key); - - } catch (Exception e) { - - Environment.logError ("Unable to get type for: " + - key, - e); - - return null; - - } - - if (t != null) - { - - return this.createAssetAccordionItem (t); - - } else { - - return null; - - } - - } - - // Pre-v2.6 - if (this.legacyAssetObjTypes.contains (objType)) - { - - return this.createAssetAccordionItem (Environment.getUserConfigurableObjectType (objType)); - - } - - if (objType.equals (Note.OBJECT_TYPE)) - { - - return new NotesAccordionItem (this.viewer) - { - - @Override - public void fillHeaderPopupMenu (JPopupMenu m, - MouseEvent ev) - { - - super.fillHeaderPopupMenu (m, - ev); - - _this.addHideSectionMenuItem (m, - objType); - - _this.addAddSectionMenu (m, - objType); - - } - - }; - - } - - return null; - - } - - private Set getSections (String propName) - { - - Set objTypes = new LinkedHashSet (); - - // Get the object types. - String v = UserProperties.get (propName); - - StringTokenizer t = new StringTokenizer (v, - "|"); - - while (t.hasMoreTokens ()) - { - - objTypes.add (t.nextToken ().trim ()); - - } - - return objTypes; - - } - - @Override - public void init (String saveState) - throws GeneralException - { - - super.init (saveState); - - if (saveState != null) - { - - Map stateO = (Map) JSONDecoder.decode (saveState); - - Collection aiIds = (Collection) stateO.get ("ids"); - - if (aiIds == null) - { - - aiIds = this.getSections (Constants.DEFAULT_PROJECT_SIDEBAR_SECTIONS_PROPERTY_NAME); - - } - - Map aiState = (Map) stateO.get ("aistate"); - - if (aiState == null) - { - - aiState = new HashMap (); - - } - - for (String aiId : aiIds) - { - - String state = (String) aiState.get (aiId); - - AccordionItem it = this.createAccordionItemForObjectType (aiId); - - if (it == null) - { - - continue; - - } - - this.addAccordionItem (it); - - if (state != null) - { - - it.initFromSaveState (state); - - } - - } - - } else { - - for (String objType : this.getSections (Constants.DEFAULT_PROJECT_SIDEBAR_SECTIONS_PROPERTY_NAME)) - { - - AccordionItem it = this.createAccordionItemForObjectType (objType); - - if (it == null) - { - - continue; - - } - - this.addAccordionItem (it); - - } - - } - - /* - for (String objType : this.getSections (Constants.PROJECT_SIDEBAR_SECTIONS_PROPERTY_NAME)) - { - - AccordionItem it = this.createAccordionItemForObjectType (objType); - - if (it == null) - { - - continue; - - } - - this.addAccordionItem (it); - - } -*/ - } - - public void setObjectsOpen (String objType) - { - - AccordionItem ai = this.getAccordionItemForObjectType (objType); - - if (ai == null) - { - - return; - - } - - ai.setContentVisible (true); - - } - /* - public void initOpenObjectTypes (final Set types) - { - - Set ais = this.getAccordionItems (); - - for (AccordionItem ai : ais) - { - - ai.setContentVisible (types.contains (ai.getId ())); - - } - - } - */ - @Override - public String getId () - { - - return "project"; - - } - -} diff --git a/src/com/quollwriter/ui/sidebars/TextPropertiesSideBar.java b/src/com/quollwriter/ui/sidebars/TextPropertiesSideBar.java deleted file mode 100644 index ba1faa4c..00000000 --- a/src/com/quollwriter/ui/sidebars/TextPropertiesSideBar.java +++ /dev/null @@ -1,286 +0,0 @@ -package com.quollwriter.ui.sidebars; - -import java.awt.Cursor; -import java.awt.Rectangle; -import java.awt.Dimension; -import java.awt.Point; -import java.awt.Color; -import java.awt.Toolkit; -import java.awt.Graphics; -import java.awt.Graphics2D; -import java.awt.Paint; -import java.awt.TexturePaint; -import java.awt.Component; -import java.awt.Image; -import java.awt.RenderingHints; - -import java.util.Map; -import java.util.HashMap; -import java.util.List; -import java.util.ArrayList; - -import java.io.*; - -import java.awt.event.*; - -import java.awt.image.*; - -import javax.swing.*; -import javax.swing.event.*; -import javax.swing.border.*; - -import com.jgoodies.forms.builder.*; -import com.jgoodies.forms.factories.*; -import com.jgoodies.forms.layout.*; - -import com.gentlyweb.properties.*; - -import com.quollwriter.*; -import com.quollwriter.data.*; -import com.quollwriter.events.*; -import com.quollwriter.ui.*; - -import com.quollwriter.ui.components.ActionAdapter; -import com.quollwriter.ui.components.ImagePanel; -import com.quollwriter.ui.components.QTextEditor; -import com.quollwriter.ui.components.QPopup; -import com.quollwriter.ui.components.ChangeAdapter; -import com.quollwriter.ui.components.TextProperties; - -import static com.quollwriter.LanguageStrings.*; -import static com.quollwriter.Environment.getUIString; - -public class TextPropertiesSideBar extends AbstractSideBar implements MainPanelListener, FullScreenListener -{ - - public static final String ID = "textproperties"; - - private TextPropertiesEditPanel props = null; - private FullScreenPropertiesEditPanel fsprops = null; - - public TextPropertiesSideBar (AbstractProjectViewer pv, - PopupsSupported popupParent, - TextProperties props) - { - - super (pv); - - this.fsprops = new FullScreenPropertiesEditPanel (); - - final TextPropertiesSideBar _this = this; - - this.props = new TextPropertiesEditPanel (pv, - props, - ProjectEvent.TEXT_PROPERTIES, - true, - popupParent) - { - - public void setBackgroundColor (Color c) - { - - //_this.fsTextProps.setBackgroundColor (c); - - _this.fsprops.setBackgroundColor (c); - - } - - }; - - pv.addFullScreenListener (this); - - } - - @Override - public String getId () - { - - return ID; - - } - - @Override - public void fullScreenExited (FullScreenEvent ev) - { - - this.onShow (); - - /* - this.setTitle (this.getTitle ()); - - UserProperties.removeListener (this.fsTextProps); - - // Add the listener last so that if we get an update nothing will NPE. - UserProperties.addListener (this.props); - - this.props.setVisible (true); - - this.fsTextProps.setVisible (false); - - this.fsprops.setVisible (false); - */ - } - - @Override - public void fullScreenEntered (FullScreenEvent ev) - { - - this.onShow (); - - /* - this.setTitle ("Full Screen Properties"); - - final TextPropertiesSideBar _this = this; - - UserProperties.removeListener (this.props); - - FullScreenFrame fsf = this.viewer.getFullScreenFrame (); - - UserProperties.addListener (this.fsTextProps); - - this.props.setVisible (false); - this.fsprops.setFullScreenFrame (fsf); - - this.fsTextProps.setVisible (true); - this.fsprops.setVisible (true); - - this.validate (); - this.repaint (); - */ - } - - /** - * Always pref width, 250. - */ - @Override - public Dimension getMinimumSize () - { - - return new Dimension (this.getPreferredSize ().width, - 250); - } - - @Override - public List getHeaderControls () - { - - return null; - - } - - public boolean canClose () - { - - return true; - - } - - public String getIconType () - { - - return Constants.SETTINGS_ICON_NAME; - - } - - @Override - public void onHide () - { - - - - } - - @Override - public void onShow () - { - - if (this.viewer.isInFullScreen ()) - { - - this.setTitle (getUIString (project,sidebar,textproperties,fullscreentitle)); - //"Full Screen Properties"); - - UserProperties.removeListener (this.props); - - this.props.setTextProperties (Environment.getFullScreenTextProperties ()); - - UserProperties.addListener (this.props); - - FullScreenFrame fsf = this.viewer.getFullScreenFrame (); - - this.fsprops.setFullScreenFrame (fsf); - - this.fsprops.setVisible (true); - - } else { - - UserProperties.removeListener (this.props); - - this.props.setTextProperties (Environment.getProjectTextProperties ()); - - UserProperties.addListener (this.props); - - this.setTitle (this.getTitle ()); - - this.fsprops.setVisible (false); - - } - - this.validate (); - this.repaint (); - - - } - - @Override - public void onClose () - { - - UserProperties.removeListener (this.props); - - this.viewer.removeFullScreenListener (this); - - } - - public String getTitle () - { - - return getUIString (project,sidebar,textproperties,title); - //"Text Properties"; - - } - - @Override - public void init (String saveState) - throws GeneralException - { - - super.init (saveState); - - } - - public void panelShown (MainPanelEvent ev) - { - - } - - public JComponent getContent () - { - - Box b = new Box (BoxLayout.Y_AXIS); - - this.fsprops.setBorder (UIUtils.createPadding (0, 0, 10, 0)); - - b.add (this.fsprops); - - b.add (this.props); - - this.props.init (); - - UserProperties.addListener (this.props); - - return this.wrapInScrollPane (b); - - } - -} diff --git a/src/com/quollwriter/ui/sidebars/WordCountsSideBar.java b/src/com/quollwriter/ui/sidebars/WordCountsSideBar.java deleted file mode 100644 index 691a07ac..00000000 --- a/src/com/quollwriter/ui/sidebars/WordCountsSideBar.java +++ /dev/null @@ -1,1227 +0,0 @@ -package com.quollwriter.ui.sidebars; - -import java.awt.Dimension; -import java.awt.Component; -import java.awt.Font; -import java.awt.event.*; - -import javax.swing.*; -import javax.swing.border.*; -import javax.swing.event.*; - -import java.util.List; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.Date; -import java.util.Set; - -import com.jgoodies.forms.builder.*; -import com.jgoodies.forms.factories.*; -import com.jgoodies.forms.layout.*; - -import com.quollwriter.data.*; -import com.quollwriter.*; -import com.quollwriter.ui.*; -import com.quollwriter.ui.charts.*; -import com.quollwriter.ui.panels.*; -import com.quollwriter.db.*; -import com.quollwriter.events.*; -import com.quollwriter.ui.components.ChangeAdapter; -import com.quollwriter.ui.components.Header; - -import static com.quollwriter.LanguageStrings.*; -import static com.quollwriter.Environment.getUIString; - -public class WordCountsSideBar extends AbstractSideBar -{ - - public static final String ID = "wordcounts"; - - private final String COL_SPEC = "right:max(80px;p), 6px, p:grow"; - - private JLabel projectSessionWordCount = null; - private JLabel totalSessionWordCount = null; - private JLabel chapterWordCount = null; - private JLabel chapterPages = null; - private JLabel allChaptersWordCount = null; - private JLabel allChaptersPages = null; - private Timer timer = null; - private AccordionItem chapterItem = null; - private AccordionItem selectedItems = null; - private JComponent chapterSparkLine = null; - private JLabel chapterSparkLineLabel = null; - private JLabel selectedWordCount = null; - private JLabel chapterFleschKincaid = null; - private JLabel chapterGunningFog = null; - private JLabel chapterFleschReadingEase = null; - private JLabel allChaptersFleschKincaid = null; - private JLabel allChaptersGunningFog = null; - private JLabel allChaptersFleschReadingEase = null; - private JLabel selectedFleschKincaid = null; - private JLabel selectedFleschReadingEase = null; - private JLabel selectedGunningFog = null; - private JComponent selectedReadability = null; - private JComponent allReadability = null; - private JComponent chapterReadability = null; - private JComponent selectedReadabilityHeader = null; - private JComponent allReadabilityHeader = null; - private JComponent chapterReadabilityHeader = null; - private JLabel editPointWordCount = null; - private Box chapterEditPointBox = null; - private Box allChaptersEditPointBox = null; - private JLabel allEditPointWordCount = null; - private JLabel allChaptersEditCount = null; - - public WordCountsSideBar (AbstractProjectViewer v) - { - - super (v); - - } - - @Override - public String getId () - { - - return ID; - - } - - @Override - public boolean canClose () - { - - return true; - - } - - /** - * Start the timer and call {@link update()} later. - */ - @Override - public void onShow () - { - - final WordCountsSideBar _this = this; - - if (this.timer == null) - { - - this.timer = new Timer (2 * Constants.SEC_IN_MILLIS, - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - _this.update (); - - } - - }); - - } - - // Start the timer. - this.timer.start (); - - UIUtils.doLater (new ActionListener () - { - - public void actionPerformed (ActionEvent ev) - { - - _this.update (); - - } - - }); - - } - - @Override - public void onHide () - { - - this.timer.stop (); - - } - - /** - * Stop the timer, we don't set the timer to null since {@link removeOnClose()} is false. - */ - @Override - public void onClose () - { - - // Pause the timer. - this.timer.stop (); - - this.timer = null; - - } - - /** - * Always return false, we want to keep the counts around since it's a labour intensive thing. - * - * @returns Always false. - */ - public boolean removeOnClose () - { - - return false; - - } - - public String getIconType () - { - - return Constants.WORDCOUNT_ICON_NAME; - - } - - public String getTitle () - { - - return Environment.getUIString (LanguageStrings.project, - LanguageStrings.sidebar, - LanguageStrings.wordcount, - LanguageStrings.title); - //return "Word Counts"; - - } - - @Override - public void panelShown (MainPanelEvent ev) - { - /* - if (ev.getPanel () instanceof AbstractEditorPanel) - { - - this.chapterItem.setVisible (true); - this.chapterSparkLine.removeAll (); - - } else { - - this.chapterItem.setVisible (false); - - } -*/ - this.update (); - - } - - private void update () - { - - if (!this.isVisible ()) - { - - return; - - } - - if (this.timer == null) - { - - // Probably closing down. - return; - - } - - ChapterCounts achc = this.viewer.getAllChapterCounts (); - - // When shutting down we may get a null back, just return. - if (achc == null) - { - - this.timer.stop (); - - this.timer = null; - - return; - - } - - java.util.List prefix = new ArrayList<> (); - prefix.add (LanguageStrings.project); - prefix.add (LanguageStrings.sidebar); - prefix.add (LanguageStrings.wordcount); - - String valueperc = Environment.getUIString (prefix, - LanguageStrings.valuepercent); - - this.projectSessionWordCount.setText (Environment.formatNumber (this.viewer.getSessionWordCount ())); - this.totalSessionWordCount.setText (Environment.formatNumber ((Environment.getSessionWordCount ())));//achc.wordCount - this.viewer.getStartWordCounts ().wordCount))); - - final Chapter c = this.viewer.getChapterCurrentlyEdited (); - - if (c != null) - { - - AbstractEditorPanel qep = this.viewer.getEditorForChapter (c); - - String sel = qep.getEditor ().getSelectedText (); - - this.selectedItems.setVisible (false); - this.selectedReadability.setVisible (false); - this.selectedReadabilityHeader.setVisible (false); - - if (!sel.equals ("")) - { - - ChapterCounts sc = new ChapterCounts (sel); - - this.selectedWordCount.setText (Environment.formatNumber (sc.wordCount)); - - this.selectedItems.setVisible (true); - - if ((sc.wordCount > Constants.MIN_READABILITY_WORD_COUNT) - && - (this.viewer.isLanguageEnglish ()) - ) - { - - // Show the readability. - this.selectedReadability.setVisible (true); - this.selectedReadabilityHeader.setVisible (true); - - ReadabilityIndices ri = this.viewer.getReadabilityIndices (sel); - - this.selectedFleschKincaid.setText (Environment.formatNumber (Math.round (ri.getFleschKincaidGradeLevel ()))); - - this.selectedGunningFog.setText (Environment.formatNumber (Math.round (ri.getGunningFogIndex ()))); - - this.selectedFleschReadingEase.setText (Environment.formatNumber (Math.round (ri.getFleschReadingEase ()))); - - } - - } - - //int a4Count = 0; //this.viewer.getChapterA4PageCount (c); - - ChapterCounts chc = this.viewer.getChapterCounts (c); - - this.chapterEditPointBox.setVisible (false); - - if ((c.getEditPosition () > 0) - && - (chc != null) - ) - { - - // Get the text. - String editText = qep.getEditor ().getText ().substring (0, c.getEditPosition ()); - - if (editText.trim ().length () > 0) - { - - ChapterCounts sc = new ChapterCounts (editText); - - this.editPointWordCount.setText (String.format (valueperc, - Environment.formatNumber (sc.wordCount), - Environment.formatNumber (Environment.getPercent (sc.wordCount, chc.wordCount)))); - - this.chapterEditPointBox.setVisible (true); - - } - - } - - if (chc != null) - { - - this.chapterWordCount.setText (String.format (valueperc, - Environment.formatNumber (chc.wordCount), - Environment.formatNumber (Environment.getPercent (chc.wordCount, achc.wordCount)))); - - this.chapterPages.setText (Environment.formatNumber (chc.standardPageCount)); - - this.chapterReadability.setVisible (false); - this.chapterReadabilityHeader.setVisible (false); - - if ((this.viewer.isLanguageEnglish ()) - && - (chc.wordCount >= Constants.MIN_READABILITY_WORD_COUNT) - ) - { - - this.chapterReadability.setVisible (true); - this.chapterReadabilityHeader.setVisible (true); - - ReadabilityIndices ri = this.viewer.getReadabilityIndices (c); - - this.chapterFleschKincaid.setText (Environment.formatNumber (Math.round (ri.getFleschKincaidGradeLevel ()))); - - this.chapterGunningFog.setText (Environment.formatNumber (Math.round (ri.getGunningFogIndex ()))); - - this.chapterFleschReadingEase.setText (Environment.formatNumber (Math.round (ri.getFleschReadingEase ()))); - - } - - this.chapterItem.setTitle (qep.getTitle ()); - - this.chapterItem.setVisible (true); - - if (this.chapterSparkLine.getComponents ().length == 0) - { - - try - { - - ChapterDataHandler dh = (ChapterDataHandler) this.viewer.getDataHandler (Chapter.class); - - // TODO: Find a better way of handling this. - if (dh != null) - { - - org.jfree.data.time.TimeSeries ts = new org.jfree.data.time.TimeSeries (c.getName ()); - - int diff = 0; - - int min = Integer.MAX_VALUE; - int max = Integer.MIN_VALUE; - - // Get all the word counts for the chapter. - java.util.List wordCounts = dh.getWordCounts (c, - -7); - - if (wordCounts.size () == 0) - { - - wordCounts.add (new WordCount (chc.wordCount, - null, - Environment.zeroTimeFieldsForDate (new Date ()))); - - } - - // Expand the dates back if necessary. - if (wordCounts.size () == 1) - { - - // Get a date for 7 days ago. - Date d = new Date (System.currentTimeMillis () - (7 * 24 * 60 * 60 * 1000)); - - wordCounts.add (0, - new WordCount (chc.wordCount, - null, - Environment.zeroTimeFieldsForDate (d))); - - } - - for (WordCount wc : wordCounts) - { - - int count = wc.getCount (); - - min = Math.min (min, - count); - max = Math.max (max, - count); - - try - { - - ts.add (new org.jfree.data.time.Day (wc.getEnd ()), - count); - - } catch (Exception e) { - - // Ignore, trying to add a duplicate day. - - } - - } - - diff = max - min; - - int wordDiff = diff; - - if (diff == 0) - { - - diff = 100; - - } - - if ((min < Integer.MAX_VALUE) || - (max > Integer.MIN_VALUE)) - { - - this.chapterSparkLineLabel.setText (String.format (Environment.getUIString (prefix, - LanguageStrings.labels, - LanguageStrings.sparkline),//"past 7 days, %s%s words", - Environment.formatNumber (7), - (wordDiff == 0 ? "" : (wordDiff > 0 ? "+" : "")), - Environment.formatNumber (wordDiff))); - - org.jfree.chart.ChartPanel cp = new org.jfree.chart.ChartPanel (QuollChartUtils.createSparkLine (ts, - max + (diff / 2), - min - (diff / 2))); - - //cp.setToolTipText ("Word count activity for the past 7 days"); - - cp.setMaximumSize (new Dimension (Short.MAX_VALUE, - 16)); - cp.setPreferredSize (new Dimension (60, - 16)); - this.chapterSparkLine.add (cp); - - } - - } - - } catch (Exception e) - { - - Environment.logError ("Unable to generate 7 day activity sparkline", - e); - - } - - } - - } - - } else { - - this.chapterItem.setVisible (false); - - } - - this.allReadability.setVisible (false); - this.allReadabilityHeader.setVisible (false); - - if ((this.viewer.isLanguageEnglish ()) - && - (achc.wordCount >= Constants.MIN_READABILITY_WORD_COUNT) - ) - { - - this.allReadability.setVisible (true); - this.allReadabilityHeader.setVisible (true); - - ReadabilityIndices ri = this.viewer.getAllReadabilityIndices (); - - this.allChaptersFleschKincaid.setText (Environment.formatNumber (Math.round (ri.getFleschKincaidGradeLevel ()))); - - this.allChaptersFleschReadingEase.setText (Environment.formatNumber (Math.round (ri.getFleschReadingEase ()))); - - this.allChaptersGunningFog.setText (Environment.formatNumber (Math.round (ri.getGunningFogIndex ()))); - - } - - this.allChaptersWordCount.setText (Environment.formatNumber (achc.wordCount)); - - this.allChaptersPages.setText (Environment.formatNumber (achc.standardPageCount)); //this.viewer.getAllChaptersA4PageCount ())); - - this.allChaptersEditPointBox.setVisible (false); - - final StringBuilder buf = new StringBuilder (); - - Set chapters = this.viewer.getProject ().getAllNamedChildObjects (Chapter.class); - - int editComplete = 0; - - for (NamedObject n : chapters) - { - - Chapter nc = (Chapter) n; - - if (nc.getEditPosition () > 0) - { - - if (buf.length () > 0) - { - - buf.append (" "); - - } - - AbstractEditorPanel pan = this.viewer.getEditorForChapter (nc); - - String t = null; - - if (pan != null) - { - - t = pan.getEditor ().getText (); - - } else { - - t = nc.getChapterText (); - - } - - if (nc.getEditPosition () <= t.length ()) - { - - buf.append (t.substring (0, - nc.getEditPosition ())); - - } - - } - - if (nc.isEditComplete ()) - { - - editComplete++; - - } - - } - - String allEditText = buf.toString ().trim (); - - if (buf.length () > 0) - { - - ChapterCounts allc = new ChapterCounts (buf.toString ()); - - this.allEditPointWordCount.setText (String.format (valueperc, - Environment.formatNumber (allc.wordCount), - Environment.formatNumber (Environment.getPercent (allc.wordCount, achc.wordCount)))); - - this.allChaptersEditCount.setText (String.format (valueperc, - Environment.formatNumber (editComplete), - Environment.formatNumber (Environment.getPercent (editComplete, chapters.size ())))); - - this.allChaptersEditPointBox.setVisible (true); - - } - - } - - private JComponent getWords (JLabel wordCount, - JLabel pagesCount, - JComponent cp, - JLabel sparkLineLabel, - int wordCountDiff, - int days) - { - - java.util.List prefix = new ArrayList<> (); - prefix.add (LanguageStrings.project); - prefix.add (LanguageStrings.sidebar); - prefix.add (LanguageStrings.wordcount); - prefix.add (LanguageStrings.labels); - - String cols = COL_SPEC; - - String rows = "p, 6px, p, 6px, p"; - - FormLayout fl = new FormLayout (cols, - rows); - PanelBuilder b = new PanelBuilder (fl); - b.border (Borders.DIALOG); - - CellConstraints cc = new CellConstraints (); - - wordCount.setFont (wordCount.getFont ().deriveFont (Font.BOLD)); - - b.add (wordCount, - cc.xy (1, 1)); - - b.addLabel (Environment.getUIString (prefix, - LanguageStrings.words), - //"words", - cc.xy (3, 1)); - - pagesCount.setFont (pagesCount.getFont ().deriveFont (Font.BOLD)); - - b.add (pagesCount, - cc.xy (1, 3)); - - b.addLabel (Environment.getUIString (prefix, - LanguageStrings.a4pages), - //"A4 pages", - cc.xy (3, 3)); - - String sl = Environment.getUIString (prefix, - LanguageStrings.sparkline); - - sparkLineLabel.setText (String.format (sl, - Environment.formatNumber (days), - (wordCountDiff > 0 ? "+" : (wordCountDiff == 0 ? "" : "-")), - Environment.formatNumber (wordCountDiff))); - //"past " + days + " days" + diff); - - b.add (sparkLineLabel, - cc.xy (3, 5)); - - b.add (cp, - cc.xywh (1, 5, 1, 1)); - - JPanel p = b.getPanel (); - p.setOpaque (false); - p.setBorder (new EmptyBorder (10, 10, 10, 10)); - p.setAlignmentX (Component.LEFT_ALIGNMENT); - - return p; - - } - - private JComponent getReadability (JLabel fleschKincaid, - JLabel fleschReading, - JLabel gunningFog) - { - - java.util.List prefix = new ArrayList<> (); - prefix.add (LanguageStrings.project); - prefix.add (LanguageStrings.sidebar); - prefix.add (LanguageStrings.wordcount); - prefix.add (LanguageStrings.labels); - - String cols = COL_SPEC; - - String rows = "p, 6px, p, 6px, p"; - - FormLayout fl = new FormLayout (cols, - rows); - PanelBuilder b = new PanelBuilder (fl); - b.border (Borders.DIALOG); - - CellConstraints cc = new CellConstraints (); - /* - b.addLabel ("F-K", - cc.xy (1, - 1)); - b.addLabel ("FR", - cc.xy (3, - 1)); - b.addLabel ("GF", - cc.xy (5, - 1)); - */ - - fleschKincaid.setFont (fleschKincaid.getFont ().deriveFont (Font.BOLD)); - - b.add (fleschKincaid, - cc.xy (1, 1)); - - b.addLabel (Environment.getUIString (prefix, - LanguageStrings.fk), - //"Flesch-Kincaid", - cc.xy (3, 1)); - - fleschReading.setFont (fleschReading.getFont ().deriveFont (Font.BOLD)); - - b.add (fleschReading, - cc.xy (1, 3)); - - b.addLabel (Environment.getUIString (prefix, - LanguageStrings.fr), - //"Flesch Reading", - cc.xy (3, 3)); - - gunningFog.setFont (gunningFog.getFont ().deriveFont (Font.BOLD)); - - b.add (gunningFog, - cc.xy (1, 5)); - - b.addLabel (Environment.getUIString (prefix, - LanguageStrings.gf), - //"Gunning Fog", - cc.xy (3, 5)); - - JPanel p = b.getPanel (); - p.setOpaque (false); - p.setBorder (UIUtils.createPadding (10, 10, 10, 10)); - p.setAlignmentX (Component.LEFT_ALIGNMENT); - - return p; - - } - - public List getHeaderControls () - { - - final WordCountsSideBar _this = this; - - List buts = new ArrayList (); - - JButton b = UIUtils.createButton ("chart", - Constants.ICON_SIDEBAR, - Environment.getUIString (LanguageStrings.project, - LanguageStrings.sidebar, - LanguageStrings.wordcount, - LanguageStrings.headercontrols, - LanguageStrings.items, - LanguageStrings.statistics, - LanguageStrings.tooltip), - //"Click to view the detail", - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - _this.viewer.viewStatistics (); - - } - - }); - - buts.add (b); - - return buts; - - } - - @Override - public Dimension getMinimumSize () - { - - return new Dimension (260, - 250); - } - - public JComponent getContent () - { - - java.util.List prefix = new ArrayList<> (); - prefix.add (LanguageStrings.project); - prefix.add (LanguageStrings.sidebar); - prefix.add (LanguageStrings.wordcount); - - final WordCountsSideBar _this = this; - - Box box = new Box (BoxLayout.Y_AXIS); - - final Chapter c = this.viewer.getChapterCurrentlyEdited (); - - this.projectSessionWordCount = UIUtils.createInformationLabel (null); - this.totalSessionWordCount = UIUtils.createInformationLabel (null); - this.chapterWordCount = UIUtils.createInformationLabel (null); - this.chapterPages = UIUtils.createInformationLabel (null); - this.allChaptersWordCount = UIUtils.createInformationLabel (null); - this.allChaptersPages = UIUtils.createInformationLabel (null); - this.selectedWordCount = UIUtils.createInformationLabel (null); - this.chapterSparkLine = new Box (BoxLayout.X_AXIS); - this.chapterSparkLine.setOpaque (false); - this.chapterSparkLineLabel = UIUtils.createInformationLabel (null); - this.selectedFleschKincaid = UIUtils.createInformationLabel (null); - this.selectedFleschReadingEase = UIUtils.createInformationLabel (null); - this.selectedGunningFog = UIUtils.createInformationLabel (null); - this.editPointWordCount = UIUtils.createInformationLabel (null); - this.allEditPointWordCount = UIUtils.createInformationLabel (null); - this.allChaptersEditCount = UIUtils.createInformationLabel (null); - - List items = new ArrayList (); - - items.add (this.getItem ("words", - this.selectedWordCount)); - - this.selectedReadabilityHeader = this.createSubHeader (Environment.getUIString (prefix, - LanguageStrings.labels, - LanguageStrings.readability)); - //"Readability"); - - items.add (this.selectedReadabilityHeader); - - this.selectedReadability = this.getReadability (this.selectedFleschKincaid, - this.selectedFleschReadingEase, - this.selectedGunningFog); - - items.add (this.selectedReadability); - - this.selectedItems = this.getItems (Environment.getUIString (prefix, - LanguageStrings.sectiontitles, - LanguageStrings.selected), - //"Selected text", - Constants.EDIT_ICON_NAME, - items); - - this.selectedItems.setVisible (false); - - box.add (this.selectedItems); - - items = new ArrayList (); - - items.add (this.getItem (Environment.getUIString (prefix, - LanguageStrings.labels, - LanguageStrings.projectwords), - this.projectSessionWordCount)); - - items.add (this.getItem (Environment.getUIString (prefix, - LanguageStrings.labels, - LanguageStrings.totalwords), - //"words, total", - this.totalSessionWordCount)); - - AccordionItem it = this.getItems (getUIString (prefix,sectiontitles,session), - //"This session", - Constants.CLOCK_ICON_NAME, - items); - - box.add (it); - - items = new ArrayList (); - - items.add (this.getWords (this.chapterWordCount, - this.chapterPages, - this.chapterSparkLine, - this.chapterSparkLineLabel, - 0, - 7)); - - this.chapterEditPointBox = new Box (BoxLayout.Y_AXIS); - - items.add (this.chapterEditPointBox); - - this.chapterEditPointBox.add (this.createSubHeader (Environment.getUIString (prefix, - LanguageStrings.labels, - LanguageStrings.edited))); - //"Edited")); - - this.chapterEditPointBox.add (this.getItem (Environment.getUIString (prefix, - LanguageStrings.labels, - LanguageStrings.words), - //"words", - this.editPointWordCount)); - - //this.chapterEditPointBox.setVisible (false); - - UIUtils.setPadding (this.chapterEditPointBox, 0, 0, 10, 0); - - this.chapterFleschKincaid = UIUtils.createInformationLabel (null); - this.chapterFleschReadingEase = UIUtils.createInformationLabel (null); - this.chapterGunningFog = UIUtils.createInformationLabel (null); - - this.chapterReadabilityHeader = this.createSubHeader (getUIString (prefix,labels,readability)); - //"Readability"); - - items.add (this.chapterReadabilityHeader); - - this.chapterReadability = this.getReadability (this.chapterFleschKincaid, - this.chapterFleschReadingEase, - this.chapterGunningFog); - - items.add (this.chapterReadability); - - this.chapterItem = this.getItems ("", - Chapter.OBJECT_TYPE, - items); - - if (c == null) - { - - this.chapterItem.setVisible (false); - - } - - box.add (this.chapterItem); - - items = new ArrayList (); - - JComponent sparkLine = new JPanel (); - sparkLine.setBorder (null); - sparkLine.setOpaque (false); - - int wordCountDiff30 = 0; - - try - { - - ProjectDataHandler dh = (ProjectDataHandler) this.viewer.getDataHandler (Project.class); - - // TODO: Find a better way of handling this. - if (dh != null) - { - - org.jfree.data.time.TimeSeries ts = new org.jfree.data.time.TimeSeries ("All"); - - int diff = 0; - - int min = Integer.MAX_VALUE; - int max = Integer.MIN_VALUE; - - // Get all the word counts for the project. - java.util.List wordCounts = dh.getWordCounts (this.viewer.getProject (), - -30); - - for (WordCount wc : wordCounts) - { - - int count = wc.getCount (); - - min = Math.min (min, - count); - max = Math.max (max, - count); - - ts.add (new org.jfree.data.time.Day (wc.getEnd ()), - count); - - } - - diff = max - min; - - if (diff == 0) - { - - diff = 100; - - } - - if ((min < Integer.MAX_VALUE) || - (max > Integer.MIN_VALUE)) - { - - wordCountDiff30 = max - min; - - org.jfree.chart.ChartPanel cp = new org.jfree.chart.ChartPanel (QuollChartUtils.createSparkLine (ts, - max + (diff / 2), - min - (diff / 2))); - - //cp.setToolTipText ("Word count activity for the past 30 days"); - cp.setMaximumSize (new Dimension (60, - 16)); - cp.setPreferredSize (new Dimension (60, - 16)); - - sparkLine = cp; - - } - - } - - } catch (Exception e) - { - - Environment.logError ("Unable to generate 30 day activity sparkline", - e); - - } - - items.add (this.getWords (this.allChaptersWordCount, - this.allChaptersPages, - sparkLine, - UIUtils.createInformationLabel (null), - wordCountDiff30, - 30)); - - this.allChaptersFleschKincaid = UIUtils.createInformationLabel (null); - this.allChaptersFleschReadingEase = UIUtils.createInformationLabel (null); - this.allChaptersGunningFog = UIUtils.createInformationLabel (null); - - this.allChaptersEditPointBox = new Box (BoxLayout.Y_AXIS); - - items.add (this.allChaptersEditPointBox); - - this.allChaptersEditPointBox.add (this.createSubHeader (Environment.getUIString (prefix, - LanguageStrings.labels, - LanguageStrings.edited))); - //"Edited")); - - this.allChaptersEditPointBox.add (this.getItem (Environment.getUIString (prefix, - LanguageStrings.labels, - LanguageStrings.words), - //"words", - this.allEditPointWordCount)); - - this.allChaptersEditPointBox.add (this.getItem (Environment.getUIString (prefix, - LanguageStrings.labels, - LanguageStrings.chapters), - //"{chapters}", - this.allChaptersEditCount)); - - this.allChaptersEditPointBox.setVisible (false); - - this.allChaptersEditPointBox.setBorder (new EmptyBorder (0, 0, 10, 0)); - - this.allReadabilityHeader = this.createSubHeader (Environment.getUIString (prefix, - LanguageStrings.labels, - LanguageStrings.readability)); - //"Readability"); - - items.add (this.allReadabilityHeader); - - this.allReadability = this.getReadability (this.allChaptersFleschKincaid, - this.allChaptersFleschReadingEase, - this.allChaptersGunningFog); - - items.add (this.allReadability); - - box.add (this.getItems (Environment.getUIString (prefix, - LanguageStrings.sectiontitles, - LanguageStrings.allchapters), - //"All {Chapters}", - Book.OBJECT_TYPE, - items)); - - final JLabel history = UIUtils.createClickableLabel (Environment.getUIString (prefix, - LanguageStrings.viewdetaillink), - //"View Detail", - Environment.getIcon ("chart", - Constants.ICON_MENU)); - - UIUtils.setPadding (history, 0, 5, 0, 0); - - box.add (history); - box.add (Box.createVerticalStrut (10)); - - history.addMouseListener (new MouseEventHandler () - { - - public void handlePress (MouseEvent ev) - { - - _this.viewer.viewStatistics (); - - } - - }); - - JLabel l = UIUtils.createClickableLabel (Environment.getUIString (prefix, - LanguageStrings.helplink), - //"Click to find out more about
    the Readability indices", - Environment.getIcon ("help", - Constants.ICON_MENU)); - - UIUtils.setPadding (l, 0, 5, 0, 0); - - l.addMouseListener (new MouseEventHandler () - { - - public void handlePress (MouseEvent ev) - { - - // Open the url. - UIUtils.openURL (_this, - "help://chapters/readability"); - - } - - }); - - box.add (l); - - box.add (Box.createVerticalGlue ()); - - UIUtils.doLater (new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - _this.update (); - - } - - }); - - return this.wrapInScrollPane (box); - - } - - private JComponent getItem (String label, - JComponent value) - { - - String cols = COL_SPEC; - - String rows = "p"; - - FormLayout fl = new FormLayout (cols, - rows); - PanelBuilder b = new PanelBuilder (fl); - b.border (Borders.DIALOG); - - CellConstraints cc = new CellConstraints (); - - value.setFont (value.getFont ().deriveFont (Font.BOLD)); - - b.add (value, - cc.xy (1, 1)); - - b.addLabel (Environment.replaceObjectNames (label), - cc.xy (3, 1)); - - JPanel p = b.getPanel (); - p.setOpaque (false); - p.setBorder (new EmptyBorder (6, 10, 0, 10)); - p.setAlignmentX (Component.LEFT_ALIGNMENT); - - return p; - - } - - private AccordionItem getItems (String title, - String iconType, - List items) - { - - final Box b = new Box (BoxLayout.Y_AXIS); - - for (JComponent c : items) - { - - c.setAlignmentY (Component.TOP_ALIGNMENT); - - b.add (c); - - } - - b.setOpaque (false); - b.setAlignmentX (Component.LEFT_ALIGNMENT); - b.add (Box.createVerticalGlue ()); - - AccordionItem it = new AccordionItem (title, - iconType) - { - - @Override - public JComponent getContent () - { - - return b; - - } - - }; - - Header h = it.getHeader (); - - //h.setFont (h.getFont ().deriveFont ((float) UIUtils.scaleToScreenSize (12d)).deriveFont (java.awt.Font.PLAIN)); - - h.setBorder (new CompoundBorder (new CompoundBorder (new MatteBorder (0, 0, 1, 0, UIUtils.getBorderColor ()), - new EmptyBorder (0, 0, 3, 0)), - h.getBorder ())); - - it.init (); - - it.revalidate (); - - it.setMaximumSize (new Dimension (Short.MAX_VALUE, - it.getPreferredSize ().height)); - return it; - - } - - private JLabel createSubHeader (String title) - { - - JLabel ll = UIUtils.createInformationLabel (String.format ("%s", - title)); - - UIUtils.setPadding (ll, 0, 10, 0, 0); - - return ll; - - } - - @Override - public void init (String saveState) - throws GeneralException - { - - super.init (saveState); - - } - -} diff --git a/src/com/quollwriter/ui/userobjects/AbstractUserConfigurableObjectFieldViewEditHandler.java b/src/com/quollwriter/ui/userobjects/AbstractUserConfigurableObjectFieldViewEditHandler.java deleted file mode 100644 index 17b7d5f2..00000000 --- a/src/com/quollwriter/ui/userobjects/AbstractUserConfigurableObjectFieldViewEditHandler.java +++ /dev/null @@ -1,114 +0,0 @@ -package com.quollwriter.ui.userobjects; - -import java.util.Map; -import java.util.Set; -import java.util.LinkedHashSet; - -import javax.swing.*; - -import com.gentlyweb.utils.*; - -import com.quollwriter.*; -import com.quollwriter.ui.*; -import com.quollwriter.ui.forms.*; -import com.quollwriter.data.*; - -public abstract class AbstractUserConfigurableObjectFieldViewEditHandler implements UserConfigurableObjectFieldViewEditHandler -{ - - protected UserConfigurableObjectField field = null; - protected E typeField = null; - protected AbstractProjectViewer viewer = null; - protected UserConfigurableObject obj = null; - - public AbstractUserConfigurableObjectFieldViewEditHandler (E typeField, - UserConfigurableObject obj, - UserConfigurableObjectField field, - AbstractProjectViewer viewer) - { - - this.field = field; - this.viewer = viewer; - - this.typeField = typeField; - - if (obj == null) - { - - throw new NullPointerException ("User object cannot be null."); - - } - - this.obj = obj; - - } - - @Override - public Set getNamesFromFieldValue () - { - - return new LinkedHashSet (); - - } - - @Override - public void updateFieldFromInput () - throws GeneralException - { - - if (this.field == null) - { - - this.field = new UserConfigurableObjectField (this.typeField); - - this.obj.addField (this.field); - - } - - this.field.setValue (this.getInputSaveValue ()); - - } - - @Override - public T getFieldValue () - { - - return (this.field != null ? (T) this.field.getValue () : null); - - } - - @Override - public UserConfigurableObjectField getField () - { - - return this.field; - - } - - @Override - public E getTypeField () - { - - return this.typeField; - - } - - public FormItem createNoValueItem () - { - - return this.createNoValueItem (null); - - } - - public FormItem createNoValueItem (String label) - { - - return new AnyFormItem (this.typeField.getFormName (), - UIUtils.createInformationLabel ((label != null ? label : Environment.getUIString (LanguageStrings.form, - LanguageStrings.view, - LanguageStrings.novalue)))); - //"Not provided.")); - - } - -} diff --git a/src/com/quollwriter/ui/userobjects/DateUserConfigurableObjectFieldViewEditHandler.java b/src/com/quollwriter/ui/userobjects/DateUserConfigurableObjectFieldViewEditHandler.java deleted file mode 100644 index fd23c9e5..00000000 --- a/src/com/quollwriter/ui/userobjects/DateUserConfigurableObjectFieldViewEditHandler.java +++ /dev/null @@ -1,156 +0,0 @@ -package com.quollwriter.ui.userobjects; - -import java.awt.event.*; - -import java.util.Map; -import java.util.Set; -import java.util.LinkedHashSet; -import java.util.Date; - -import javax.swing.*; - -import com.gentlyweb.utils.*; - -import com.quollwriter.*; -import com.quollwriter.ui.*; -import com.quollwriter.ui.forms.*; -import com.quollwriter.data.*; - -public class DateUserConfigurableObjectFieldViewEditHandler extends AbstractUserConfigurableObjectFieldViewEditHandler -{ - - private DateFormItem editItem = null; - - public DateUserConfigurableObjectFieldViewEditHandler (DateUserConfigurableObjectTypeField typeField, - UserConfigurableObject obj, - UserConfigurableObjectField field, - AbstractProjectViewer viewer) - { - - super (typeField, - obj, - field, - viewer); - - } - - @Override - public void grabInputFocus () - { - - if (this.editItem != null) - { - - this.editItem.grabFocus (); - - } - - } - - @Override - public Set getInputFormItems (String initValue, - ActionListener formSave) - { - - Set items = new LinkedHashSet (); - - this.editItem = new DateFormItem (this.typeField.getFormName (), - this.typeField.getMinimum (), - this.typeField.getMaximum (), - this.typeField.getDefault ()); - - if (this.getFieldValue () != null) - { - - this.editItem.setDate (this.getFieldValue ()); - - } - - if (initValue != null) - { - - this.editItem.setDate (this.stringToValue (initValue)); - - } - - items.add (this.editItem); - - return items; - - } - - @Override - public Set getInputFormItemErrors () - { - - return null; - - } - - @Override - public Date getInputSaveValue () - { - - return this.editItem.getValue (); - - } - - @Override - public Date stringToValue (String s) - { - - if (s == null) - { - - return null; - - } - - return Environment.parseDate (s); - - } - - @Override - public String valueToString (Date val) - { - - if (val == null) - { - - return null; - - } - - return Environment.formatDate (val); - - } - - @Override - public Set getViewFormItems () - { - - Set items = new LinkedHashSet (); - - Date d = this.getFieldValue (); - - if (d != null) - { - - items.add (new AnyFormItem (this.typeField.getFormName (), - UIUtils.createLabel (Environment.formatDate (d)))); - - } else { - - items.add (this.createNoValueItem (Environment.getUIString (LanguageStrings.form, - LanguageStrings.view, - LanguageStrings.types, - UserConfigurableObjectTypeField.Type.date.getType (), - LanguageStrings.novalue))); - - } - - return items; - - } - -} diff --git a/src/com/quollwriter/ui/userobjects/DateUserConfigurableObjectTypeFieldConfigHandler.java b/src/com/quollwriter/ui/userobjects/DateUserConfigurableObjectTypeFieldConfigHandler.java deleted file mode 100644 index 9348d01c..00000000 --- a/src/com/quollwriter/ui/userobjects/DateUserConfigurableObjectTypeFieldConfigHandler.java +++ /dev/null @@ -1,207 +0,0 @@ -package com.quollwriter.ui.userobjects; - -import java.awt.Dimension; - -import java.util.Map; -import java.util.Set; -import java.util.LinkedHashSet; -import java.util.Date; -import java.util.ArrayList; - -import javax.swing.*; - -import com.quollwriter.*; -import com.quollwriter.ui.*; -import com.quollwriter.ui.forms.*; -import com.quollwriter.data.*; - -public class DateUserConfigurableObjectTypeFieldConfigHandler implements UserConfigurableObjectTypeFieldConfigHandler -{ - - private DateFormItem editDefDate = null; - private DateFormItem editMinDate = null; - private DateFormItem editMaxDate = null; - - private DateUserConfigurableObjectTypeField field = null; - - public DateUserConfigurableObjectTypeFieldConfigHandler (DateUserConfigurableObjectTypeField f) - { - - this.field = f; - - java.util.List prefix = new ArrayList (); - prefix.add (LanguageStrings.form); - prefix.add (LanguageStrings.config); - prefix.add (LanguageStrings.types); - prefix.add (UserConfigurableObjectTypeField.Type.date.getType ()); - - this.editDefDate = new DateFormItem (Environment.getUIString (prefix, - LanguageStrings._default, - LanguageStrings.text)); - //"Default"); - this.editMinDate = new DateFormItem (Environment.getUIString (prefix, - LanguageStrings.min, - LanguageStrings.text)); - //"Minimum"); - this.editMaxDate = new DateFormItem (Environment.getUIString (prefix, - LanguageStrings.max, - LanguageStrings.text)); - //"Maximum"); - - } - - @Override - public String getConfigurationDescription () - { - - Set strs = new LinkedHashSet (); - - java.util.List prefix = new ArrayList (); - prefix.add (LanguageStrings.form); - prefix.add (LanguageStrings.config); - prefix.add (LanguageStrings.types); - prefix.add (UserConfigurableObjectTypeField.Type.date.getType ()); - - strs.add (Environment.getUIString (prefix, - LanguageStrings.description)); - - //strs.add ("date"); - - if (this.field.getMinimum () != null) - { - - strs.add (String.format (Environment.getUIString (prefix, - LanguageStrings.min, - LanguageStrings.description), - Environment.formatDate (this.field.getMinimum ()))); - - //strs.add ("min: " + Environment.formatDate (this.field.getMinimum ())); - - } - - if (this.field.getMaximum () != null) - { - - strs.add (String.format (Environment.getUIString (prefix, - LanguageStrings.max, - LanguageStrings.description), - Environment.formatDate (this.field.getMaximum ()))); - //strs.add ("max: " + Environment.formatDate (this.field.getMaximum ())); - - } - - if (this.field.getDefault () != null) - { - - strs.add (String.format (Environment.getUIString (prefix, - LanguageStrings._default, - LanguageStrings.description), - Environment.formatDate (this.field.getDefault ()))); - //strs.add ("default: " + Environment.formatDate (this.field.getDefault ())); - - } - - return Utils.joinStrings (strs, - null); - - } - - @Override - public boolean updateFromExtraFormItems () - { - - this.field.setDefault (this.editDefDate.getValue ()); - this.field.setMinimum (this.editMinDate.getValue ()); - this.field.setMaximum (this.editMaxDate.getValue ()); - - return true; - - } - - @Override - public Set getExtraFormItemErrors (UserConfigurableObjectType objType) - { - - java.util.List prefix = new ArrayList (); - prefix.add (LanguageStrings.form); - prefix.add (LanguageStrings.config); - prefix.add (LanguageStrings.types); - prefix.add (UserConfigurableObjectTypeField.Type.date.getType ()); - prefix.add (LanguageStrings.errors); - - Set errors = new LinkedHashSet (); - - Date defVal = this.editDefDate.getValue (); - Date minVal = this.editMinDate.getValue (); - Date maxVal = this.editMaxDate.getValue (); - - if ((minVal != null) - && - (maxVal != null) - && - (minVal.after (maxVal)) - ) - { - - errors.add (Environment.getUIString (prefix, - LanguageStrings.max, - LanguageStrings.greaterthanmin)); - //errors.add ("The maximum date must be after the minimum."); - - } - - if ((defVal != null) - && - (minVal != null) - && - (minVal.after (defVal)) - ) - { - - errors.add (Environment.getUIString (prefix, - LanguageStrings._default, - LanguageStrings.greaterthanmin)); - //errors.add ("The default date must be after the minimum."); - - } - - if ((defVal != null) - && - (maxVal != null) - && - (defVal.after (maxVal)) - ) - { - - errors.add (Environment.getUIString (prefix, - LanguageStrings._default, - LanguageStrings.lessthanmax)); - //errors.add ("The default date must be before the maximum."); - - } - - return errors; - - } - - @Override - public Set getExtraFormItems () - { - - Set nitems = new LinkedHashSet (); - - this.editDefDate.setDate (this.field.getDefault ()); - this.editMinDate.setDate (this.field.getMinimum ()); - this.editMaxDate.setDate (this.field.getMaximum ()); - - nitems.add (this.editDefDate); - - nitems.add (this.editMinDate); - - nitems.add (this.editMaxDate); - - return nitems; - - } - -} diff --git a/src/com/quollwriter/ui/userobjects/FileUserConfigurableObjectFieldViewEditHandler.java b/src/com/quollwriter/ui/userobjects/FileUserConfigurableObjectFieldViewEditHandler.java deleted file mode 100644 index 5a586fd0..00000000 --- a/src/com/quollwriter/ui/userobjects/FileUserConfigurableObjectFieldViewEditHandler.java +++ /dev/null @@ -1,230 +0,0 @@ -package com.quollwriter.ui.userobjects; - -import java.awt.event.*; - -import java.util.Map; -import java.util.Set; -import java.util.LinkedHashSet; -import java.util.UUID; - -import java.io.*; - -import javax.swing.*; - -import com.gentlyweb.utils.*; - -import com.quollwriter.*; -import com.quollwriter.ui.*; -import com.quollwriter.ui.forms.*; -import com.quollwriter.data.*; - -public class FileUserConfigurableObjectFieldViewEditHandler extends AbstractUserConfigurableObjectFieldViewEditHandler -{ - - private FileSelectorFormItem editItem = null; - - public FileUserConfigurableObjectFieldViewEditHandler (FileUserConfigurableObjectTypeField typeField, - UserConfigurableObject obj, - UserConfigurableObjectField field, - AbstractProjectViewer viewer) - { - - super (typeField, - obj, - field, - viewer); - - } - - @Override - public void grabInputFocus () - { - - if (this.editItem != null) - { - - this.editItem.grabFocus (); - - } - - } - - @Override - public Set getInputFormItems (String initValue, - ActionListener formSave) - { - - Set items = new LinkedHashSet (); - - this.editItem = new FileSelectorFormItem (this.typeField.getFormName (), - this.viewer.getProjectFile ((this.getFieldValue () != null ? this.getFieldValue () : initValue)), - false, - JFileChooser.FILES_ONLY); - - items.add (this.editItem); - - return items; - - } - - @Override - public Set getInputFormItemErrors () - { - - return null; - - } - - @Override - public String getInputSaveValue () - throws GeneralException - { - - File f = this.editItem.getValue (); - - if (f == null) - { - - if (this.getFieldValue () != null) - { - - this.viewer.getProjectFile (this.getFieldValue ()).delete (); - - } - - return null; - - } - - File currF = this.viewer.getProjectFile (this.getFieldValue ()); - - boolean save = false; - - // Do we have a selected file and don't have a saved one? - // Or, do we have both and have they changed? - if ((f != null) - && - ((currF == null) - || - (f.compareTo (currF) != 0) - ) - ) - { - - String v = this.getFieldValue (); - - String fn = null; - - if (currF == null) - { - - fn = UUID.randomUUID ().toString () + "." + Utils.getFileType (f); - - } else { - - String t = Utils.getFileType (currF); - - fn = v.substring (0, - v.length () - t.length ()) + Utils.getFileType (f); - - } - - try - { - - // Copy the new file into place. - this.viewer.saveToProjectFilesDirectory (f, - fn); - - } catch (Exception e) { - - throw new GeneralException ("Unable to copy file: " + - f + - " to project files dir with filename: " + - fn, - e); - - } - - f = this.viewer.getProjectFile (fn); - - } - - return f.getName (); - - } - - @Override - public String stringToValue (String s) - { - - // It's just the file name. - return s; - - } - - @Override - public String valueToString (String f) - throws GeneralException - { - - return f; - - } - - @Override - public Set getViewFormItems () - { - - Set items = new LinkedHashSet (); - - File f = null; - - if (this.getFieldValue () != null) - { - - f = this.viewer.getProjectFile (this.getFieldValue ()); - - } - - String url = null; - - if (f != null) - { - - try - { - - url = f.toURI ().toURL ().toExternalForm (); - - } catch (Exception e) { - - Environment.logError ("Unable to convert file to a url string: " + - f, - e); - - url = "file://" + f.getPath (); - - } - - } - - if (url != null) - { - - items.add (new AnyFormItem (this.typeField.getFormName (), - UIUtils.createClickableLabel (f.getName (), - null, - url))); - - } else { - - items.add (this.createNoValueItem ()); - - } - - return items; - - } - -} diff --git a/src/com/quollwriter/ui/userobjects/ImageUserConfigurableObjectFieldViewEditHandler.java b/src/com/quollwriter/ui/userobjects/ImageUserConfigurableObjectFieldViewEditHandler.java deleted file mode 100644 index 36af75b0..00000000 --- a/src/com/quollwriter/ui/userobjects/ImageUserConfigurableObjectFieldViewEditHandler.java +++ /dev/null @@ -1,305 +0,0 @@ -package com.quollwriter.ui.userobjects; - -import java.awt.event.*; - -import java.util.Map; -import java.util.Set; -import java.util.LinkedHashSet; -import java.util.UUID; -import java.util.ArrayList; - -import java.io.*; - -import java.awt.*; -import java.awt.event.*; -import java.awt.image.*; - -import javax.swing.*; - -import javax.imageio.*; - -import com.gentlyweb.utils.*; - -import com.quollwriter.*; -import com.quollwriter.ui.*; -import com.quollwriter.ui.forms.*; -import com.quollwriter.data.*; - -public class ImageUserConfigurableObjectFieldViewEditHandler extends AbstractUserConfigurableObjectFieldViewEditHandler -{ - - private ImageSelectorFormItem editItem = null; - - public ImageUserConfigurableObjectFieldViewEditHandler (ImageUserConfigurableObjectTypeField typeField, - UserConfigurableObject obj, - UserConfigurableObjectField field, - AbstractProjectViewer viewer) - { - - super (typeField, - obj, - field, - viewer); - - } - - @Override - public void grabInputFocus () - { - - if (this.editItem != null) - { - - this.editItem.grabFocus (); - - } - - } - - @Override - public Set getInputFormItems (String initValue, - ActionListener formSave) - { - - Set items = new LinkedHashSet (); - - this.editItem = new ImageSelectorFormItem (this.typeField.getFormName (), - UIUtils.imageFileFilter, - this.viewer.getProjectFile ((this.getFieldValue () != null ? this.getFieldValue () : initValue)), - new Dimension (100, 100), - false, - null); - - items.add (this.editItem); - - return items; - - } - - @Override - public Set getInputFormItemErrors () - { - - return null; - - } - - @Override - public String getInputSaveValue () - throws GeneralException - { - - File f = this.editItem.getValue (); - - if (f == null) - { - - if (this.getFieldValue () != null) - { - - this.viewer.getProjectFile (this.getFieldValue ()).delete (); - - } - - return null; - - } - - File currF = this.viewer.getProjectFile (this.getFieldValue ()); - - boolean save = false; - - // Do we have a selected file and don't have a saved one? - // Or, do we have both and have they changed? - if ((f != null) - && - ((currF == null) - || - (f.compareTo (currF) != 0) - ) - ) - { - - String v = this.getFieldValue (); - - String fn = null; - - if (currF == null) - { - - fn = UUID.randomUUID ().toString () + "." + Utils.getFileType (f); - - } else { - - String t = Utils.getFileType (currF); - - fn = v.substring (0, - v.length () - t.length ()) + Utils.getFileType (f); - - } - - try - { - - // Copy the new file into place. - this.viewer.saveToProjectFilesDirectory (f, - fn); - - } catch (Exception e) { - - throw new GeneralException ("Unable to copy file: " + - f + - " to project files dir with filename: " + - fn, - e); - - } - - f = this.viewer.getProjectFile (fn); - - } - - return f.getName (); - - } - - @Override - public String stringToValue (String s) - { - - // It's just the file name. - return s; - - } - - @Override - public String valueToString (String f) - throws GeneralException - { - - return f; - - } - - public boolean hasImage () - { - - final File pf = this.viewer.getProjectFile (this.getFieldValue ()); - - if (pf == null) - { - - return false; - - } - - BufferedImage v = UIUtils.getImage (pf); - - return v != null; - - } - - @Override - public Set getViewFormItems () - { - - final java.util.List prefix = new ArrayList (); - prefix.add (LanguageStrings.form); - prefix.add (LanguageStrings.view); - prefix.add (LanguageStrings.types); - prefix.add (UserConfigurableObjectTypeField.Type.image.getType ()); - - final ImageUserConfigurableObjectFieldViewEditHandler _this = this; - - Set items = new LinkedHashSet (); - - final File pf = this.viewer.getProjectFile (this.getFieldValue ()); - - if ((pf == null) - || - (!pf.exists ()) - ) - { - - items.add (this.createNoValueItem ()); - - return items; - - } - - BufferedImage v = UIUtils.getImage (pf); - - ImageIcon icon = null; - - if (v != null) - { - - icon = new ImageIcon (v); - - if (v.getWidth () > 150) - { - - v = UIUtils.getScaledImage (v, - 150); - - icon = new ImageIcon (v); - - } - - } - - if (icon != null) - { - - JLabel l = UIUtils.createLabel (null, - icon, - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - try - { - - UIUtils.showFile (_this.viewer, - pf); - - } catch (Exception e) { - - UIUtils.showErrorMessage (_this.viewer, - Environment.getUIString (prefix, - LanguageStrings.actionerror)); - //"Unable to show image."); - - Environment.logError ("Unable to show image: " + - pf + - ", for: " + - _this.field, - e); - - } - - } - - }); - - l.setToolTipText (Environment.getUIString (prefix, - LanguageStrings.tooltip)); - //l.setToolTipText ("Click to view the full image"); - items.add (new AnyFormItem (this.typeField.getFormName (), - l)); - - } else { - - items.add (this.createNoValueItem (Environment.getUIString (prefix, - LanguageStrings.novalue))); - - } - - return items; - - } - -} diff --git a/src/com/quollwriter/ui/userobjects/MultiTextUserConfigurableObjectFieldViewEditHandler.java b/src/com/quollwriter/ui/userobjects/MultiTextUserConfigurableObjectFieldViewEditHandler.java deleted file mode 100644 index cec17ba4..00000000 --- a/src/com/quollwriter/ui/userobjects/MultiTextUserConfigurableObjectFieldViewEditHandler.java +++ /dev/null @@ -1,256 +0,0 @@ -package com.quollwriter.ui.userobjects; - -import java.awt.event.*; - -import java.util.Map; -import java.util.Set; -import java.util.LinkedHashSet; -import java.util.StringTokenizer; - -import javax.swing.*; - -import com.gentlyweb.utils.*; - -import com.quollwriter.*; -import com.quollwriter.ui.*; -import com.quollwriter.ui.forms.*; -import com.quollwriter.data.*; -import com.quollwriter.text.*; -import com.quollwriter.ui.components.Markup; - -public class MultiTextUserConfigurableObjectFieldViewEditHandler extends AbstractUserConfigurableObjectFieldViewEditHandler -{ - - private MultiLineTextFormItem editItem = null; - - public MultiTextUserConfigurableObjectFieldViewEditHandler (MultiTextUserConfigurableObjectTypeField typeField, - UserConfigurableObject obj, - UserConfigurableObjectField field, - AbstractProjectViewer viewer) - { - - super (typeField, - obj, - field, - viewer); - - } - - @Override - public Set getNamesFromFieldValue () - { - - Set ret = new LinkedHashSet (); - - StringWithMarkup sm = this.getFieldValue (); - - if (sm != null) - { - - String st = sm.getText (); - - if (st != null) - { - - StringTokenizer t = new StringTokenizer (st, - "\n;,"); - - while (t.hasMoreTokens ()) - { - - ret.add (t.nextToken ().trim ()); - - } - - } - - } - - return ret; - - } - - @Override - public void grabInputFocus () - { - - if (this.editItem != null) - { - - this.editItem.getTextArea ().grabFocus (); - - } - - } - - @Override - public Set getInputFormItems (String initValue, - ActionListener formSave) - { - - this.editItem = new MultiLineTextFormItem (this.typeField.getFormName (), - this.viewer, - (this.typeField.isNameField () ? 3 : 7)); - - this.editItem.setCanFormat (true); - this.editItem.setAutoGrabFocus (false); - - UIUtils.addDoActionOnReturnPressed (this.editItem.getTextArea (), - formSave); - - if (this.typeField.isNameField ()) - { - - this.editItem.setSpellCheckEnabled (false); - - this.editItem.setToolTipText (Environment.getUIString (LanguageStrings.form, - LanguageStrings.addedit, - LanguageStrings.types, - UserConfigurableObjectTypeField.Type.multitext.getType (), - LanguageStrings.othernames, - LanguageStrings.tooltip)); - //"Separate each name/alias with a new line, comma or a semi-colon."); - - } - - if (this.getFieldValue () != null) - { - - this.editItem.setText (this.getFieldValue ()); - - } else { - - if (initValue != null) - { - - this.editItem.setText (initValue); - - } - - } - - Set items = new LinkedHashSet (); - - items.add (this.editItem); - - return items; - - } - - @Override - public Set getInputFormItemErrors () - { - - return null; - - } - - @Override - public StringWithMarkup getInputSaveValue () - { - - return this.editItem.getValue (); - - } - - @Override - public String valueToString (StringWithMarkup val) - throws GeneralException - { - - try - { - - return JSONEncoder.encode (val); - - } catch (Exception e) { - - throw new GeneralException ("Unable to encode to string", - e); - - } - - } - - @Override - public StringWithMarkup stringToValue (String s) - { - - return JSONDecoder.decodeToStringWithMarkup (s); - - } - - @Override - public Set getViewFormItems () - { - - StringWithMarkup text = (this.field != null ? (StringWithMarkup) this.field.getValue () : null); - - Set items = new LinkedHashSet (); - - FormItem item = null; - - if ((text != null) - && - (text.hasText ()) - ) - { - - JComponent t = null; - - if (this.typeField.isDisplayAsBullets ()) - { - - Markup m = text.getMarkup (); - - StringBuilder b = new StringBuilder ("
      "); - - TextIterator iter = new TextIterator (text.getText ()); - - for (Paragraph p : iter.getParagraphs ()) - { - - b.append ("
    • "); - b.append (p.markupAsHTML (m)); - b.append ("
    • "); - - } - - b.append ("
    "); - - t = UIUtils.createObjectDescriptionViewPane (b.toString (), - this.field.getParentObject (), - this.viewer, - null); - - } else { - - t = UIUtils.createObjectDescriptionViewPane (text, - this.field.getParentObject (), - this.viewer, - null); - - } - - t.setBorder (null); - - item = new AnyFormItem (this.typeField.getFormName (), - t); - - } else { - - item = this.createNoValueItem (Environment.getUIString (LanguageStrings.form, - LanguageStrings.view, - LanguageStrings.types, - UserConfigurableObjectTypeField.Type.multitext.getType (), - LanguageStrings.novalue)); - - } - - items.add (item); - - return items; - - } - -} diff --git a/src/com/quollwriter/ui/userobjects/MultiTextUserConfigurableObjectTypeFieldConfigHandler.java b/src/com/quollwriter/ui/userobjects/MultiTextUserConfigurableObjectTypeFieldConfigHandler.java deleted file mode 100644 index 83d999dd..00000000 --- a/src/com/quollwriter/ui/userobjects/MultiTextUserConfigurableObjectTypeFieldConfigHandler.java +++ /dev/null @@ -1,155 +0,0 @@ -package com.quollwriter.ui.userobjects; - -import javax.swing.*; -import java.awt.event.*; - -import java.util.Map; -import java.util.Set; -import java.util.LinkedHashSet; -import java.util.ArrayList; - -import com.gentlyweb.utils.*; - -import com.quollwriter.*; -import com.quollwriter.ui.*; -import com.quollwriter.ui.forms.*; -import com.quollwriter.data.*; - -public class MultiTextUserConfigurableObjectTypeFieldConfigHandler implements UserConfigurableObjectTypeFieldConfigHandler -{ - - private CheckboxFormItem displayAsBullets = null; - private CheckboxFormItem isOtherNames = null; - - private MultiTextUserConfigurableObjectTypeField field = null; - - public MultiTextUserConfigurableObjectTypeFieldConfigHandler (MultiTextUserConfigurableObjectTypeField f) - { - - this.field = f; - - java.util.List prefix = new ArrayList (); - prefix.add (LanguageStrings.form); - prefix.add (LanguageStrings.config); - prefix.add (LanguageStrings.types); - prefix.add (UserConfigurableObjectTypeField.Type.multitext.getType ()); - - this.isOtherNames = new CheckboxFormItem (null, - this.replaceObjName (Environment.getUIString (prefix, - LanguageStrings.othernames, - LanguageStrings.text)), - //"Is other names/aliases for the %s"), - false, - this.replaceObjName (Environment.getUIString (prefix, - LanguageStrings.othernames, - LanguageStrings.tooltip))); - //"Check this box to mark this field as other name or aliases for the %s. Separate each name/alias with a new line, a comma or a semi-colon.")); - - this.displayAsBullets = new CheckboxFormItem (null, - Environment.getUIString (prefix, - LanguageStrings.bulletpoints, - LanguageStrings.text), - //"Display as bullet points", - false, - Environment.getUIString (prefix, - LanguageStrings.bulletpoints, - LanguageStrings.tooltip)); - //"Check this box to display the text in the field as a series of bullet points. Each separate line of text will be treated as a bullet point."); - - } - - public String getObjName () - { - - return this.field.getUserConfigurableObjectType ().getObjectTypeName ().toLowerCase (); - - } - - public String replaceObjName (String s) - { - - return String.format (s, - this.getObjName ()); - - } - - @Override - public boolean updateFromExtraFormItems () - { - - this.field.setDisplayAsBullets (this.displayAsBullets.isSelected ()); - this.field.setNameField (this.isOtherNames.isSelected ()); - - return true; - - } - - @Override - public Set getExtraFormItemErrors (UserConfigurableObjectType objType) - { - - Set errors = new LinkedHashSet (); - - return errors; - - } - - @Override - public Set getExtraFormItems () - { - - Set nitems = new LinkedHashSet (); - - this.displayAsBullets.setSelected (this.field.isDisplayAsBullets ()); - this.isOtherNames.setSelected (this.field.isNameField ()); - - nitems.add (this.displayAsBullets); - - nitems.add (this.isOtherNames); - - return nitems; - - } - - @Override - public String getConfigurationDescription () - { - - Set strs = new LinkedHashSet (); - - java.util.List prefix = new ArrayList (); - prefix.add (LanguageStrings.form); - prefix.add (LanguageStrings.config); - prefix.add (LanguageStrings.types); - prefix.add (UserConfigurableObjectTypeField.Type.multitext.getType ()); - - strs.add (Environment.getUIString (prefix, - LanguageStrings.description)); - //"multi-line text"); - - if (this.field.isNameField ()) - { - - strs.add (this.replaceObjName (Environment.getUIString (prefix, - LanguageStrings.othernames, - LanguageStrings.description))); - //"is other names/aliases for the %s")); - - } - - if (this.field.isDisplayAsBullets ()) - { - - strs.add (Environment.getUIString (prefix, - LanguageStrings.bulletpoints, - LanguageStrings.description)); - //"displayed as bullet points"); - - } - - return Utils.joinStrings (strs, - null); - - } - -} \ No newline at end of file diff --git a/src/com/quollwriter/ui/userobjects/NumberUserConfigurableObjectFieldViewEditHandler.java b/src/com/quollwriter/ui/userobjects/NumberUserConfigurableObjectFieldViewEditHandler.java deleted file mode 100644 index 8c2af130..00000000 --- a/src/com/quollwriter/ui/userobjects/NumberUserConfigurableObjectFieldViewEditHandler.java +++ /dev/null @@ -1,313 +0,0 @@ -package com.quollwriter.ui.userobjects; - -import java.awt.event.*; - -import java.util.Map; -import java.util.Set; -import java.util.LinkedHashSet; -import java.util.ArrayList; - -import java.math.*; - -import javax.swing.*; - -import com.gentlyweb.utils.*; - -import com.quollwriter.*; -import com.quollwriter.ui.*; -import com.quollwriter.ui.forms.*; -import com.quollwriter.data.*; - -public class NumberUserConfigurableObjectFieldViewEditHandler extends AbstractUserConfigurableObjectFieldViewEditHandler -{ - - private TextFormItem editItem = null; - - public NumberUserConfigurableObjectFieldViewEditHandler (NumberUserConfigurableObjectTypeField typeField, - UserConfigurableObject obj, - UserConfigurableObjectField field, - AbstractProjectViewer viewer) - { - - super (typeField, - obj, - field, - viewer); - - } - - @Override - public void grabInputFocus () - { - - if (this.editItem != null) - { - - this.editItem.grabFocus (); - - } - - } - - @Override - public Set getInputFormItems (String initValue, - ActionListener formSave) - { - - Set items = new LinkedHashSet (); - - String v = null; - - if (this.getFieldValue () != null) - { - - v = Environment.formatNumber (this.getFieldValue ()); - - } else { - - if (initValue != null) - { - - try - { - - v = Environment.formatNumber (this.stringToValue (initValue)); - - } catch (Exception e) { - - Environment.logError ("Unable to convert value: " + - initValue + - " to a number.", - e); - - } - - } - - } - - this.editItem = new TextFormItem (this.typeField.getFormName (), - v); - - UIUtils.addDoActionOnReturnPressed (this.editItem.getTextField (), - formSave); - - items.add (this.editItem); - - return items; - - } - - @Override - public Set getInputFormItemErrors () - { - - java.util.List prefix = new ArrayList (); - prefix.add (LanguageStrings.form); - prefix.add (LanguageStrings.addedit); - prefix.add (LanguageStrings.types); - prefix.add (UserConfigurableObjectTypeField.Type.number.getType ()); - prefix.add (LanguageStrings.errors); - - Set errors = new LinkedHashSet (); - - String val = this.editItem.getValue (); - - Double v = null; - - if ((val != null) - && - (val.trim ().length () > 0) - ) - { - - try - { - - v = Environment.parseToDouble (val); - - } catch (Exception e) { - - errors.add (String.format (Environment.getUIString (prefix, - LanguageStrings.invalidvalue), - //"%s does not appear to be a number.", - this.typeField.getFormName ())); - - } - - } - - // Check for the maximum/minimum. - if (v != null) - { - - Double max = null; - - try - { - - max = this.typeField.getMaximum (); - - } catch (Exception e) { - - Environment.logError ("Unable to get maximum", - e); - - } - - if (max != null) - { - - if (v > max) - { - - errors.add (String.format (Environment.getUIString (prefix, - LanguageStrings.max), - //"%s must be a maximum of %s", - this.typeField.getFormName (), - Environment.formatNumber (max))); - - } - - } - - Double min = null; - - try - { - - min = this.typeField.getMinimum (); - - } catch (Exception e) { - - Environment.logError ("Unable to get minimum", - e); - - } - - if (min != null) - { - - if (v < min) - { - - errors.add (String.format (Environment.getUIString (prefix, - LanguageStrings.min), - //"%s must be a minimum of %s", - this.typeField.getFormName (), - Environment.formatNumber (min))); - - } - - } - - } - - return errors; - - } - - @Override - public Double getInputSaveValue () - { - - String val = this.editItem.getValue (); - - Double v = null; - - if ((val != null) - && - (val.trim ().length () > 0) - ) - { - - try - { - - return Environment.parseToDouble (val); - - } catch (Exception e) { - - Environment.logError ("Unable to convert: " + val + " to a double.", - e); - - } - - } - - return null; - - } - - @Override - public String valueToString (Double val) - { - - if (val == null) - { - - return null; - - } - - return Environment.formatNumber (val); - - } - - @Override - public Double stringToValue (String s) - throws GeneralException - { - - if (s == null) - { - - return null; - - } - - try - { - - return Environment.parseToDouble (s); - - } catch (Exception e) { - - throw new GeneralException ("Unable to convert: " + - s + - " to a double.", - e); - - } - - } - - @Override - public Set getViewFormItems () - { - - Set items = new LinkedHashSet (); - - Double d = (this.field != null ? (Double) this.field.getValue () : null); - - if (d != null) - { - - items.add (new AnyFormItem (this.typeField.getFormName (), - UIUtils.createLabel (Environment.formatNumber (d)))); - - } else { - - items.add (this.createNoValueItem (Environment.getUIString (LanguageStrings.form, - LanguageStrings.view, - LanguageStrings.types, - UserConfigurableObjectTypeField.Type.number.getType (), - LanguageStrings.novalue))); - - } - - return items; - - } - -} diff --git a/src/com/quollwriter/ui/userobjects/ObjectDescriptionUserConfigurableObjectFieldViewEditHandler.java b/src/com/quollwriter/ui/userobjects/ObjectDescriptionUserConfigurableObjectFieldViewEditHandler.java deleted file mode 100644 index 2257b28f..00000000 --- a/src/com/quollwriter/ui/userobjects/ObjectDescriptionUserConfigurableObjectFieldViewEditHandler.java +++ /dev/null @@ -1,241 +0,0 @@ -package com.quollwriter.ui.userobjects; - -import java.awt.event.*; - -import java.util.Map; -import java.util.Set; -import java.util.LinkedHashSet; - -import javax.swing.*; - -import com.gentlyweb.utils.*; - -import com.quollwriter.*; -import com.quollwriter.ui.*; -import com.quollwriter.ui.forms.*; -import com.quollwriter.data.*; -import com.quollwriter.text.*; -import com.quollwriter.ui.components.QTextEditor; -import com.quollwriter.ui.components.Markup; - -public class ObjectDescriptionUserConfigurableObjectFieldViewEditHandler extends AbstractUserConfigurableObjectFieldViewEditHandler -{ - - private MultiLineTextFormItem editItem = null; - - public ObjectDescriptionUserConfigurableObjectFieldViewEditHandler (ObjectDescriptionUserConfigurableObjectTypeField typeField, - UserConfigurableObject obj, - UserConfigurableObjectField field, - AbstractProjectViewer viewer) - { - - super (typeField, - obj, - field, - viewer); - - } - - @Override - public void updateFieldFromInput () - { - - this.obj.setDescription (this.getInputSaveValue ()); - - } - - @Override - public void grabInputFocus () - { - - if (this.editItem != null) - { - - this.editItem.getTextArea ().grabFocus (); - - } - } - - @Override - public Set getInputFormItems (String initValue, - ActionListener formSave) - { - - this.editItem = new MultiLineTextFormItem (this.typeField.getFormName (), - this.viewer, - 10); - - this.editItem.setCanFormat (true); - this.editItem.setAutoGrabFocus (false); - - UIUtils.addDoActionOnReturnPressed (this.editItem.getTextArea (), - formSave); - - if (this.typeField.isNameField ()) - { - - this.editItem.setSpellCheckEnabled (false); - - } - - this.editItem.setText (this.obj.getDescription ()); - - Set items = new LinkedHashSet (); - - items.add (this.editItem); - - return items; - - } - - @Override - public Set getInputFormItemErrors () - { - - return null; - - } - - @Override - public StringWithMarkup getInputSaveValue () - { - - StringWithMarkup sm = this.editItem.getValue (); - - if (sm.getText ().length () == 0) - { - - return null; - - } - - return sm; - - } - - @Override - public String valueToString (StringWithMarkup val) - throws GeneralException - { - - try - { - - return JSONEncoder.encode (val); - - } catch (Exception e) { - - throw new GeneralException ("Unable to encode to string", - e); - - } - - } - - @Override - public StringWithMarkup stringToValue (String s) - { - - return JSONDecoder.decodeToStringWithMarkup (s); - - } - - @Override - public StringWithMarkup getFieldValue () - { - - return this.obj.getDescription (); - - } - - @Override - public Set getViewFormItems () - { - - StringWithMarkup text = this.obj.getDescription (); - - JComponent t = null; - - Set items = new LinkedHashSet (); - - FormItem item = null; - - if (text != null) - { - - if (this.typeField.isDisplayAsBullets ()) - { - - Markup m = text.getMarkup (); - - StringBuilder b = new StringBuilder ("
      "); - - TextIterator iter = new TextIterator (text.getText ()); - - for (Paragraph p : iter.getParagraphs ()) - { - - b.append ("
    • "); - b.append (p.markupAsHTML (m)); - b.append ("
    • "); - - } - - b.append ("
    "); - - t = UIUtils.createObjectDescriptionViewPane (b.toString (), - this.obj, - this.viewer, - null); - - } else { - - t = UIUtils.createObjectDescriptionViewPane (text, - this.obj, - this.viewer, - null); - - } - - t.setSize (new java.awt.Dimension (250, Short.MAX_VALUE)); - t.setBorder (null); - - item = new AnyFormItem (this.typeField.getFormName (), - t); - - } else { - - item = this.createNoValueItem (); - - } - - items.add (item); - - return items; - - } - - public QTextEditor getInputTextComponent (ActionListener formSave) - { - - Set its = this.getInputFormItems (null, - formSave); - - QTextEditor ed = this.editItem.getTextArea ().getEditor (); - - ed.setBorder (new JScrollPane ().getBorder ()); - ed.setMargin (new java.awt.Insets (3, 3, 3, 3)); - ed.setMaximumSize (new java.awt.Dimension (Short.MAX_VALUE, Short.MAX_VALUE)); - - return ed; - - } - - public JComponent getViewTextComponent () - { - - return this.getViewFormItems ().iterator ().next ().getComponent (); - - } - -} diff --git a/src/com/quollwriter/ui/userobjects/ObjectDescriptionUserConfigurableObjectTypeFieldConfigHandler.java b/src/com/quollwriter/ui/userobjects/ObjectDescriptionUserConfigurableObjectTypeFieldConfigHandler.java deleted file mode 100644 index 23863dc5..00000000 --- a/src/com/quollwriter/ui/userobjects/ObjectDescriptionUserConfigurableObjectTypeFieldConfigHandler.java +++ /dev/null @@ -1,128 +0,0 @@ -package com.quollwriter.ui.userobjects; - -import javax.swing.*; -import java.awt.event.*; - -import java.util.Map; -import java.util.Set; -import java.util.LinkedHashSet; -import java.util.ArrayList; - -import com.gentlyweb.utils.*; - -import com.quollwriter.*; -import com.quollwriter.ui.*; -import com.quollwriter.ui.forms.*; -import com.quollwriter.data.*; - -public class ObjectDescriptionUserConfigurableObjectTypeFieldConfigHandler implements UserConfigurableObjectTypeFieldConfigHandler -{ - - private CheckboxFormItem displayAsBullets = null; - - private ObjectDescriptionUserConfigurableObjectTypeField field = null; - - public ObjectDescriptionUserConfigurableObjectTypeFieldConfigHandler (ObjectDescriptionUserConfigurableObjectTypeField f) - { - - this.field = f; - - java.util.List prefix = new ArrayList (); - prefix.add (LanguageStrings.form); - prefix.add (LanguageStrings.config); - prefix.add (LanguageStrings.types); - prefix.add (UserConfigurableObjectTypeField.Type.objectdesc.getType ()); - prefix.add (LanguageStrings.bulletpoints); - - this.displayAsBullets = new CheckboxFormItem (null, - Environment.getUIString (prefix, - LanguageStrings.text), - //"Display as bullet points", - false, - Environment.getUIString (prefix, - LanguageStrings.tooltip)); - //"Check this box to display the text in the field as a series of bullet points. Each separate line of text will be treated as a bullet point."); - - } - - public String getObjName () - { - - return this.field.getUserConfigurableObjectType ().getObjectTypeName ().toLowerCase (); - - } - - public String replaceObjName (String s) - { - - return String.format (s, - this.getObjName ()); - - } - - @Override - public boolean updateFromExtraFormItems () - { - - this.field.setDisplayAsBullets (this.displayAsBullets.isSelected ()); - - return true; - - } - - @Override - public Set getExtraFormItemErrors (UserConfigurableObjectType objType) - { - - Set errors = new LinkedHashSet (); - - return errors; - - } - - @Override - public Set getExtraFormItems () - { - - Set nitems = new LinkedHashSet (); - - this.displayAsBullets.setSelected (this.field.isDisplayAsBullets ()); - - nitems.add (this.displayAsBullets); - - return nitems; - - } - - @Override - public String getConfigurationDescription () - { - - Set strs = new LinkedHashSet (); - - strs.add (this.replaceObjName (Environment.getUIString (LanguageStrings.form, - LanguageStrings.config, - LanguageStrings.types, - UserConfigurableObjectTypeField.Type.objectdesc.getType (), - LanguageStrings.description))); - //"is the %s description")); - - if (this.field.isDisplayAsBullets ()) - { - - strs.add (Environment.getUIString (LanguageStrings.form, - LanguageStrings.config, - LanguageStrings.types, - UserConfigurableObjectTypeField.Type.objectdesc.getType (), - LanguageStrings.bulletpoints, - LanguageStrings.description)); - //"displayed as bullet points"); - - } - - return Utils.joinStrings (strs, - null); - - } - -} \ No newline at end of file diff --git a/src/com/quollwriter/ui/userobjects/ObjectImageUserConfigurableObjectFieldViewEditHandler.java b/src/com/quollwriter/ui/userobjects/ObjectImageUserConfigurableObjectFieldViewEditHandler.java deleted file mode 100644 index 36c39220..00000000 --- a/src/com/quollwriter/ui/userobjects/ObjectImageUserConfigurableObjectFieldViewEditHandler.java +++ /dev/null @@ -1,143 +0,0 @@ -package com.quollwriter.ui.userobjects; - -import java.io.*; -import java.awt.image.*; -import java.awt.event.*; - -import java.util.Map; -import java.util.Set; -import java.util.LinkedHashSet; -import java.util.ArrayList; - -import javax.swing.*; - -import com.gentlyweb.utils.*; - -import com.quollwriter.*; -import com.quollwriter.ui.*; -import com.quollwriter.ui.forms.*; -import com.quollwriter.data.*; - -public class ObjectImageUserConfigurableObjectFieldViewEditHandler extends ImageUserConfigurableObjectFieldViewEditHandler -{ - - public ObjectImageUserConfigurableObjectFieldViewEditHandler (ImageUserConfigurableObjectTypeField typeField, - UserConfigurableObject obj, - UserConfigurableObjectField field, - AbstractProjectViewer viewer) - { - - super (typeField, - obj, - field, - viewer); - - } - - @Override - public Set getViewFormItems () - { - - final java.util.List prefix = new ArrayList (); - prefix.add (LanguageStrings.form); - prefix.add (LanguageStrings.view); - prefix.add (LanguageStrings.types); - prefix.add (UserConfigurableObjectTypeField.Type.objectimage.getType ()); - - final ImageUserConfigurableObjectFieldViewEditHandler _this = this; - - Set items = new LinkedHashSet (); - - final File pf = this.viewer.getProjectFile (this.getFieldValue ()); - - BufferedImage v = UIUtils.getImage (pf); - - ImageIcon icon = null; - - if (v != null) - { - - icon = new ImageIcon (v); - - if (v.getWidth () > 250) - { - - v = UIUtils.getScaledImage (v, - 250); - - icon = new ImageIcon (v); - - } - - } - - if (icon != null) - { - - JLabel l = UIUtils.createLabel (null, - icon, - new ActionListener () - { - - @Override - public void actionPerformed (ActionEvent ev) - { - - try - { - - UIUtils.showFile (_this.viewer, - pf); - - } catch (Exception e) { - - UIUtils.showErrorMessage (_this.viewer, - Environment.getUIString (prefix, - LanguageStrings.actionerror)); - //"Unable to show image."); - - Environment.logError ("Unable to show image: " + - pf + - ", for: " + - _this.field, - e); - - } - - } - - }); - - l.setToolTipText (Environment.getUIString (prefix, - LanguageStrings.tooltip)); - //"Click to view the full image"); - items.add (new AnyFormItem (this.typeField.getFormName (), - l)); - - } else { - - items.add (this.createNoValueItem (Environment.getUIString (prefix, - LanguageStrings.novalue))); - - } - - return items; - - } - - public JComponent getViewImageComponent () - { - - return this.getViewFormItems ().iterator ().next ().getComponent (); - - } - - public JComponent getInputImageComponent () - { - - return this.getInputFormItems (null, - null).iterator ().next ().getComponent (); - - } - -} diff --git a/src/com/quollwriter/ui/userobjects/ObjectNameUserConfigurableObjectFieldViewEditHandler.java b/src/com/quollwriter/ui/userobjects/ObjectNameUserConfigurableObjectFieldViewEditHandler.java deleted file mode 100644 index 92ff2aa8..00000000 --- a/src/com/quollwriter/ui/userobjects/ObjectNameUserConfigurableObjectFieldViewEditHandler.java +++ /dev/null @@ -1,165 +0,0 @@ -package com.quollwriter.ui.userobjects; - -import java.awt.event.*; - -import java.util.Map; -import java.util.Set; -import java.util.LinkedHashSet; -import java.util.ArrayList; - -import javax.swing.*; - -import com.gentlyweb.utils.*; - -import com.quollwriter.*; -import com.quollwriter.ui.*; -import com.quollwriter.ui.forms.*; -import com.quollwriter.data.*; - -public class ObjectNameUserConfigurableObjectFieldViewEditHandler extends AbstractUserConfigurableObjectFieldViewEditHandler -{ - - private TextFormItem editItem = null; - - public ObjectNameUserConfigurableObjectFieldViewEditHandler (ObjectNameUserConfigurableObjectTypeField typeField, - UserConfigurableObject obj, - UserConfigurableObjectField field, - AbstractProjectViewer viewer) - { - - super (typeField, - obj, - field, - viewer); - - } - - public TextFormItem getInputFormItem () - { - - return this.editItem; - - } - - @Override - public void grabInputFocus () - { - - this.editItem.getComponent ().grabFocus (); - - } - - @Override - public Set getInputFormItems (String initValue, - ActionListener formSave) - { - - Set items = new LinkedHashSet (); - - this.editItem = new TextFormItem (this.typeField.getFormName (), - this.obj.getName () != null ? this.obj.getName () : initValue); - - UIUtils.addDoActionOnReturnPressed (this.editItem.getTextField (), - formSave); - - items.add (this.editItem); - - return items; - - } - - @Override - public Set getInputFormItemErrors () - { - - java.util.List prefix = new ArrayList (); - prefix.add (LanguageStrings.form); - prefix.add (LanguageStrings.addedit); - prefix.add (LanguageStrings.types); - prefix.add (UserConfigurableObjectTypeField.Type.objectname.getType ()); - prefix.add (LanguageStrings.errors); - - Set errs = new LinkedHashSet (); - - String name = this.getInputSaveValue (); - - if (name == null) - { - - errs.add (String.format (Environment.getUIString (prefix, - LanguageStrings.novalue), - this.typeField.getFormName ())); - //+ " must be provided."); - - } else { - - Asset a = this.viewer.getProject ().getAssetByName (name, - this.obj.getUserConfigurableObjectType ()); - - if ((a != null) - && - (this.obj.getKey () != a.getKey ()) - ) - { - - errs.add (String.format (Environment.getUIString (prefix, - LanguageStrings.valueexists), - a.getObjectTypeName (), - a.getName ())); - - } - - } - - return errs; - - } - - @Override - public void updateFieldFromInput () - { - - this.obj.setName (this.getInputSaveValue ()); - - } - - @Override - public String getInputSaveValue () - { - - return this.editItem.getValue (); - - } - - @Override - public String valueToString (String val) - { - - return val; - - } - - @Override - public String stringToValue (String s) - { - - return s; - - } - - @Override - public Set getViewFormItems () - { - - Set items = new LinkedHashSet (); - - String v = this.obj.getName (); - - items.add (new AnyFormItem (this.typeField.getFormName (), - new JLabel (v))); - - return items; - - } - -} diff --git a/src/com/quollwriter/ui/userobjects/ObjectNameUserConfigurableObjectTypeFieldConfigHandler.java b/src/com/quollwriter/ui/userobjects/ObjectNameUserConfigurableObjectTypeFieldConfigHandler.java deleted file mode 100644 index 1fb130df..00000000 --- a/src/com/quollwriter/ui/userobjects/ObjectNameUserConfigurableObjectTypeFieldConfigHandler.java +++ /dev/null @@ -1,89 +0,0 @@ -package com.quollwriter.ui.userobjects; - -import java.util.Map; -import java.util.Set; -import java.util.LinkedHashSet; - -import javax.swing.*; - -import com.gentlyweb.utils.*; - -import com.quollwriter.*; -import com.quollwriter.ui.*; -import com.quollwriter.ui.forms.*; -import com.quollwriter.data.*; - -public class ObjectNameUserConfigurableObjectTypeFieldConfigHandler implements UserConfigurableObjectTypeFieldConfigHandler -{ - - private ObjectNameUserConfigurableObjectTypeField field = null; - - public ObjectNameUserConfigurableObjectTypeFieldConfigHandler (ObjectNameUserConfigurableObjectTypeField field) - { - - this.field = field; - - } - - public String getObjName () - { - - return this.field.getUserConfigurableObjectType ().getObjectTypeName ().toLowerCase (); - - } - - public String replaceObjName (String s) - { - - return String.format (s, - this.getObjName ()); - - } - - @Override - public String getConfigurationDescription () - { - - Set strs = new LinkedHashSet (); - - strs.add (this.replaceObjName (Environment.getUIString (LanguageStrings.form, - LanguageStrings.config, - LanguageStrings.types, - UserConfigurableObjectTypeField.Type.objectname.getType (), - LanguageStrings.description))); - //"is the %s name")); - - return Utils.joinStrings (strs, - null); - - } - - @Override - public boolean updateFromExtraFormItems () - { - - return true; - - } - - @Override - public Set getExtraFormItemErrors (UserConfigurableObjectType objType) - { - - Set errors = new LinkedHashSet (); - - return errors; - - } - - @Override - public Set getExtraFormItems () - { - - Set nitems = new LinkedHashSet (); - - return nitems; - - } - -} diff --git a/src/com/quollwriter/ui/userobjects/SelectUserConfigurableObjectFieldViewEditHandler.java b/src/com/quollwriter/ui/userobjects/SelectUserConfigurableObjectFieldViewEditHandler.java deleted file mode 100644 index 8e9e9586..00000000 --- a/src/com/quollwriter/ui/userobjects/SelectUserConfigurableObjectFieldViewEditHandler.java +++ /dev/null @@ -1,184 +0,0 @@ -package com.quollwriter.ui.userobjects; - -import java.awt.event.*; -import java.util.*; - -import javax.swing.*; - -import com.gentlyweb.utils.*; - -import com.quollwriter.*; -import com.quollwriter.ui.*; -import com.quollwriter.ui.forms.*; -import com.quollwriter.data.*; - -public class SelectUserConfigurableObjectFieldViewEditHandler extends AbstractUserConfigurableObjectFieldViewEditHandler> -{ - - private SelectFormItem editItem = null; - - public SelectUserConfigurableObjectFieldViewEditHandler (SelectUserConfigurableObjectTypeField typeField, - UserConfigurableObject obj, - UserConfigurableObjectField field, - AbstractProjectViewer viewer) - { - - super (typeField, - obj, - field, - viewer); - - } - - @Override - public void grabInputFocus () - { - - this.editItem.getComponent ().grabFocus (); - - } - - @Override - public Set getInputFormItems (String initValue, - ActionListener formSave) - { - - Set sel = new LinkedHashSet (); - - if (this.getFieldValue () != null) - { - - sel.addAll (this.getFieldValue ()); - - } else { - - if (initValue != null) - { - - sel.add (initValue); - - } - - } - - this.editItem = new SelectFormItem (this.typeField.getFormName (), - new Vector (this.typeField.getItems ()), - (this.typeField.isAllowMulti () ? 5 : 1), - sel, - Short.MAX_VALUE, - false, - null); - - Set items = new LinkedHashSet (); - - items.add (this.editItem); - - return items; - - } - - @Override - public Set getInputFormItemErrors () - { - - return null; - - } - - @Override - public Set getInputSaveValue () - { - - return this.editItem.getValue (); - - } - - @Override - public String valueToString (Set val) - throws GeneralException - { - - if (val == null) - { - - return null; - - } - - try - { - - return JSONEncoder.encode (val); - - } catch (Exception e) { - - throw new GeneralException ("Unable to encode values: " + - val, - e); - - } - - } - - @Override - public Set stringToValue (String s) - { - - if (s == null) - { - - return null; - - } - - return new LinkedHashSet ((Collection) JSONDecoder.decode (s)); - - } - - @Override - public Set getViewFormItems () - { - - java.util.List prefix = new ArrayList (); - prefix.add (LanguageStrings.form); - prefix.add (LanguageStrings.view); - prefix.add (LanguageStrings.types); - prefix.add (UserConfigurableObjectTypeField.Type.select.getType ()); - - Set items = new LinkedHashSet (); - - String label = Environment.getUIString (prefix, - LanguageStrings.novalue); - //"Not provided."; - - Set value = null; - - if (this.field != null) - { - - value = (Set) this.field.getValue (); - - } - - if ((value != null) - && - (value.size () > 0) - ) - { - - items.add (new AnyFormItem (this.typeField.getFormName (), - UIUtils.createLabel (Utils.joinStrings (value, Environment.getUIString (prefix, - LanguageStrings.valueseparator))))); - - } else { - - items.add (this.createNoValueItem (Environment.getUIString (prefix, - LanguageStrings.novalue))); - - } - - return items; - - } - -} diff --git a/src/com/quollwriter/ui/userobjects/TextUserConfigurableObjectFieldViewEditHandler.java b/src/com/quollwriter/ui/userobjects/TextUserConfigurableObjectFieldViewEditHandler.java deleted file mode 100644 index 2b8f7952..00000000 --- a/src/com/quollwriter/ui/userobjects/TextUserConfigurableObjectFieldViewEditHandler.java +++ /dev/null @@ -1,222 +0,0 @@ -package com.quollwriter.ui.userobjects; - -import java.awt.event.*; -import java.util.Map; -import java.util.Set; -import java.util.LinkedHashSet; -import java.util.StringTokenizer; -import java.util.ArrayList; - -import javax.swing.*; - -import com.gentlyweb.utils.*; - -import com.quollwriter.*; -import com.quollwriter.ui.*; -import com.quollwriter.ui.forms.*; -import com.quollwriter.data.*; - -public class TextUserConfigurableObjectFieldViewEditHandler extends AbstractUserConfigurableObjectFieldViewEditHandler -{ - - private JTextField editItem = null; - //private MultiLineTextFormItem editItem = null; - - public TextUserConfigurableObjectFieldViewEditHandler (TextUserConfigurableObjectTypeField typeField, - UserConfigurableObject obj, - UserConfigurableObjectField field, - AbstractProjectViewer viewer) - { - - super (typeField, - obj, - field, - viewer); - - //this.typeField = (TextUserConfigurableObjectTypeField) this.field.getUserConfigurableObjectTypeField (); - - } - - @Override - public Set getNamesFromFieldValue () - { - - Set ret = new LinkedHashSet (); - - StringWithMarkup sm = this.getFieldValue (); - - if (sm != null) - { - - String st = sm.getText (); - - if (st != null) - { - - StringTokenizer t = new StringTokenizer (st, - ";,"); - - while (t.hasMoreTokens ()) - { - - ret.add (t.nextToken ().trim ()); - - } - - } - - } - - return ret; - - } - - @Override - public void grabInputFocus () - { - - if (this.editItem != null) - { - - this.editItem.grabFocus (); - - } - - } - - @Override - public Set getInputFormItems (String initValue, - ActionListener formSave) - { - - Set items = new LinkedHashSet (); - - this.editItem = UIUtils.createTextField (); - - UIUtils.addDoActionOnReturnPressed (this.editItem, - formSave); - - - StringWithMarkup text = this.getFieldValue (); - - if (text != null) - { - - this.editItem.setText (text.getText ()); - - } else { - - if (initValue != null) - { - - this.editItem.setText (initValue); - - } - - } - - if (this.typeField.isNameField ()) - { - - java.util.List prefix = new ArrayList (); - prefix.add (LanguageStrings.form); - prefix.add (LanguageStrings.addedit); - prefix.add (LanguageStrings.types); - prefix.add (UserConfigurableObjectTypeField.Type.text.getType ()); - prefix.add (LanguageStrings.othernames); - - this.editItem.setToolTipText (Environment.getUIString (prefix, - LanguageStrings.tooltip)); - //"Separate each name/alias with a comma or a semi-colon."); - - } - - items.add (new AnyFormItem (this.typeField.getFormName (), - this.editItem)); - - return items; - - } - - @Override - public Set getInputFormItemErrors () - { - - return null; - - } - - @Override - public StringWithMarkup getInputSaveValue () - { - - return new StringWithMarkup (this.editItem.getText ()); - - } - - @Override - public String valueToString (StringWithMarkup val) - throws GeneralException - { - - try - { - - return JSONEncoder.encode (val); - - } catch (Exception e) { - - throw new GeneralException ("Unable to encode value to a string", - e); - - } - - } - - @Override - public StringWithMarkup stringToValue (String s) - { - - return JSONDecoder.decodeToStringWithMarkup (s); - - } - - @Override - public Set getViewFormItems () - { - - Set items = new LinkedHashSet (); - - StringWithMarkup text = this.getFieldValue (); - - if ((text != null) - && - (text.hasText ()) - ) - { - - JComponent t = UIUtils.createObjectDescriptionViewPane (text, - this.field.getParentObject (), - this.viewer, - null); - - t.setBorder (null); - - items.add (new AnyFormItem (this.typeField.getFormName (), - t)); - - } else { - - items.add (this.createNoValueItem (Environment.getUIString (LanguageStrings.form, - LanguageStrings.view, - LanguageStrings.types, - UserConfigurableObjectTypeField.Type.text.getType (), - LanguageStrings.novalue))); - - } - - return items; - - } - -} diff --git a/src/com/quollwriter/ui/userobjects/TextUserConfigurableObjectTypeFieldConfigHandler.java b/src/com/quollwriter/ui/userobjects/TextUserConfigurableObjectTypeFieldConfigHandler.java deleted file mode 100644 index 0e03841c..00000000 --- a/src/com/quollwriter/ui/userobjects/TextUserConfigurableObjectTypeFieldConfigHandler.java +++ /dev/null @@ -1,130 +0,0 @@ -package com.quollwriter.ui.userobjects; - -import java.util.Map; -import java.util.Set; -import java.util.LinkedHashSet; -import java.util.ArrayList; - -import javax.swing.*; - -import com.gentlyweb.utils.*; - -import com.quollwriter.*; -import com.quollwriter.ui.*; -import com.quollwriter.ui.forms.*; -import com.quollwriter.data.*; - -public class TextUserConfigurableObjectTypeFieldConfigHandler implements UserConfigurableObjectTypeFieldConfigHandler -{ - - private TextUserConfigurableObjectTypeField field = null; - private CheckboxFormItem isOtherNames = null; - - public TextUserConfigurableObjectTypeFieldConfigHandler (TextUserConfigurableObjectTypeField field) - { - - this.field = field; - - java.util.List prefix = new ArrayList (); - prefix.add (LanguageStrings.form); - prefix.add (LanguageStrings.config); - prefix.add (LanguageStrings.types); - prefix.add (UserConfigurableObjectTypeField.Type.text.getType ()); - prefix.add (LanguageStrings.othernames); - - this.isOtherNames = new CheckboxFormItem (null, - this.replaceObjName (Environment.getUIString (prefix, - LanguageStrings.text)), - //"Is other names/aliases for the %s"), - false, - this.replaceObjName (Environment.getUIString (prefix, - LanguageStrings.tooltip))); - //"Check this box to mark this field as other name or aliases for the %s. Separate each name/alias with a new line, a comma or a semi-colon.")); - - } - - public String getObjName () - { - - return this.field.getUserConfigurableObjectType ().getObjectTypeName ().toLowerCase (); - - } - - public String replaceObjName (String s) - { - - return String.format (s, - this.getObjName ()); - /* - return StringUtils.replaceString (s, - "%s", - this.getObjName ()); - */ - } - - @Override - public String getConfigurationDescription () - { - - java.util.List prefix = new ArrayList (); - prefix.add (LanguageStrings.form); - prefix.add (LanguageStrings.config); - prefix.add (LanguageStrings.types); - prefix.add (UserConfigurableObjectTypeField.Type.text.getType ()); - - Set strs = new LinkedHashSet (); - - strs.add (Environment.getUIString (prefix, - LanguageStrings.description)); - //"single line text"); - - if (this.field.isNameField ()) - { - - strs.add (this.replaceObjName (Environment.getUIString (prefix, - LanguageStrings.othernames, - LanguageStrings.description))); - //"is other names/aliases for the %s")); - - } - - return Utils.joinStrings (strs, - null); - - } - - @Override - public boolean updateFromExtraFormItems () - { - - this.field.setNameField (this.isOtherNames.isSelected ()); - - return true; - - } - - @Override - public Set getExtraFormItemErrors (UserConfigurableObjectType objType) - { - - Set errors = new LinkedHashSet (); - - return errors; - - } - - @Override - public Set getExtraFormItems () - { - - Set nitems = new LinkedHashSet (); - - this.isOtherNames.setSelected (this.field.isNameField ()); - - nitems.add (this.isOtherNames); - - return nitems; - - } - -} diff --git a/src/com/quollwriter/ui/userobjects/WebpageUserConfigurableObjectFieldViewEditHandler.java b/src/com/quollwriter/ui/userobjects/WebpageUserConfigurableObjectFieldViewEditHandler.java deleted file mode 100644 index 2517aa50..00000000 --- a/src/com/quollwriter/ui/userobjects/WebpageUserConfigurableObjectFieldViewEditHandler.java +++ /dev/null @@ -1,139 +0,0 @@ -package com.quollwriter.ui.userobjects; - -import java.awt.event.*; -import java.util.Map; -import java.util.Set; -import java.util.LinkedHashSet; - -import javax.swing.*; - -import com.gentlyweb.utils.*; - -import com.quollwriter.*; -import com.quollwriter.ui.*; -import com.quollwriter.ui.forms.*; -import com.quollwriter.data.*; - -public class WebpageUserConfigurableObjectFieldViewEditHandler extends AbstractUserConfigurableObjectFieldViewEditHandler -{ - - private TextFormItem editItem = null; - - public WebpageUserConfigurableObjectFieldViewEditHandler (WebpageUserConfigurableObjectTypeField typeField, - UserConfigurableObject obj, - UserConfigurableObjectField field, - AbstractProjectViewer viewer) - { - - super (typeField, - obj, - field, - viewer); - - } - - @Override - public void grabInputFocus () - { - - if (this.editItem != null) - { - - this.editItem.grabFocus (); - - } - - } - - @Override - public Set getInputFormItems (String initValue, - ActionListener formSave) - { - - Set items = new LinkedHashSet (); - - this.editItem = new TextFormItem (this.typeField.getFormName (), - (this.field != null ? (String) this.field.getValue () : initValue)); - - UIUtils.addDoActionOnReturnPressed (this.editItem.getTextField (), - formSave); - - items.add (this.editItem); - - return items; - - } - - @Override - public Set getInputFormItemErrors () - { - - return null; - - } - - @Override - public String getInputSaveValue () - { - - return this.editItem.getValue (); - - } - - @Override - public String valueToString (String val) - { - - return val; - - } - - @Override - public String stringToValue (String s) - { - - return s; - - } - - @Override - public Set getViewFormItems () - { - - Set items = new LinkedHashSet (); - - String value = (this.field != null ? (String) this.field.getValue () : null); - - if (value != null) - { - - if ((!value.startsWith ("http://")) - && - (!value.startsWith ("https://")) - ) - { - - value = "http://" + value; - - } - - items.add (new AnyFormItem (this.typeField.getFormName (), - UIUtils.createClickableLabel (value, - null, - value))); - - } else { - - items.add (this.createNoValueItem (Environment.getUIString (LanguageStrings.form, - LanguageStrings.view, - LanguageStrings.types, - LanguageStrings.webpage, - LanguageStrings.novalue))); - - } - - return items; - - } - -} diff --git a/src/com/quollwriter/Base64.java b/src/main/java/com/quollwriter/Base64.java similarity index 100% rename from src/com/quollwriter/Base64.java rename to src/main/java/com/quollwriter/Base64.java diff --git a/src/com/quollwriter/BlankTimerTask.java b/src/main/java/com/quollwriter/BlankTimerTask.java similarity index 100% rename from src/com/quollwriter/BlankTimerTask.java rename to src/main/java/com/quollwriter/BlankTimerTask.java diff --git a/src/com/quollwriter/Constants.java b/src/main/java/com/quollwriter/Constants.java similarity index 82% rename from src/com/quollwriter/Constants.java rename to src/main/java/com/quollwriter/Constants.java index a1485529..4958c6fd 100644 --- a/src/com/quollwriter/Constants.java +++ b/src/main/java/com/quollwriter/Constants.java @@ -3,6 +3,8 @@ public class Constants { + public static String GZIP_EXTENSION = ".gz"; + public static final int SEC_IN_MILLIS = 1000; public static final int MIN_IN_MILLIS = 60 * SEC_IN_MILLIS; @@ -11,6 +13,9 @@ public class Constants public static final long DAY_IN_MILLIS = 24 * HOUR_IN_MILLIS; + public static final int DEFAULT_WORDS = 500; + public static final int DEFAULT_MINS = 30; + public static final int ICON_MENU = 1; public static final int ICON_TOOLBAR = 2; @@ -127,6 +132,22 @@ public class Constants public static final String BACKUPS_HTML_PANEL_ACTION = "backups"; + public static final String FULL_SCREEN_HEADER_CONTROL_BUTTON_IDS_PROPERTY_NAME = "fullScreenHeaderControlButtonIds"; + + public static final String PROJECT_VIEWER_HEADER_CONTROL_BUTTON_IDS_PROPERTY_NAME = "projectViewerHeaderControlButtonIds"; + + public static final String WARMUP_VIEWER_HEADER_CONTROL_BUTTON_IDS_PROPERTY_NAME = "warmupViewerHeaderControlButtonIds"; + + public static final String ALL_PROJECTS_VIEWER_HEADER_CONTROL_BUTTONS_IDS_PROPERTY_NAME = "allProjectsViewerHeaderControlButtonIds"; + + public static final String LANGUAGE_STRINGS_EDITOR_HEADER_CONTROL_BUTTON_IDS_PROPERTY_NAME = "languageStringsEditorHeaderControlButtonIds"; + + public static final String DEFAULT_UI_BASE_FONT_SIZE_PROPERTY_NAME = "defaultUIBaseFontSIze"; + + public static final String UI_BASE_FONT_SIZE_PROPERTY_NAME = "uiBaseFontSize"; + + public static final String UI_BASE_FONT_PROPERTY_NAME = "uiBaseFont"; + public static final String COPYRIGHT_PROPERTY_NAME = "copyright"; public static final String SOURCE_CODE_WEBSITE_PROPERTY_NAME = "sourceCodeWebsite"; @@ -135,6 +156,10 @@ public class Constants public static final String GOFUNDME_WEBSITE_PROPERTY_NAME = "gofundmeWebsite"; + public static final String SEEN_ASKED_NIGHT_MODE_ENABLE_PERMANENT_PROPERTY_NAME = "seenAskedNightModeEnablePermanent"; + + public static final String NIGHT_MODE_ENABLE_PERMENANTLY_PROPERTY_NAME = "nightModeEnabledPermanently"; + public static final String DEFAULT_UI_LANGUAGE_PROPERTY_NAME = "defaultUILanguage"; public static final String USER_UI_LANGUAGE_PROPERTY_NAME = "userUILanguage"; @@ -147,6 +172,8 @@ public class Constants public static final String CLOSE_PROJECTS_WINDOW_WHEN_PROJECT_OPENED_PROPERTY_NAME = "closeProjectsWindowWhenProjectOpened"; + public static final String KEEP_PROJECTS_WINDOW_WHEN_PROJECT_OPENED_PROPERTY_NAME = "keepProjectsWindowWhenProjectOpened"; + public static final String SHOW_PROJECTS_WINDOW_WHEN_NO_OPEN_PROJECTS_PROPERTY_NAME = "showProjectsWindowWhenNoOpenProjects"; public static final String PROJECT_INFO_DB_DIR_PROPERTY_NAME = "projctInfoDBDir"; @@ -175,6 +202,24 @@ public class Constants public static final String DELETE_UI_LANGUAGE_STRINGS_URL_PROPERTY_NAME = "quollWriterDeleteUILanguageStringsURL"; + public static final String SUBMIT_WEBSITE_LANGUAGE_STRINGS_URL_PROPERTY_NAME = "quollWriterSubmitWebsiteLanguageStringsURL"; + + public static final String TRYOUT_WEBSITE_LANGUAGE_STRINGS_URL_PROPERTY_NAME = "quollWriterTryoutWebsiteLanguageStringsURL"; + + public static final String DELETE_WEBSITE_LANGUAGE_STRINGS_URL_PROPERTY_NAME = "quollWriterDeleteWebsiteLanguageStringsURL"; + + public static final String FIND_HIGHLIGHT_COLOR_PROPERTY_NAME = "findHighlightColor"; + + public static final String SYNONYM_HIGHLIGHT_COLOR_PROPERTY_NAME = "synonymHighlightColor"; + + public static final String PROBLEM_FINDER_BLOCK_HIGHLIGHT_COLOR_PROPERTY_NAME = "problemFinderBlockHighlightColor"; + + public static final String PROBLEM_FINDER_ISSUE_HIGHLIGHT_COLOR_PROPERTY_NAME = "problemFinderIssueHighlightColor"; + + public static final String EDIT_NEEDED_NOTE_CHAPTER_HIGHLIGHT_COLOR_PROPERTY_NAME = "editNeededNoteChapterHighlightColor"; + + public static final String EDITOR_COMMENT_CHAPTER_HIGHLIGHT_COLOR_PROPERTY_NAME = "editorCommentChapterHighlightColor"; + public static final String EDIT_MARKER_COLOR_PROPERTY_NAME = "editMarkerColor"; public static final String COMPRESS_CHAPTER_CONTEXT_MENU_PROPERTY_NAME = "compressChapterContextMenu"; @@ -183,10 +228,20 @@ public class Constants public static final String COLOR_SWATCHES_PROPERTY_NAME = "colorSwatches"; + public static final Integer DEFAULT_CHAPTER_AUTO_SAVE_TIME = 5 * Constants.MIN_IN_MILLIS; + + public static final String AUTO_NIGHT_MODE_ENABLED_PROPERTY_NAME = "autoNightModeEnabled"; + + public static final String AUTO_NIGHT_MODE_TO_PROPERTY_NAME = "autoNightModeTo"; + + public static final String AUTO_NIGHT_MODE_FROM_PROPERTY_NAME = "autoNightModeFrom"; + public static final String CHAPTER_AUTO_SAVE_INTERVAL_PROPERTY_NAME = "chapterAutoSaveInterval"; public static final String CHAPTER_AUTO_SAVE_ENABLED_PROPERTY_NAME = "chapterAutoSaveEnabled"; + public static final Integer DEFAULT_AUTO_SNAPSHOTS_SAVE_TIME = 12 * Constants.HOUR_IN_MILLIS; + public static final String AUTO_SNAPSHOTS_ENABLED_PROPERTY_NAME = "enableAutoSnapshots"; public static final String AUTO_SNAPSHOTS_TIME_PROPERTY_NAME = "autoSnapshotsTime"; @@ -195,6 +250,8 @@ public class Constants public static final String USER_UI_LANGUAGES_DIR_NAME = Constants.UI_LANGUAGES_DIR_NAME + "/user"; + public static final String USER_WEBSITE_LANGUAGES_DIR_NAME = Constants.UI_LANGUAGES_DIR_NAME + "/website"; + public static final String DATE_FORMAT_PROPERTY_NAME = "dateFormat"; public static final String OPEN_TABS_PROPERTY_NAME = "openTabIds"; @@ -213,8 +270,20 @@ public class Constants public static final String WINDOW_WIDTH_PROPERTY_NAME = "windowWidth"; + public static final String WINDOW_TOP_LOCATION_PROPERTY_NAME = "windowTopLocation"; + + public static final String WINDOW_LEFT_LOCATION_PROPERTY_NAME = "windowLeftLocation"; + + public static final String PROJECT_STATE_PROPERTY_NAME = "projectState"; + + public static final String WINDOW_MAXIMIZED_PROPERTY_NAME = "windowMaximized"; + public static final String SPELL_CHECKING_ENABLED_PROPERTY_NAME = "spellCheckingEnabled"; + public static final String LAST_EDITOR_VISIBLE_PARAGRAPH_PROPERTY_NAME = "lastEditorVisibleParagraph"; + + public static final String LAST_EDITOR_SCROLL_OFFSET_PROPERTY_NAME = "lastEditorScrollOffset"; + public static final String LAST_EDITOR_CARET_POSITION_PROPERTY_NAME = "lastEditorCaretPosition"; public static final String LAST_EDITOR_SCROLL_POSITION_PROPERTY_NAME = "lastEditorScrollPosition"; @@ -225,6 +294,8 @@ public class Constants public static final String ASSET_RIGHT_SPLIT_PANE_DIVIDER_LOCATION_PROPERTY_NAME = "assetRightSplitPaneDividerLocation"; + public static final String USER_CONFIGURABLE_OBJECT_TYPE_SORTABLE_FIELDS_LAYOUT_PROPERTY_NAME = "userConfigurableObjectTypeSortableFieldsLayout"; + public static final String COMPACT_MENUS_PROPERTY_NAME = "compactMenus"; public static final String DEFAULT_EDITOR_WRITING_LINE_COLOR_PROPERTY_NAME = "defaultEditorWritingLineColor"; @@ -247,6 +318,8 @@ public class Constants public static final String EDITOR_WRITING_LINE_COLOR_PROPERTY_NAME = "editorWritingLineColor"; + public static final String EDITOR_WRITING_LINE_COLOR_NIGHT_MODE_PROPERTY_NAME = "editorWritingLineColorNightMode"; + public static final String EDITOR_HIGHLIGHT_WRITING_LINE_PROPERTY_NAME = "editorHighlightWritingLine"; public static final String EDITOR_USE_TYPEWRITER_SCROLLING_PROPERTY_NAME = "editorUseTypewriterScrolling"; @@ -255,6 +328,10 @@ public class Constants public static final String EDITOR_FONT_PROPERTY_NAME = "editorFont"; + public static final String EDITOR_FONT_COLOR_NIGHT_MODE_PROPERTY_NAME = "editorFontColorNightMode"; + + public static final String EDITOR_BGCOLOR_NIGHT_MODE_PROPERTY_NAME = "editorBGColorNightMode"; + public static final String EDITOR_FONT_COLOR_PROPERTY_NAME = "editorFontColor"; public static final String EDITOR_BGCOLOR_PROPERTY_NAME = "editorBGColor"; @@ -263,6 +340,8 @@ public class Constants public static final String EDITOR_LINE_SPACING_PROPERTY_NAME = "editorLineSpacing"; + public static final String EDITOR_PARAGRAPH_SPACING_PROPERTY_NAME = "editorParagraphSpacing"; + public static final String EDITOR_ALIGNMENT_PROPERTY_NAME = "editorAlignment"; public static final String EDITOR_TEXT_BORDER_PROPERTY_NAME = "editorTextBorder"; @@ -293,6 +372,8 @@ public class Constants public static final String QUOLL_WRITER_WEBSITE_PROPERTY_NAME = "quollWriterWebsite"; + public static final String QUOLL_WRITER_WEBSITE_PROMPTS_LINK_PROPERTY_NAME = "quollWriterWebsitePromptsLinks"; + public static final String QUOLL_WRITER_DEBUG_WEBSITE_PROPERTY_NAME = "quollWriterDebugWebsite"; public static final String QUOLL_WRITER_LANGUAGE_FILES_URL_PROPERTY_NAME = "quollWriterLanguageFilesUrl"; @@ -311,6 +392,8 @@ public class Constants public static final String QUOLL_WRITER_GET_UI_LANGUAGE_STRINGS_URL_PROPERTY_NAME = "quollWriterGetUILanguageStringsUrl"; + public static final String QUOLL_WRITER_GET_WEBSITE_LANGUAGE_STRINGS_URL_PROPERTY_NAME = "quollWriterGetWebsiteLanguageStringsUrl"; + public static final String WRITING_GENRES_PROPERTY_NAME = "writingGenres"; //public static final String BUG_REPORT_MAILTO_URI_PROPERTY_NAME = "bugReportMailtoURI"; @@ -333,6 +416,8 @@ public class Constants public static final String FULL_SCREEN_EDITOR_WRITING_LINE_COLOR_PROPERTY_NAME = "fullScreenEditorWritingLineColor"; + public static final String FULL_SCREEN_EDITOR_WRITING_LINE_COLOR_NIGHT_MODE_PROPERTY_NAME = "fullScreenEditorWritingLineColorNightMode"; + public static final String FULL_SCREEN_EDITOR_HIGHLIGHT_WRITING_LINE_PROPERTY_NAME = "fullScreenEditorHighlightWritingLine"; public static final String FULL_SCREEN_SIDEBAR_WIDTH_PROPERTY_NAME = "fullScreenSidebarWidth"; @@ -349,9 +434,13 @@ public class Constants public static final String FULL_SCREEN_EDITOR_INDENT_FIRST_LINE_PROPERTY_NAME = "fullScreenEditorIndentFirstLine"; + public static final String FULL_SCREEN_EDITOR_FONT_COLOR_NIGHT_MODE_PROPERTY_NAME = "fullScreenEditorFontColorNightMode"; + public static final String FULL_SCREEN_EDITOR_FONT_COLOR_PROPERTY_NAME = "fullScreenEditorFontColor"; - public static final String FULL_SCREEN_EDITOR_FONT_BGCOLOR_PROPERTY_NAME = "fullScreenEditorFontBGColor"; + public static final String FULL_SCREEN_EDITOR_BGCOLOR_PROPERTY_NAME = "fullScreenEditorFontBGColor"; + + public static final String FULL_SCREEN_EDITOR_BGCOLOR_NIGHT_MODE_PROPERTY_NAME = "fullScreenEditorFontBGColorNightMode"; public static final String FULL_SCREEN_EDITOR_FONT_PROPERTY_NAME = "fullScreenEdiorFont"; @@ -359,6 +448,8 @@ public class Constants public static final String FULL_SCREEN_EDITOR_LINE_SPACING_PROPERTY_NAME = "fullScreenEditorLineSpacing"; + public static final String FULL_SCREEN_EDITOR_PARAGRAPH_SPACING_PROPERTY_NAME = "fullScreenEditorParagraphSpacing"; + public static final String FULL_SCREEN_EDITOR_ALIGNMENT_PROPERTY_NAME = "fullScreenEditorAlignment"; public static final String FULL_SCREEN_EDITOR_TEXT_BORDER_PROPERTY_NAME = "fullScreenEditorTextBorder"; @@ -381,12 +472,16 @@ public class Constants public static final String DATA_HBM_XML_FILE_NAME = "data.hbm.xml"; + public static final String USER_DICTIONARY_WORDS_PROPERTY_NAME = "userDictionaryWords"; + public static final String USER_DICTIONARY_FILE_NAME = "user.dict"; public static final String DEFAULT_PROJECTS_DIR_NAME = "projects"; public static final String PROJECT_FILES_DIR_NAME = "files"; + public static final String UI_LANGUAGE_STRINGS_SPELL_CHECK_LANGUAGE_PROPERTY_NAME = "uiLanguageStringsSpellCheckLanguage"; + public static final String SPELL_CHECK_LANGUAGE_PROPERTY_NAME = "spellCheckLanugage"; public static final String DEFAULT_SPELL_CHECK_LANGUAGE_PROPERTY_NAME = "defaultSpellCheckLanugage"; @@ -453,6 +548,10 @@ public class Constants public static final String DEFAULT_CHAPTER_INFO_PREVIEW_FORMAT = "defaultChapterInfoPreviewFormat"; public static final String DEBUG_MODE_PROPERTY_NAME = "debugMode"; + + // Note this is based on the size in the server which is set by system property: xmpp.parser.buffer.size + public static final int EDITORS_SERVICE_MAX_MESSAGE_SIZE = 5242880; + public static final int EDITORS_SERVICE_AVATAR_MAX_WIDTH = 120; public static final String EDITORS_SERVICE_HOST_PROPERTY_NAME = "editorsServiceHost"; public static final String EDITORS_SERVICE_PORT_PROPERTY_NAME = "editorsServicePort"; public static final String EDITORS_SERVICE_REPORT_MESSAGE_PAGE_PROPERTY_NAME = "editorsServiceReportMessagePage"; @@ -472,6 +571,8 @@ public class Constants public static final String AUTO_SEND_ERRORS_TO_SUPPORT_PROPERTY_NAME = "autoSendErrorsToSupport"; + public static final Integer DEFAULT_BACKUPS_TO_KEEP = -1; + public static final String BACKUPS_TO_KEEP_COUNT_PROPERTY_NAME = "backupsToKeepCount"; public static final String DEFAULT_PROJECT_SIDEBAR_SECTIONS_PROPERTY_NAME = "defaultProjectSidebarSections"; @@ -496,14 +597,23 @@ public class Constants public static final String USER_PROMPTS_FILE = "own-prompts.xml"; public static final String TRANSPARENT_PNG_NAME = "16x16-transparent.png"; - public static final String WINDOW_ICON_PNG_NAME = "window-icon-v3.png"; + //public static final String WINDOW_ICON_PNG_NAME = "window-icon-v3.png"; + public static final String WINDOW_ICON_PNG_NAME = "window-icon-v6.png"; public static final String LOGO_PNG_NAME = "q-app-logo.png"; //"logo-v2.png"; public static final String LOADING_GIF_NAME = "loading24.gif"; public static final String TYPING_GIF_NAME = "typing24.gif"; + public static final String BACKUP_FILE_NAME_PREFIX = "backup"; + public static final String BACKUP_FILE_NAME_SUFFIX = ".zip"; + public static final String PROJECT_DB_FILE_NAME_PREFIX = "projectdb"; public static final String QUOLL_WRITER_DIR_NAME = "QuollWriter"; + public static final String H2_DB_FILE_SUFFIX = ".h2.db"; + + public static final String FULL_PROJECT_DB_FILE_NAME = PROJECT_DB_FILE_NAME_PREFIX + H2_DB_FILE_SUFFIX; + public static final String FULL_OLD_PROJECT_DB_FILE_NAME = PROJECT_DB_FILE_NAME_PREFIX + H2_DB_FILE_SUFFIX + ".old"; + public static final String PROPERTIES_FILE_NAME = "properties.xml"; public static final String PROJECTS_FILE_NAME = "projects.xml"; @@ -519,6 +629,15 @@ public class Constants public static final String EDITORS_EDITOR_FILE_NAME = "editor.xml"; + public static final String LEGACY_CHARACTER_SMALL_ICON_IMAGE_NAME = "/imgs/character16.png"; + public static final String LEGACY_CHARACTER_LARGE_ICON_IMAGE_NAME = "/imgs/character24.png"; + public static final String LEGACY_LOCATION_SMALL_ICON_IMAGE_NAME = "/imgs/location16.png"; + public static final String LEGACY_LOCATION_LARGE_ICON_IMAGE_NAME = "/imgs/location24.png"; + public static final String LEGACY_RESEARCHITEM_SMALL_ICON_IMAGE_NAME = "/imgs/researchitem16.png"; + public static final String LEGACY_RESEARCHITEM_LARGE_ICON_IMAGE_NAME = "/imgs/researchitem24.png"; + public static final String LEGACY_OBJECT_SMALL_ICON_IMAGE_NAME = "/imgs/object16.png"; + public static final String LEGACY_OBJECT_LARGE_ICON_IMAGE_NAME = "/imgs/object24.png"; + public static final String LEGACY_OBJECT_TYPE_NAMES_FILE_NAME = "object-type-names.xml"; public static final String OBJECT_TYPE_NAMES_FILE_NAME = "object-type-names" + JSON_FILE_EXT; @@ -537,9 +656,10 @@ public class Constants public static final String UI_LANGUAGE_STRINGS_SUBMITTER_ID_PROPERTY_NAME = "ui-language-strings-submitter-id"; public static final String UI_LANGUAGE_STRINGS_SUBMITTER_ID_HEADER_NAME = "qw-ui-language-strings-submitter-id"; - public static final String IMGS_DIR = "/imgs/"; + public static final String WEBSITE_LANGUAGE_STRINGS_SUBMITTER_ID_PROPERTY_NAME = "website-language-strings-submitter-id"; + public static final String WEBSITE_LANGUAGE_STRINGS_SUBMITTER_ID_HEADER_NAME = "qw-website-language-strings-submitter-id"; - public static final String H2_DB_FILE_SUFFIX = ".h2.db"; + public static final String IMGS_DIR = "/imgs/"; public static final String BACKGROUND_IMGS_DIR = Constants.IMGS_DIR + "bgs/"; public static final String BACKGROUND_THUMB_IMGS_DIR = Constants.BACKGROUND_IMGS_DIR + "thumbs/"; @@ -547,6 +667,7 @@ public class Constants public static final String NO_AVATAR_IMAGE_FILE_NAME = "noavatar.png"; public static final String DATA_DIR = "/data/"; + public static final String LOGGING_CONFIG_FILE_NAME = Constants.DATA_DIR + "logging.properties"; public static final String DEFAULT_UI_LANGUAGE_STRINGS_FILE = Constants.DATA_DIR + "default-ui-language-strings" + JSON_FILE_EXT; public static final String TIPS_FILE = Constants.DATA_DIR + "tips.xml"; public static final String PROBLEM_FINDER_RULES_FILE = Constants.DATA_DIR + "problem-finder-rules.xml"; @@ -557,6 +678,7 @@ public class Constants public static final String WORD_SYLLABLE_COUNTS_FILE = Constants.DATA_DIR + "word-syllable-counts.txt"; public static final String UPDATE_SCRIPTS_DIR = Constants.SCHEMA_DIR + "update-scripts"; public static final String EDITOR_UPDATE_SCRIPTS_DIR = Constants.EDITOR_SCHEMA_DIR + "update-scripts"; + public static final String WEBVIEW_HEADER_FILE = Constants.DATA_DIR + "webview-header.txt"; public static final String PROJECT_INFO_DB_FILE_NAME_PREFIX = "project-info-db"; public static final String PROJECT_INFO_SCHEMA_DIR = Constants.DATA_DIR + "project-info-schema/"; @@ -571,7 +693,7 @@ public class Constants public static final String DEFAULT_PROJECT_PROPERTIES_FILE = Constants.DATA_DIR + DEFAULT_PROJECT_PROPERTIES_FILE_NAME; public static final String DEFAULT_KEY_STROKE_SOUND_FILE = Constants.DATA_DIR + "typewriter-key.wav"; public static final String DEFAULT_ACHIEVEMENT_SOUND_FILE = Constants.DATA_DIR + "achievement.wav"; - public static final String DEFAULT_FULL_SCREEN_BG_IMAGE_FILE_NAME = "1-skyline.jpg"; + public static final String DEFAULT_FULL_SCREEN_BG_IMAGE_FILE_NAME = "bg:_1-skyline.jpg"; public static final String DEFAULT_OBJECT_TYPE_NAMES_FILE = Constants.DATA_DIR + "object-names.xml"; @@ -600,6 +722,22 @@ public class Constants public static final String DOCUMENT_NORMAL_FILE_NAME = Constants.DATA_DIR + "document-normal.png"; public static final String DOCUMENT_ERROR_FILE_NAME = Constants.DATA_DIR + "document-error.png"; + public static final String USER_STYLE_SHEET_FILE_NAME_PROPERTY_NAME = "userStyleSheet"; + public static final String DEFAULT_STYLE_SHEET_FILE_NAME = Constants.DATA_DIR + "default-style.css"; + + public static final String COMPONENT_STYLESHEET_TYPE = "components"; + public static final String POPUP_STYLESHEET_TYPE = "popups"; + public static final String VIEWER_STYLESHEET_TYPE = "viewers"; + public static final String PANEL_STYLESHEET_TYPE = "panels"; + public static final String SIDEBAR_STYLESHEET_TYPE = "sidebars"; + + /** + * The path to the stylesheet, %1$s is replaced by the type of stylesheet to add, i.e. Constants.COMPONENT_STYLESHEET_TYPE + * or Constants.POPUP_STYLESHEET_TYPE. %2$s is replaced by the actual stylesheet name, e.g. + * /data/stylesheets/components/notification.css + */ + public static final String STYLESHEET_PATH = "/data/stylesheets/%1$s/%2$s.css"; + //public static final String MINS_5 = "5 mins"; //public static final String MINS_10 = "10 mins"; //public static final String MINS_20 = "20 mins"; diff --git a/src/main/java/com/quollwriter/DOM4JUtils.java b/src/main/java/com/quollwriter/DOM4JUtils.java new file mode 100644 index 00000000..152f90b9 --- /dev/null +++ b/src/main/java/com/quollwriter/DOM4JUtils.java @@ -0,0 +1,455 @@ +package com.quollwriter; + +import java.io.*; +import java.nio.file.*; +import java.nio.charset.*; + +import org.dom4j.*; +import org.dom4j.tree.*; +import org.dom4j.io.*; + +public class DOM4JUtils +{ + + public static String childElementContent (Element el, + String elName) + throws GeneralException + { + + return DOM4JUtils.childElementContent (el, + elName, + true, + null); + + } + + public static String childElementContent (Element el, + String elName, + boolean required, + String onNotProvidedNotRequired) + throws GeneralException + { + + Element cel = el.element (elName); + + if (cel == null) + { + + if (required) + { + + DOM4JUtils.raiseException ("Expected: %1$s to have a child element: %2$s that has content.", + el, + elName); + return null; + + } else { + + return onNotProvidedNotRequired; + + } + + } + + String v = cel.getText (); + + if ("".equals (v)) + { + + return onNotProvidedNotRequired; + + } + + return v; + + } + + public static String elementAsString (Element el) + throws GeneralException + { + + try + { + + Document doc = DocumentHelper.createDocument (); + doc.setRootElement (el); + return el.asXML (); + + } catch (Exception e) { + + DOM4JUtils.raiseException ("Unable to get %1$s as string.", + el); + return null; + + } + + } + + public static String attributeValue (Element el, + String attrName) + throws GeneralException + { + + return DOM4JUtils.attributeValue (el, + attrName, + true); + + } + + public static String attributeValue (Element el, + String attrName, + boolean required) + throws GeneralException + { + + String val = el.attributeValue (attrName); + + if ((val == null) + && + (required) + ) + { + + DOM4JUtils.raiseException ("Expected: %1$s to have an attribute called: %2$s", + DOM4JUtils.getPath (el), + attrName); + + } + + return val; + + } + + public static Boolean attributeValueAsBoolean (Element el, + String attrName) + throws GeneralException + { + + return DOM4JUtils.attributeValueAsBoolean (el, + attrName, + true); + + } + + public static Boolean attributeValueAsBoolean (Element el, + String attrName, + boolean required) + throws GeneralException + { + + String val = DOM4JUtils.attributeValue (el, + attrName, + required); + + if (val == null) + { + + return false; + + } + + try + { + + return Boolean.valueOf (val); + + } catch (Exception e) { + + DOM4JUtils.raiseException ("Unable to convert value: %1$s to boolean, attribute: %2$s", + val, + el.attribute (attrName), + e); + return false; + + } + + } + + public static Integer attributeValueAsInt (Element el, + String attrName) + throws GeneralException + { + + return DOM4JUtils.attributeValueAsInt (el, + attrName, + true); + + } + + public static Integer attributeValueAsInt (Element el, + String attrName, + boolean required) + throws GeneralException + { + + String val = DOM4JUtils.attributeValue (el, + attrName, + required); + + if (val == null) + { + + return 0; + + } + + try + { + + return Integer.valueOf (val); + + } catch (Exception e) { + + DOM4JUtils.raiseException ("Unable to convert value: %1$s to integer, attribute: %2$s", + val, + el.attribute (attrName), + e); + return 0; + + } + + } + + public static Float attributeValueAsFloat (Element el, + String attrName) + throws GeneralException + { + + return DOM4JUtils.attributeValueAsFloat (el, + attrName, + true); + + } + + public static Float attributeValueAsFloat (Element el, + String attrName, + boolean required) + throws GeneralException + { + + String val = DOM4JUtils.attributeValue (el, + attrName, + required); + + if (val == null) + { + + return 0f; + + } + + try + { + + return Float.valueOf (val); + + } catch (Exception e) { + + DOM4JUtils.raiseException ("Unable to convert value: %1$s to float, attribute: %2$s", + val, + el.attribute (attrName), + e); + return 0f; + + } + + } + + public static Element stringAsElement (String v) + throws GeneralException + { + + try + { + + Document doc = DocumentHelper.parseText (v); + return doc.getRootElement (); + + } catch (Exception e) { + + throw new GeneralException ("Unable to convert text to an element: " + v, + e); + + } + + } + + public static String getElementPath (Element el, + StringBuilder buf) + { + + String b = '/' + el.getQualifiedName (); + + // Now just check to see if element is part of group at this level. + // Get the parent. + Element parent = el.getParent (); + + if (parent != null) + { + + for (Element cel : parent.elements (el.getName ())) + { + + int i = 1; + + if (cel == el) + { + + // They are the same, add a [X] to the buffer. + b += '['; + + if (cel.attribute ("id") != null) + { + + b += cel.attributeValue ("id"); + + } else { + + b += i + ""; + + } + + b += ']'; + + } + + i++; + + } + + buf.insert (0, + b); + + return DOM4JUtils.getElementPath (parent, + buf); + + } + + buf.insert (0, + b); + + return buf.toString (); + + } + + public static String getPath (Element el) + { + + return DOM4JUtils.getElementPath (el); + + } + + public static String getElementPath (Element el) + { + + return DOM4JUtils.getElementPath (el, + new StringBuilder ()); + + } + + public static String getPath (Attribute attr) + { + + String path = DOM4JUtils.getElementPath (attr.getParent (), + new StringBuilder ()); + return path + "/@" + attr.getQualifiedName (); + + } + + public static Element fileAsElement (Path p) + throws GeneralException + { + + return DOM4JUtils.fileAsElement (p.toFile ()); + + } + + public static Element fileAsElement (File f) + throws GeneralException + { + + try + { + + String s = new String (Files.readAllBytes (f.toPath ()), + StandardCharsets.UTF_8); + + Document doc = DocumentHelper.parseText (s); + + return doc.getRootElement (); + + } catch (Exception e) { + + throw new GeneralException ("Unable to convert file: " + f + " to xml", + e); + + } + + } + + public static void raiseException (String message, + Object... args) + throws GeneralException + { + + Object[] vals = new Object[args.length]; + + for (int i = 0; i < vals.length; i++) + { + + Object o = args[i]; + + if (o instanceof Attribute) + { + + vals[i] = DOM4JUtils.getPath ((Attribute) o); + continue; + + } + + if (o instanceof Element) + { + + vals[i] = DOM4JUtils.getPath ((Element) o); + continue; + + } + + vals[i] = o; + + } + + throw new GeneralException (String.format (message, + vals)); + + } + + public static void writeToFile (Element el, + Path path, + boolean overwrite) + throws GeneralException + { + + try + { + + try (BufferedWriter bw = new BufferedWriter (new OutputStreamWriter (new FileOutputStream (path.toFile (), !overwrite), StandardCharsets.UTF_8))) + { + + XMLWriter xmlw = new XMLWriter (bw); + xmlw.write (el); + bw.flush (); + bw.close (); + + } + + } catch (Exception e) { + + throw new GeneralException ("Unable to write element to path: " + path, + e); + + } + + } + +} diff --git a/src/com/quollwriter/DefaultIconProvider.java b/src/main/java/com/quollwriter/DefaultIconProvider.java similarity index 100% rename from src/com/quollwriter/DefaultIconProvider.java rename to src/main/java/com/quollwriter/DefaultIconProvider.java diff --git a/src/main/java/com/quollwriter/DictionaryProvider.java b/src/main/java/com/quollwriter/DictionaryProvider.java new file mode 100644 index 00000000..edd3430f --- /dev/null +++ b/src/main/java/com/quollwriter/DictionaryProvider.java @@ -0,0 +1,836 @@ +package com.quollwriter; + +import java.io.*; +import java.net.*; +import java.util.*; +import java.nio.file.*; + +import javafx.scene.control.*; +import javafx.scene.text.*; +import javafx.scene.layout.*; + +import com.quollwriter.*; +import com.quollwriter.uistrings.UILanguageStrings; +import com.quollwriter.ui.fx.components.*; +import com.quollwriter.ui.fx.viewers.*; +import com.quollwriter.ui.fx.*; +import com.quollwriter.text.*; +import com.quollwriter.ui.events.DictionaryChangedEvent; +import com.quollwriter.ui.events.DictionaryChangedListener; +import com.quollwriter.uistrings.UILanguageStringsManager; + +import com.softcorporation.suggester.util.Constants; +import com.softcorporation.suggester.util.SpellCheckConfiguration; +import com.softcorporation.suggester.Suggestion; +import com.softcorporation.suggester.dictionary.BasicDictionary; +import com.softcorporation.suggester.BasicSuggester; + +import static com.quollwriter.uistrings.UILanguageStringsManager.getUILanguageStringProperty; +import static com.quollwriter.LanguageStrings.*; + +public class DictionaryProvider +{ + + private List listeners = new ArrayList (); + private QWSpellDictionaryHashMap projDict = null; + private SpellChecker checker = null; + private com.swabunga.spell.event.SpellChecker projectSpellChecker = null; + + // TODO Use a path. + private static File userDictFile = null; + private static QWSpellDictionaryHashMap userDict = null; + private static com.swabunga.spell.event.SpellChecker userSpellChecker = null; + private String language = null; + + public DictionaryProvider (String lang, + List projWords) + throws Exception + { + + this.language = lang; + + Path dictFile = DictionaryProvider.getDictionaryFilePath (lang); + + if (Files.notExists (dictFile)) + { + + throw new GeneralException ("Unable to find dictionary file: " + + dictFile); + + } + + BasicDictionary dict = new BasicDictionary ("file://" + dictFile.toFile ().getPath ()); + + SpellCheckConfiguration config = new SpellCheckConfiguration ("/com/softcorporation/suggester/spellCheck.config"); + + final BasicSuggester suggester = new BasicSuggester (config); + suggester.attach (dict); + + final DictionaryProvider _this = this; + + this.checker = new SpellChecker () + { + + public synchronized boolean isCorrect (Word word) + { + + if (word.isPunctuation ()) + { + + return true; + + } + + String w = word.getText (); + + // See if the word is a number. + try + { + + Double.parseDouble (w); + + return true; + + } catch (Exception e) { + + // Not a number. + + } + + if (this.isIgnored (word)) + { + + return true; + + } + + try + { + + if (_this.projectSpellChecker.isCorrect (w)) + { + + return true; + + } + + if (DictionaryProvider.userSpellChecker.isCorrect (w)) + { + + return true; + + } + + if (suggester.hasExactWord (w)) + { + + return true; + + } + + int result = suggester.hasWord (w); + if (result == Constants.RESULT_ID_MATCH || + result == Constants.RESULT_ID_MATCH_EXACT) + { + return true; + } + + }catch (Exception e) { + + Environment.logError ("Unable to check word: " + + word, + e); + + } + + return false; + + } + + public synchronized boolean isIgnored (Word word) + { + + return false; + + } + + public synchronized List getSuggestions (Word word) + { + + List ret = new ArrayList (); + + if (word == null) + { + + return null; + + } + + if (this.isCorrect (word)) + { + + return null; + + } + + String wt = word.getText (); + + List suggestions = null; + + List jsuggestions = _this.projectSpellChecker.getSuggestions (wt, + 1); + + if (jsuggestions != null) + { + + for (int i = 0; i < jsuggestions.size (); i++) + { + + ret.add (((com.swabunga.spell.engine.Word) jsuggestions.get (i)).getWord ()); + + } + + } + + jsuggestions = DictionaryProvider.userSpellChecker.getSuggestions (wt, + 1); + + if (jsuggestions != null) + { + + for (int i = 0; i < jsuggestions.size (); i++) + { + + ret.add (((com.swabunga.spell.engine.Word) jsuggestions.get (i)).getWord ()); + + } + + } + + try + { + + suggestions = suggester.getSuggestions (wt, 20); + + } catch (Exception e) { + + e.printStackTrace (); + + } + + if (suggestions != null) + { + + for (int i = 0; i < suggestions.size (); i++) + { + + Suggestion s = (Suggestion) suggestions.get (i); + + ret.add (s.word); + + } + + } + + if (Character.isUpperCase (wt.charAt (0))) + { + + for (int i = 0; i < ret.size (); i++) + { + + String w = ret.get (i); + + ret.set (i, + Character.toUpperCase (w.charAt (0)) + w.substring (1)); + + } + + } + + return ret; + + } + + }; + + this.projectSpellChecker = new com.swabunga.spell.event.SpellChecker (); + + if (projWords != null) + { + + StringBuilder b = new StringBuilder (); + + for (String i : projWords) + { + + b.append (i); + b.append ('\n'); + + } + + this.projDict = new QWSpellDictionaryHashMap (new StringReader (b.toString ())); + + this.projectSpellChecker.addDictionary (this.projDict); + + //this.dicts.add (this.projDict); + + } + + if (DictionaryProvider.userDict == null) + { + + Path userDictFile = DictionaryProvider.getUserDictionaryFilePath (); + + if (Files.notExists (userDictFile)) + { + + Files.createFile (userDictFile); + + } + + DictionaryProvider.userDict = new QWSpellDictionaryHashMap (userDictFile.toFile ()); + + DictionaryProvider.userDictFile = userDictFile.toFile (); + + DictionaryProvider.userSpellChecker = new com.swabunga.spell.event.SpellChecker (); + + DictionaryProvider.userSpellChecker.setUserDictionary (DictionaryProvider.userDict); + + } + + } + + public String getLanguage () + { + + return this.language; + + } + + public static boolean isLanguageInstalled (String lang) + { + + Path f = DictionaryProvider.getDictionaryFilePath (lang); + + if ((f != null) + && + (Files.exists (f)) + ) + { + + return true; + + } + + return false; + + } + + /** + * Checks to see if the directory is an indexed dictionary directory which means: + * - It contains a db directory + * - It contains a words directory + * - It contains a contents file + * + * @param dir The directory to check. + * @return If the checks pass. + */ + private boolean isIndexedDictionaryDirectory (File dir) + { + + if (!dir.exists ()) + { + + return false; + + } + + File dbDir = new File (dir, "db"); + + if ((!dbDir.exists ()) + || + (dbDir.isFile ()) + ) + { + + return false; + + } + + File wordsDir = new File (dir, "words"); + + if ((!wordsDir.exists ()) + || + (wordsDir.isFile ()) + ) + { + + return false; + + } + + return true; + + } + + public void addDictionaryChangedListener (DictionaryChangedListener l) + { + + if (this.listeners.contains (l)) + { + + return; + + } + + this.listeners.add (l); + + } + + public void removeDictionaryChangedListener (DictionaryChangedListener l) + { + + this.listeners.remove (l); + + } + + protected void fireDictionaryEvent (DictionaryChangedEvent ev) + { + + for (int i = 0; i < this.listeners.size (); i++) + { + + DictionaryChangedListener dcl = (DictionaryChangedListener) this.listeners.get (i); + + dcl.dictionaryChanged (ev); + + } + + } + + public SpellChecker getSpellChecker () + { + + return this.checker; + + } + + public static void addUserWord (String word) + { + + if (!DictionaryProvider.userDict.isCorrect (word)) + { + + DictionaryProvider.userDict.addWord (word); +/* + this.fireDictionaryEvent (new DictionaryChangedEvent (this, + DictionaryChangedEvent.WORD_ADDED, + word)); +*/ + } + + } + + public static void removeUserWord (String word) + { + + if (DictionaryProvider.userDict != null) + { + + DictionaryProvider.userDict.removeWord (word); + + try + { + + DictionaryProvider.userDict.saveDictionaryToFile (DictionaryProvider.userDictFile); + + } catch (Exception e) + { + + Environment.logError ("Unable to save user dictionary file", + e); + + } + + /* + this.fireDictionaryEvent (new DictionaryChangedEvent (this, + DictionaryChangedEvent.WORD_REMOVED, + word)); +*/ + } + + } + + public void removeWord (String word, + String type) + { + + if (type.equals ("project")) + { + + if (this.projDict != null) + { + + this.projDict.removeWord (word); + + this.fireDictionaryEvent (new DictionaryChangedEvent (this, + DictionaryChangedEvent.WORD_REMOVED, + word)); + + } + + } + + if (type.equals ("user")) + { + + if (DictionaryProvider.userDict != null) + { + + DictionaryProvider.userDict.removeWord (word); + + try + { + + DictionaryProvider.userDict.saveDictionaryToFile (DictionaryProvider.userDictFile); + + } catch (Exception e) + { + + Environment.logError ("Unable to save user dictionary file", + e); + + } + + this.fireDictionaryEvent (new DictionaryChangedEvent (this, + DictionaryChangedEvent.WORD_REMOVED, + word)); + + } + + } + + } + + public void addWord (String word, + String type) + { + + if (type.equals ("project")) + { + + if (this.projDict == null) + { + + try + { + + this.projDict = new QWSpellDictionaryHashMap (new StringReader ("")); + + } catch (Exception e) + { + + Environment.logError ("Unable to create project dictionary for word: " + + word, + e); + + return; + + } + + } + + this.projDict.addWord (word); + + this.fireDictionaryEvent (new DictionaryChangedEvent (this, + DictionaryChangedEvent.WORD_ADDED, + word)); + + } + + if (type.equals ("user")) + { + + if (!DictionaryProvider.userDict.isCorrect (word)) + { + + DictionaryProvider.userDict.addWord (word); + + this.fireDictionaryEvent (new DictionaryChangedEvent (this, + DictionaryChangedEvent.WORD_ADDED, + word)); + + } + + } + + } + + public static void downloadDictionaryFiles (String lang, + final AbstractViewer parent, + final Runnable onComplete) + { + + if (UILanguageStrings.isEnglish (lang)) + { + + lang = com.quollwriter.Constants.ENGLISH; + + } + + final String langOrig = lang; + final String language = lang; + + String fileLang = lang; + + // Legacy, if the user doesn't have the language file but DOES have a thesaurus then just + // download the English-dictionary-only.zip. + if ((UILanguageStrings.isEnglish (lang)) + && + (Files.notExists (DictionaryProvider.getDictionaryFilePath (lang))) + && + (DictionaryProvider.hasSynonymsDirectory (lang)) + ) + { + + fileLang = "English-dictionary-only"; + + } + + URL url = null; + + try + { + + url = new URL (Environment.getQuollWriterWebsite () + "/" + Utils.replaceString (UserProperties.get (com.quollwriter.Constants.QUOLL_WRITER_LANGUAGE_FILES_URL_PROPERTY_NAME), + "[[LANG]]", + Utils.replaceString (fileLang, + " ", + "%20"))); + + } catch (Exception e) { + + Environment.logError ("Unable to download language files, cant create url", + e); + + ComponentUtils.showErrorMessage (parent, + getUILanguageStringProperty (dictionary,download,actionerror)); + //"Unable to download language files"); + + return; + + } + + Environment.logDebugMessage ("Downloading language file(s) from: " + url + ", for language: " + lang); + + File _file = null; + + // Create a temp file for it. + try + { + + _file = File.createTempFile ("quollwriter-language-" + fileLang, + null); + + } catch (Exception e) { + + Environment.logError ("Unable to download language files, cant create temp file", + e); + + ComponentUtils.showErrorMessage (parent, + getUILanguageStringProperty (dictionary,download,actionerror)); + //"Unable to download language files"); + + return; + + } + + _file.deleteOnExit (); + + final File file = _file; + + VBox b = new VBox (); + + Text text = new Text (); + text.textProperty ().bind (getUILanguageStringProperty (Arrays.asList (dictionary,download,notification), + language)); + + final ProgressBar prog = new ProgressBar (); + + b.getChildren ().addAll (text, prog); + + final Notification n = parent.addNotification (b, + StyleClassNames.DOWNLOAD, + -1, + null); + + final UrlDownloader downloader = new UrlDownloader (url, + file, + new DownloadListener () + { + + @Override + public void onStop () + { + + } + + @Override + public void handleError (Exception e) + { + + UIUtils.runLater (() -> + { + + n.removeNotification (); + + Environment.logError ("Unable to download language files", + e); + + ComponentUtils.showErrorMessage (parent, + getUILanguageStringProperty (dictionary,download,actionerror)); + //"A problem has occurred while downloading the language files for " + langOrig + ".

    Please contact Quoll Writer support for assistance."); + + }); + + } + + @Override + public void progress (final int downloaded, + final int total) + { + + UIUtils.runLater (() -> + { + + double val = (double) downloaded / (double) total; + + prog.setProgress (val); + + }); + + } + + @Override + public void finished (int total) + { + + UIUtils.runLater (() -> + { + + prog.setProgress (-1); + + }); + + new Thread (() -> + { + + // Now extract the file into the relevant directory. + try + { + + Utils.extractZipFile (file, + Environment.getUserQuollWriterDirPath ().toFile ()); + + } catch (Exception e) { + + Environment.logError ("Unable to extract language zip file: " + + file + + " to: " + + Environment.getUserQuollWriterDirPath (), + e); + + ComponentUtils.showErrorMessage (parent, + getUILanguageStringProperty (dictionary,download,actionerror)); + + return; + + } finally { + + file.delete (); + + } + + if (onComplete != null) + { + + UIUtils.runLater (() -> + { + + prog.setProgress (-1); + + onComplete.run (); + + }); + + } + + UIUtils.runLater (() -> n.removeNotification ()); + + }).start (); + + } + + }); + + downloader.start (); + +// TODO Add a listener to the notification for removal. +/* + n.addCancelListener (new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + downloader.stop (); + + file.delete (); + + } + + }); +*/ + } + + /** + * Gets the path for the dictionaires. + */ + public static Path getDictionariesDirPath () + { + + return Environment.getUserPath (com.quollwriter.Constants.DICTIONARIES_DIR); + + } + + /** + * Gets the user dictionary. + */ + public static Path getUserDictionaryFilePath () + { + + return Environment.getUserPath (com.quollwriter.Constants.USER_DICTIONARY_FILE_NAME); + + } + + /** + * Gets the path for a specific dictionary. + */ + public static Path getDictionaryFilePath (String lang) + { + + return DictionaryProvider.getDictionariesDirPath ().resolve (lang + ".zip"); + + } + + public static boolean hasSynonymsDirectory (String lang) + { + + Path f = Environment.getUserPath (com.quollwriter.Constants.THESAURUS_DIR).resolve (lang); + + return Files.exists (f) && Files.isDirectory (f); + + } + +} diff --git a/src/com/quollwriter/DictionaryProvider2.java b/src/main/java/com/quollwriter/DictionaryProvider2.java similarity index 94% rename from src/com/quollwriter/DictionaryProvider2.java rename to src/main/java/com/quollwriter/DictionaryProvider2.java index 959c3d68..2f13c6ea 100644 --- a/src/com/quollwriter/DictionaryProvider2.java +++ b/src/main/java/com/quollwriter/DictionaryProvider2.java @@ -6,7 +6,7 @@ import com.quollwriter.ui.events.*; -import com.quollwriter.ui.components.*; +import com.quollwriter.ui.fx.*; import com.quollwriter.text.*; import com.softcorporation.suggester.util.Constants; diff --git a/src/com/quollwriter/DownloadListener.java b/src/main/java/com/quollwriter/DownloadListener.java similarity index 86% rename from src/com/quollwriter/DownloadListener.java rename to src/main/java/com/quollwriter/DownloadListener.java index 37435b54..69297f8c 100644 --- a/src/com/quollwriter/DownloadListener.java +++ b/src/main/java/com/quollwriter/DownloadListener.java @@ -2,12 +2,14 @@ public interface DownloadListener { - + public void progress (int downloaded, int total); - + public void finished (int total); - + public void handleError (Exception e); - -} \ No newline at end of file + + public void onStop (); + +} diff --git a/src/main/java/com/quollwriter/Environment.java b/src/main/java/com/quollwriter/Environment.java new file mode 100644 index 00000000..6d2f19ba --- /dev/null +++ b/src/main/java/com/quollwriter/Environment.java @@ -0,0 +1,6582 @@ +package com.quollwriter; + +import java.nio.channels.*; + +import java.io.*; +import javax.imageio.*; +import java.net.*; + +import java.time.*; +import java.time.format.*; +import java.time.temporal.*; +import java.text.*; +import java.util.*; +import java.util.function.*; +import java.nio.file.*; +import java.nio.file.attribute.*; +import java.nio.charset.*; +import java.util.stream.*; +import java.util.concurrent.*; +import java.util.logging.*; +import java.security.*; + +import javafx.beans.value.*; +import javafx.collections.*; +import javafx.scene.text.*; +import javafx.beans.property.*; +import javafx.scene.media.*; +import javafx.application.*; +import javafx.scene.image.*; +import javafx.scene.input.*; +import javafx.event.*; + +import org.dom4j.*; +import org.dom4j.tree.*; + +import com.quollwriter.achievements.*; +import com.quollwriter.achievements.rules.*; +import com.quollwriter.db.*; +import com.quollwriter.data.*; +import com.quollwriter.data.comparators.*; +import com.quollwriter.synonyms.*; +import com.quollwriter.editors.*; +import com.quollwriter.uistrings.*; +import com.quollwriter.text.rules.*; +import com.quollwriter.importer.*; +import com.quollwriter.ui.fx.*; +import com.quollwriter.ui.fx.viewers.*; +import com.quollwriter.ui.fx.components.*; +import com.quollwriter.events.ProjectInfoChangedEvent; +import com.quollwriter.ui.fx.swing.QTextEditor; +import com.quollwriter.editors.ui.*; + +import static com.quollwriter.LanguageStrings.*; +import static com.quollwriter.uistrings.UILanguageStringsManager.getUILanguageStringProperty; + +public class Environment +{ + + public static PrintStream out = null; +/* + private static Logger generalLog = null; + private static Logger errorLog = null; + private static Logger sqlLog = null; +*/ + + private static boolean closeDownAllowed = true; + + private static Logger sqlLog = null; + private static Logger logger = null; + private static Version appVersion = null; + //private static String appVersion = null; + //private static boolean betaVersion = false; + private static int schemaVersion = 0; + private static int projectInfoSchemaVersion = 0; + + private static SimpleDateFormat dateFormatter = null; + private static SimpleDateFormat timeFormatter = null; + + private static BooleanProperty debugModeProp = new SimpleBooleanProperty (); + private static boolean doneVersionCheck = false; + public static boolean isWindows = false; + public static boolean isMac = false; + public static boolean isLinux = false; + private static boolean isFirstUse = false; + + private static long userStyleSheetLastModified = 0; + private static ScheduledFuture userStyleSheetModifiedChecker = null; + + private static DecimalFormat numFormat = new DecimalFormat ("###,###"); + private static DecimalFormat floatNumFormat = new DecimalFormat ("###,###.#"); + + private static FileLock lock = null; + private static ScheduledThreadPoolExecutor generalTimer = null; + + private static AllProjectsViewer allProjectsViewer = null; + private static CSSViewer cssViewer = null; + + private static ObservableMap openProjects = null; + private static ObservableSet allProjects = null; + private static ObservableSet openViewers = null; + + private static Set windowIcons = null; + + private static DoubleProperty startupProgressProp = null; + private static BooleanProperty startupCompleteProp = null; + + private static BooleanProperty nightModeProp = null; + + public static Map defaultObjectProperties = new HashMap<> (); + + private static ProjectInfoObjectManager projectInfoManager = null; + + private static UserSession userSession = null; + + private static TargetsData targets = null; + + // TODO Needs it's own manager. + private static ObservableSet tags = null; + + private static AchievementsManager achievementsManager = null; + + private static ObservableSet userConfigObjTypes = null; + private static Map objectTypeNamesSingular = new HashMap<> (); + private static Map objectTypeNamesPlural = new HashMap<> (); + + private static Map userPropertyHandlers = new HashMap<> (); + private static ProjectTextProperties projectTextProps = null; + private static FullScreenTextProperties fullScreenTextProps = null; + private static DoubleProperty objectTypeNameChangedProp = null; + + // TODO Probably not needed, bind to the property. private static List startupProgressListeners = new ArrayList<> (); + + private static Map synonymProviders = new WeakHashMap<> (); + + private static Map userProjectEventListeners = null; + + private static Path userQuollWriterDirPath = null; + + // Just used in the maps above as a placeholder for the listeners. + private static final Object listenerFillObj = new Object (); + + private static int startupProgress = 0; + + private static ObservableSet styleSheets = FXCollections.observableSet (new LinkedHashSet<> ()); + + private static HostServices hostServices = null; + + private static List doOnShutdown = new ArrayList<> (); + + private static ScheduledFuture autoNightModeSchedule = null; + + static + { + + // We use a synchronized weak hash map here so that we don't have to worry about all the + // references since they will be transient compared to the potential length of the service + // running. + + // Where possible listeners should de-register as normal but this just ensure that objects + // that don't have a controlled pre-defined lifecycle (as opposed say to AbstractSideBar) + // won't leak. + Environment.userProjectEventListeners = Collections.synchronizedMap (new WeakHashMap ()); + + try + { + + // Put a wrapper around System.out to ensure that non ascii characters show up correctly when debugging. + Environment.out = new java.io.PrintStream (System.out, true, "utf-8"); + + } catch (Exception e) { + + Environment.out = System.out; + + } + + } + + public class XMLConstants + { + + public static final String projects = "projects"; + public static final String type = "type"; + public static final String name = "name"; + public static final String object = "object"; + public static final String singular = "singular"; + public static final String plural = "plural"; + public static final String file = "file"; + public static final String files = "files"; + public static final String stats = "stats"; + public static final String stat = "stat"; + public static final String id = "id"; + + } + + public static void init (DoubleProperty startupProgressProp, + Runnable onInitComplete) + throws Exception + { + + //SvgImageLoaderFactory.install (new PrimitiveDimensionProvider()); + + Environment.startupProgressProp = startupProgressProp; + Environment.startupCompleteProp = new SimpleBooleanProperty (false); + + Environment.startupCompleteProp.addListener ((pr, oldv, newv) -> + { + + // Do nothing, here to force updates. + + }); + + Environment.openProjects = FXCollections.observableMap (new HashMap<> ()); + + Environment.openViewers = FXCollections.observableSet (new HashSet<> ()); + + Environment.allProjects = FXCollections.observableSet (new HashSet<> ()); + + Environment.userConfigObjTypes = FXCollections.observableSet (new HashSet<> ()); + + Environment.allProjects.addListener ((SetChangeListener) ch -> + { + + if (ch.wasRemoved ()) + { + + ch.getElementRemoved ().dispose (); + + } + + }); + + Environment.objectTypeNameChangedProp = new SimpleDoubleProperty (0); + Environment.objectTypeNameChangedProp.addListener ((pr, oldv, newv) -> + { + + // Do nothing, here to force updates. + + }); + + + Thread.setDefaultUncaughtExceptionHandler (new Thread.UncaughtExceptionHandler () + { + + @Override + public void uncaughtException (Thread t, + Throwable e) + { + + Environment.printStackTrace (e); + Environment.logError ("Unexcepted error from thread: " + t.getId () + "\nStack Trace: \n" + Utils.getStackTrace (e)); + + } + + }); + + // Start the timer, it is done here so that any other code that needs it can start running things + // straightaway. + Environment.generalTimer = new ScheduledThreadPoolExecutor (5, + new ThreadFactory () + { + + @Override + public Thread newThread (Runnable r) + { + + Thread t = new Thread (r); + + t.setDaemon (true); + t.setPriority (Thread.MIN_PRIORITY); + t.setName ("Environment-general-" + t.getId ()); + + return t; + + } + + }); + + // Setup the user QW dir. + Environment.userQuollWriterDirPath = Paths.get (System.getProperty ("user.home"), Constants.QUOLL_WRITER_DIR_NAME); + + Files.createDirectories (Environment.userQuollWriterDirPath); + + InputStream configFile = Environment.class.getResourceAsStream (Constants.LOGGING_CONFIG_FILE_NAME); + LogManager.getLogManager ().readConfiguration (configFile); + + Environment.logger = Logger.getLogger ("logger"); +/* + File f = Environment.getErrorLogFile (); + + f.delete (); + + Environment.errorLog = Logger.getLogger ("error"); + + Environment.errorLog.addHandler (errorHandler); + + Environment.errorLog = new Logger (); + Environment.errorLog.initLogFile (f); + + f = Environment.getGeneralLogFile (); + + f.delete (); + + Environment.generalLog = new Logger (); + Environment.generalLog.initLogFile (f); + + f = Environment.getSQLLogFile (); + + f.delete (); +*/ + Environment.sqlLog = Logger.getLogger ("sql-logger"); +/* + Environment.sqlLog = new Logger (); + Environment.sqlLog.initLogFile (f); +*/ + Environment.incrStartupProgress (); + + Environment.isWindows = System.getProperty ("os.name").startsWith ("Windows"); + + Environment.isMac = System.getProperty ("os.name").startsWith ("Mac"); + + Environment.isLinux = System.getProperty ("os.name").startsWith ("Linux"); + + System.setProperty ("prism.lcdtext", "false"); + //System.setProperty("prism.lcdtext", "true"); + //System.setProperty("prism.text", "t2k"); + // TODO Handle night mode. + Environment.nightModeProp = new SimpleBooleanProperty (false); + + // Setup our stream handler for the objectref protocol. + URL.setURLStreamHandlerFactory (new ObjectRefURLStreamHandlerFactory ()); + + Environment.dateFormatter = new SimpleDateFormat ("d MMM yyyy"); + Environment.timeFormatter = new SimpleDateFormat ("HH:mm"); + + Environment.appVersion = new Version (Utils.getResourceFileAsString (Constants.VERSION_FILE).trim ()); + + try + { + + Environment.schemaVersion = Integer.parseInt (Utils.getResourceFileAsString (Constants.SCHEMA_VERSION_FILE).trim ()); + + } catch (Exception e) + { + + // Ignore. + + } + + try + { + + Environment.projectInfoSchemaVersion = Integer.parseInt (Utils.getResourceFileAsString (Constants.PROJECT_INFO_SCHEMA_VERSION_FILE).trim ()); + + } catch (Exception e) + { + + // Ignore. + + } + + com.gentlyweb.properties.Properties sysProps = new com.gentlyweb.properties.Properties (Utils.getResourceStream (Constants.DEFAULT_PROPERTIES_FILE), + null); + sysProps.setId ("system"); + + // Temporarily set the user properties to the system properties. + UserProperties.init (sysProps); + + UILanguageStringsManager.init (); + + URL u = UserProperties.getDefaultStyleSheetURL (); + + Environment.styleSheets.add (u); + + Environment.incrStartupProgress (); + + // Try and get a lock on the file. + // Change to Path? + + Path l = Environment.getUserPath ("___quollwriter_lock.lock"); + + // Try and gain a lock. + FileLock lock = FileChannel.open (l, + StandardOpenOption.CREATE, + StandardOpenOption.READ, + StandardOpenOption.WRITE).tryLock (); + + if (lock == null) + { + + throw new OverlappingFileLockException (); + + } + + Environment.lock = lock; + + l.toFile ().deleteOnExit (); + + com.gentlyweb.properties.Properties userProps = sysProps; + + Environment.incrStartupProgress (); + + // See if this is first use. + Environment.isFirstUse = (Environment.getProjectInfoSchemaVersion () == 0); + + // Get the username and password. + String username = UserProperties.get (Constants.DB_USERNAME_PROPERTY_NAME); + String password = UserProperties.get (Constants.DB_PASSWORD_PROPERTY_NAME); + + Environment.projectInfoManager = new ProjectInfoObjectManager (); + + // TODO Change to use path. + Environment.projectInfoManager.init (Environment.getProjectInfoDBPath ().toFile (), + username, + password, + null, + Environment.getProjectInfoSchemaVersion ()); + + try + { + + userProps = Environment.projectInfoManager.getUserProperties (); + + } catch (Exception e) { + + Environment.logError ("Unable to load user properties", + e); + + } + + if (userProps == null) + { + + // Check for legacy properties.xml. Pre v2.5. + Path pf = UserProperties.getUserPropertiesPath (); + + if (Files.exists (pf)) + { + + try + { + + userProps = new com.gentlyweb.properties.Properties (pf.toFile (), + Constants.GZIP_EXTENSION); + + } catch (Exception e) + { + + Environment.logError ("Unable to load user properties from file: " + + pf, + e); + + } + + Files.delete (pf); + + } + + } + + if (userProps == null) + { + + userProps = new com.gentlyweb.properties.Properties (); + + } + + if (userProps != sysProps) + { + + userProps.setId ("user"); + + userProps.setParentProperties (sysProps); + + } + + if (userProps == null) + { + + // If this is legacy and we can't load the properties file (is corrupted) then + // use the system properties as the properties. + userProps = sysProps; + + } + + Environment.incrStartupProgress (); + + +/* + TODO Get rid of default project properties. + // Get the system default project properties. + com.gentlyweb.properties.Properties sysDefProjProps = new com.gentlyweb.properties.Properties (Utils.getResourceStream (Constants.DEFAULT_PROJECT_PROPERTIES_FILE), + UserProperties.getProperties ()); + + Path defUserPropsFile = UserProperties.getUserDefaultProjectPropertiesPath (); +System.out.println ("FILEPROPS: " + defUserPropsFile); + if (Files.exists (defUserPropsFile)) + { + + com.gentlyweb.properties.Properties userDefProjProps = new com.gentlyweb.properties.Properties (defUserPropsFile.toFile (), + Constants.GZIP_EXTENSION); + + userDefProjProps.setParentProperties (sysDefProjProps); + + sysDefProjProps = userDefProjProps; + + } + + // Load the default project properties. + Environment.defaultObjectProperties.put (Project.OBJECT_TYPE, + sysDefProjProps); +*/ + // The user properties need + UserProperties.init (userProps); + + // Do a save here so that if we are loading for the first time they will be saved. + try + { + + Environment.saveUserProperties (); + + } catch (Exception e) { + + Environment.logError ("Unable to save user properties", + e); + + } + + String userUILang = UserProperties.get (Constants.USER_UI_LANGUAGE_PROPERTY_NAME); + + if (userUILang != null) + { + + UILanguageStringsManager.setUILanguage (userUILang); + + } else { + + UILanguageStringsManager.setUILanguage (UserProperties.get (Constants.DEFAULT_UI_LANGUAGE_PROPERTY_NAME)); + + } + + try + { + + Environment.loadUserObjectTypeNames (); + + } catch (Exception e) { + + Environment.logError ("Unable to load user object type names.", + e); + + } + + // Add a set of user overrides for the object type names. + UILanguageStringsManager.setUserStringProvider (ids -> + { + + if ((ids != null) + && + (ids.size () == 3) + && + (ids.get (0).equals (LanguageStrings.objectnames)) + ) + { + + String st = ids.get (1); + + StringProperty sp = null; + + if (st.equals (LanguageStrings.singular)) + { + + sp = Environment.objectTypeNamesSingular.get (ids.get (2)); + + } + + if (st.equals (LanguageStrings.plural)) + { + + sp = Environment.objectTypeNamesPlural.get (ids.get (2)); + + } + + if (sp != null) + { + + try + { + + return sp.getValue (); + + } catch (Exception e) { + + Environment.logError ("Unable to get user string for: " + ids, + e); + + } + + } + + } + + return null; + + }); + + // Add a property listener for name changes to user config object types. + /* + TODO + Environment.userConfigurableObjectTypeNameListener = new PropertyChangedListener () + { + + @Override + public void propertyChanged (PropertyChangedEvent ev) + { + + UserConfigurableObjectType type = (UserConfigurableObjectType) ev.getSource (); + + String id = type.getObjectTypeId (); + + Environment.objectTypeNamesSingular.put (id, + type.getObjectTypeName ()); + + Environment.objectTypeNamesPlural.put (id, + type.getObjectTypeNamePlural ()); + + } + + }; +*/ + + // This inits the tags. + Environment.getAllTags (); + + // Init our legacy object types, if needed. + Environment.projectInfoManager.initLegacyObjectTypes (); + + Environment.tags = FXCollections.observableSet (new LinkedHashSet ((List) Environment.projectInfoManager.getObjects (Tag.class, + null, + null, + true))); + + // The user session needs the properties. + Environment.userSession = new UserSession (); + + // Override the debug mode. + /* + if (UserProperties.get (Constants.DEBUG_MODE_PROPERTY_NAME) != null) + { + + Environment.setDebugModeEnabled (UserProperties.getAsBoolean (Constants.DEBUG_MODE_PROPERTY_NAME)); + + } +*/ + + //Environment.setDebugModeEnabled (true); + + // Create the text properties, they are derived from the user properties so need to be done after + // the user props are inited. + Environment.projectTextProps = new ProjectTextProperties (); + + Environment.fullScreenTextProps = new FullScreenTextProperties (); + + Environment.incrStartupProgress (); +/* +TODO + Environment.userPropertyHandlers.put (Constants.NOTE_TYPES_PROPERTY_NAME, + new UserPropertyHandler (Constants.NOTE_TYPES_PROPERTY_NAME, + null, + notetypes,defaulttypes)); + Environment.userPropertyHandlers.put (Constants.PROJECT_STATUSES_PROPERTY_NAME, + new UserPropertyHandler (Constants.PROJECT_STATUSES_PROPERTY_NAME, + null, + allprojects,defaultstatuses)); + Environment.userPropertyHandlers.put (Constants.TAGS_PROPERTY_NAME, + new UserPropertyHandler (Constants.TAGS_PROPERTY_NAME, + null, + // Prevents the compiler whining... + (String[]) null)); +*/ + // Init our properties. + + try + { + + Prompts.init (); + + } catch (Exception e) + { + + Environment.logError ("Unable to init prompts", + e); + + } + + try + { + + RuleFactory.init (); + + } catch (Exception e) + { + + Environment.logError ("Unable to init rule factory", + e); + + } + + try + { + + Environment.achievementsManager = new AchievementsManager (); + + } catch (Exception e) { + + Environment.logError ("Unable to init achievements manager", + e); + + } + + Environment.schedule (() -> + { + + try + { + + Importer.init (); + + } catch (Exception e) { + + Environment.logError ("Unable to init importer", + e); + + } + + }, + 5 * Constants.SEC_IN_MILLIS, + -1); + + // Try and preload the font families. + Environment.schedule (() -> + { + + Font.getFamilies ().stream () + .forEach (n -> + { + + try + { + + Font _f = Font.font (n); + + } catch (Exception e) { + + } + + }); + + }, + 10 * Constants.SEC_IN_MILLIS, + -1); + + Environment.incrStartupProgress (); + + try + { + + // Get the user editor properties. + com.gentlyweb.properties.Properties eprops = new com.gentlyweb.properties.Properties (); + + Path edPropsFile = UserProperties.getUserEditorsPropertiesPath (); + + if (Files.exists (edPropsFile)) + { + + eprops = new com.gentlyweb.properties.Properties (edPropsFile.toFile (), + Constants.GZIP_EXTENSION); + + } + + eprops.setParentProperties (UserProperties.getProperties ()); + + EditorsEnvironment.init (eprops); + + } catch (Exception e) { + + Environment.logError ("Unable to init editors environment", + e); + + } + + // Pre 2.4. + // See if there is a projects.xml file, if so load the db. + try + { + + Environment.initProjectsDBFromProjectsPath (); + + } catch (Exception e) { + + Environment.logError ("Unable to init project info from projects path", + e); + + } + + if (Environment.isFirstUse) + { + + Environment.isFirstUse = (Environment.getAllProjectInfos ().size () == 0); + + } + + Environment.targets = new TargetsData (UserProperties.getProperties ()); + //Environment.setDebugModeEnabled (true); + Environment.startupCompleteProp.addListener ((val, oldv, newv) -> + { + + if (newv) + { + + Environment.userSession.start (new Date ()); + + // See if we should be doing a warmup exercise. + if (UserProperties.getAsBoolean (Constants.DO_WARMUP_ON_STARTUP_PROPERTY_NAME)) + { + + UIUtils.runLater (() -> + { + + AbstractViewer viewer = Environment.getFocusedViewer (); + + if (viewer != null) + { + + viewer.showWarmupPromptSelect (); + + viewer.fireProjectEvent (ProjectEvent.Type.projectobject, + ProjectEvent.Action.warmuponstartup, + Warmup.OBJECT_TYPE); + + } + + }); + + } + + Date d = new Date (System.currentTimeMillis () + (Constants.DAY_IN_MILLIS)); + + d = Utils.zeroTimeFields (d); + + Environment.schedule (() -> + { + + try + { + + Environment.projectInfoManager.addSession (Environment.userSession.createSnapshot ()); + + } catch (Exception e) { + + Environment.logError ("Unable to take session snapshot", + e); + + } + + }, + d.getTime (), + // Run every 24 hours. It will drift over the days but not by much. + Constants.DAY_IN_MILLIS); + + Environment.schedule (() -> + { + + java.util.List prefix = new ArrayList<> (); + prefix.add (LanguageStrings.targets); + prefix.add (LanguageStrings.types); + + Set met = new LinkedHashSet<> (); + int sessWC = 0; + int wc = 0; + + try + { + + if (!Environment.targets.isShowMessageWhenSessionTargetReached ()) + { + + return; + + } + + sessWC = Environment.userSession.getCurrentSessionWordCount (); + + // See if the user session has exceeded the session count. + if ((sessWC >= Environment.targets.getMySessionWriting ()) + && + (Environment.userSession.shouldShowSessionTargetReachedPopup ()) + ) + { + + wc = sessWC; + met.add (getUILanguageStringProperty (Utils.newList (prefix,session))); + //"Session"); + + Environment.userSession.shownSessionTargetReachedPopup (); + + } + + } catch (Exception e) { + + Environment.logError ("Unable show session target reached popup", + e); + + } + + // Check for the daily count. + // Get all sessions for today. + try + { + + int dWC = Environment.getPastSessionsWordCount (0); + + // The order is important here, the userSession check is cheaper + // than the past sessions check since it doesn't require a db lookup. + if ((Environment.userSession.shouldShowDailyTargetReachedPopup ()) + && + (dWC >= Environment.targets.getMyDailyWriting ()) + ) + { + + wc = dWC; + + met.add (getUILanguageStringProperty (Utils.newList (prefix,daily))); + //"Daily"); + + Environment.userSession.shownDailyTargetReachedPopup (); + + } + + } catch (Exception e) { + + Environment.logError ("Unable to get past session word counts", + e); + + } + + // Get all sessions for this week. + try + { + + // We perform the cheap check here since it will prevent the extra work + // with the calendar and db from having to be performed. + if (Environment.userSession.shouldShowWeeklyTargetReachedPopup ()) + { + + GregorianCalendar gc = new GregorianCalendar (); + + int fd = gc.getFirstDayOfWeek (); + + int cd = gc.get (Calendar.DAY_OF_WEEK); + + int diff = cd - fd; + + if (diff < 0) + { + + diff += 7; + + } + + int wWC = Environment.getPastSessionsWordCount (diff); + + if (wWC >= Environment.targets.getMyWeeklyWriting ()) + { + + wc = wWC; + + met.add (getUILanguageStringProperty (Utils.newList (prefix,weekly))); + //"Weekly"); + + Environment.userSession.shownWeeklyTargetReachedPopup (); + + } + + } + + } catch (Exception e) { + + Environment.logError ("Unable to get past session word counts", + e); + + } + + // Get all sessions for this month. + try + { + + // As above, do the cheap check first to prevent the extra work from + // being done. + if (Environment.userSession.shouldShowMonthlyTargetReachedPopup ()) + { + + GregorianCalendar gc = new GregorianCalendar (); + + int fd = gc.getFirstDayOfWeek (); + + int cd = gc.get (Calendar.DAY_OF_MONTH); + + int diff = cd - fd; + + int mWC = Environment.getPastSessionsWordCount (diff); + + if (mWC >= Environment.targets.getMyMonthlyWriting ()) + { + + wc = mWC; + met.add (getUILanguageStringProperty (Utils.newList (prefix,monthly))); + //"Monthly"); + + Environment.userSession.shownMonthlyTargetReachedPopup (); + + } + + } + + } catch (Exception e) { + + Environment.logError ("Unable to get past session word counts", + e); + + } + + try + { + + if (met.size () > 0) + { + + StringBuilder b = new StringBuilder (); + + for (StringProperty m : met) + { + + b.append (String.format ("
  • %s
  • ", + m.getValue ())); + + } + + List repVals = new ArrayList<> (); + repVals.add (Environment.formatNumber (wc)); + repVals.add (b.toString ()); + + AbstractViewer viewer = Environment.getFocusedViewer (); + + UIUtils.runLater (() -> + { + + QuollPopup.messageBuilder () + .withViewer (viewer) + .closeButton () + .styleClassName (StyleClassNames.WORDCOUNT) + .title (LanguageStrings.targets,writingtargetreachedpopup,title) + .message (getUILanguageStringProperty (Arrays.asList(LanguageStrings.targets,writingtargetreachedpopup,text), + //"You have reached the following writing targets by writing %s words.
      %s
    Well done and keep it up!", + repVals.toArray ())) + .build (); + + }); + + } + + } catch (Exception e) { + + Environment.logError ("Unable to show writing targets reached popup", + e); + + } + + }, + 5 * Constants.SEC_IN_MILLIS, + 5 * Constants.SEC_IN_MILLIS); + + } + + }); + + // Register our viewer types, requires the tags property. + AbstractProjectViewer.registerViewerType (Project.NORMAL_PROJECT_TYPE, + ProjectViewer.class); + AbstractProjectViewer.registerViewerType (Project.EDITOR_PROJECT_TYPE, + EditorProjectViewer.class); + AbstractProjectViewer.registerViewerType (Project.WARMUPS_PROJECT_TYPE, + WarmupProjectViewer.class); + + // Get all the projects. + Environment.initProjectInfos (); + + ObjectProperty usProp = UserProperties.userStyleSheetProperty (); + + ChangeListener usPropList = (pr, oldv, newv) -> + { + + if (Environment.userStyleSheetModifiedChecker != null) + { + + Environment.userStyleSheetLastModified = 0; + Environment.userStyleSheetModifiedChecker.cancel (true); + + } + + if (oldv != null) + { + + try + { + + Environment.styleSheets.remove (oldv.toUri ().toURL ()); + + } catch (Exception e) { + + Environment.logError ("Unable to remove old stylesheet path: " + + oldv, + e); + + } + + } + + if ((newv != null) + && + (Files.exists (newv)) + ) + { + + try + { + + + Environment.styleSheets.add (newv.toUri ().toURL ()); + Environment.userStyleSheetLastModified = Files.getLastModifiedTime (newv).toMillis (); + + } catch (Exception e) { + + Environment.logError ("Unable to add new stylesheet path: " + + newv, + e); + + return; + + } + + Environment.userStyleSheetModifiedChecker = Environment.schedule (() -> + { + + long t = 0; + + try + { + + t = Files.getLastModifiedTime (newv).toMillis (); + + } catch (Exception e) { + + // Has the file been removed? + Environment.userStyleSheetModifiedChecker.cancel (true); + return; + + } + + if (t != Environment.userStyleSheetLastModified) + { + + UIUtils.runLater (() -> + { + + try + { + + Environment.styleSheets.remove (newv.toUri ().toURL ()); + Environment.styleSheets.add (newv.toUri ().toURL ()); + + } catch (Exception e) { + + Environment.logError ("Unable to update stylesheet: " + newv, + e); + + } + + }); + + Environment.userStyleSheetLastModified = t; + + } + + }, + 1000, + 1000); + + } + + }; + + usProp.addListener (usPropList); + + // Init... + usPropList.changed (UserProperties.userStyleSheetProperty (), + null, + UserProperties.userStyleSheetProperty ().getValue ()); + + UIUtils.runLater (onInitComplete); + + UserProperties.permanentNightModeEnabledProperty ().addListener ((pr, oldv, newv) -> + { + + Environment.scheduleAutoNightMode (); + + }); + + UserProperties.autoNightModeEnabledProperty ().addListener ((pr, oldv, newv) -> + { + + Environment.scheduleAutoNightMode (); + + }); + + UserProperties.autoNightModeFromProperty ().addListener ((pr, oldv, newv) -> + { + + Environment.scheduleAutoNightMode (); + + }); + + UserProperties.autoNightModeToProperty ().addListener ((pr, oldv, newv) -> + { + + Environment.scheduleAutoNightMode (); + + }); + + Environment.scheduleAutoNightMode (); + + if (UserProperties.permanentNightModeEnabledProperty ().getValue ()) + { + + Environment.setNightModeEnabled (true); + + } + + } + + private static void cancelAutoNightModeSchedule () + { + + if (Environment.autoNightModeSchedule != null) + { + + Environment.autoNightModeSchedule.cancel (true); + + } + + } + + private static void scheduleAutoNightMode () + { + + Environment.cancelAutoNightModeSchedule (); + + if (!(UserProperties.autoNightModeEnabledProperty ().getValue ()) + || + (UserProperties.getAsBoolean (Constants.NIGHT_MODE_ENABLE_PERMENANTLY_PROPERTY_NAME)) + ) + { + + return; + + } + + LocalTime now = LocalTime.now (); + + LocalTime f = UserProperties.getAutoNightModeFromTime (); + + if (f == null) + { + + return; + + } + + LocalTime t = UserProperties.getAutoNightModeToTime (); + + if (t == null) + { + + return; + + } + + UIUtils.runLater (() -> + { + + Environment.nightModeProp.setValue (Utils.isNowBetween (f, t)); + + }); + + // We schedule this a second later to ensure we don't go into a loop + // because the diff will be zero millis. + Environment.schedule (() -> + { + + Environment.autoNightModeSchedule = Environment.schedule (() -> + { + + Environment.scheduleAutoNightMode (); + + }, + Math.abs (Utils.getMillisFromNowToNearestNextTime (f, t)), + -1); + + }, + 1 * Constants.SEC_IN_MILLIS, + -1); + + } + + public static void setHostServices (HostServices h) + { + + Environment.hostServices = h; + + } + + public static void openURL (URL u) + { + + try + { + + Environment.hostServices.showDocument (u.toExternalForm ()); + + } catch (Exception e) { + + Environment.logError ("Unable to open url: " + u, + e); + + } + + } + + public static ObservableSet getStyleSheets () + { + + return Environment.styleSheets; + + } + + public static BooleanProperty nightModeProperty () + { + + return Environment.nightModeProp; + + } + + public static void setNightModeEnabled (boolean v) + { + + Environment.nightModeProp.set (v); + + } + + public static boolean isNightModeEnabled () + { + + return Environment.nightModeProp.get (); + + } + + public static void printStackTrace () + { + + new Exception ().printStackTrace (Environment.out); + + } + + public static void printStackTrace (Throwable e) + { + + e.printStackTrace (Environment.out); + + } + + private static void initProjectInfos () + throws Exception + { + + Set all = new LinkedHashSet (Environment.projectInfoManager.getObjects (ProjectInfo.class, + null, + null, + true)); + + all.stream () + .forEach (pi -> + { + + pi.addNonWeakPropertyChangedListener (ev -> + { + + try + { + + Environment.updateProjectInfo (pi); + + } catch (Exception e) { + + Environment.logError ("Unable to update status for project: " + + pi, + e); + + ComponentUtils.showErrorMessage (Environment.getFocusedViewer (), + getUILanguageStringProperty (LanguageStrings.project,LanguageStrings.status,actionerror)); + //"Unable to update status"); + + } + + }); + + }); + + Environment.allProjects.addAll (all); + + } + + public static void addProjectInfo (ProjectInfo pi) + { + + Environment.allProjects.add (pi); + + } + + public static void doForOpenViewers (Consumer action) + { + + UIUtils.runLater (() -> + { + + Environment.openViewers.stream ().forEach (action); + + }); + + } + + public static void doForOpenProjects (Consumer action) + { + + UIUtils.runLater (() -> + { + + Environment.openProjects.values ().stream ().forEach (action); + + }); + + } + + public static StringProperty uilangProperty () + { + + return UILanguageStringsManager.uilangProperty (); + + } + + public static Set getOpenProjectViewers () + { + + return new LinkedHashSet<> (Environment.openProjects.values ()); + + } + + public static AbstractProjectViewer getProjectViewer (ProjectInfo p) + { + + return Environment.openProjects.get (p); + + } + + public static AbstractProjectViewer getProjectViewer (Project p) + { + + return Environment.openProjects.get (Environment.getProjectInfo (p)); + + } + + public static ObservableSet getOpenViewers () + { + + // TODO Return a read only version. + return Environment.openViewers; + + } + + public static void openProjectWithId (String projId, + String projType) + throws Exception + { + + Environment.openProject (projId, + projType, + null); + + } + + public static void openProject (Project p) + throws Exception + { + + Environment.openProject (p, + null); + + } + + public static void openProject (Project p, + Runnable onProjectOpen) + throws Exception + { + + if (p == null) + { + + return; + + } + + Environment.openProject (p.getId (), + p.getType (), + onProjectOpen); + + } + + public static void openProject (final String projId, + final String projType, + final Runnable onProjectOpen) + throws Exception + { + + ProjectInfo p = Environment.getProjectInfo (projId, + projType); + + if (p != null) + { + + Environment.openProject (p, + onProjectOpen); + + } + + } + + public static void openProject (final ProjectInfo p) + throws Exception + { + + Environment.openProject (p, + null); + + } + + public static void openProject (final ProjectInfo p, + final Runnable onProjectOpen) + throws Exception + { + + if (p == null) + { + + return; + + } + + if (p.isOpening ()) + { + + return; + + } + + AbstractProjectViewer pv = Environment.getProjectViewer (p); + + if (pv != null) + { + + p.setOpening (false); + pv.getViewer ().setIconified (false); + pv.getViewer ().toFront (); + + if (onProjectOpen != null) + { + + UIUtils.runLater (onProjectOpen); + + } + + return; + + } + + try + { + + pv = AbstractProjectViewer.createProjectViewerForType (p); + + } catch (Exception e) + { + + throw new GeneralException ("Unable to open project: " + + p, + e); + + } + + if (pv == null) + { + + throw new GeneralException ("Unable to open project: " + + p); + + } + + final AbstractProjectViewer fpv = pv; + + Consumer open = pwd -> + { + + try + { + + Viewer v = fpv.createViewer (); + + fpv.openProject (p, + pwd, + onProjectOpen); + + Environment.addOpenedProject (fpv); + + if (!UserProperties.keepProjectsWindowWhenProjectOpenedProperty ().getValue ()) + { + + if (Environment.allProjectsViewer != null) + { + + Environment.allProjectsViewer.close (null); + + } + + } + + } catch (Exception e) { + + try + { + + fpv.close (() -> + { + + // This prevents QW from going into a shutdown. + // TODO: Make this nicer. + + }); + + } catch (Exception ee) { + + Environment.logError ("Unable to close project after try open, project: " + p, + ee); + + } + + if (ObjectManager.isDatabaseAlreadyInUseException (e)) + { + + ComponentUtils.showErrorMessage (Environment.getFocusedViewer (), + getUILanguageStringProperty (project,actions,openproject,errors,projectalreadyopen)); + //"Sorry, the {project} appears to already be open in Quoll Writer. Please close all other instances of Quoll Writer first before trying to open the {project}."); + + return; + + } + + Environment.logError ("Unable to open project: " + p, + e); + + ComponentUtils.showErrorMessage (Environment.getFocusedViewer (), + getUILanguageStringProperty (Arrays.asList (project,actions,openproject,openerrors,general), + p.getName (), + getUILanguageStringProperty (project,actions,openproject,openerrors,unspecified))); + + } finally { + + p.setOpening (false); + + } + + Environment.startupComplete (); + + }; + + Environment.incrStartupProgress (); + + if (p.isEncrypted ()) + { + + Environment.startupComplete (); + + Environment.showAllProjectsViewer (); + + UIUtils.forceRunLater (() -> + { + + UIUtils.askForPasswordForProject (p, + null, + open, + null, + Environment.getFocusedViewer ()); + + }); + + } else { + + open.accept (null); + + } + + } + + /** + * Creates a completely new project with the specified name at the saveDir/name location. + * If the project is to be encrypted then a filePassword should be supplied. The schema will be created. + * + * @param saveDir The directory to save the project to. + * @param name The name of the project. + * @param filePassword Optional, provide if the project is to be encrypted. + * @returns The new project object created. + * @throws An exception if the schema cannot be created or if the save location already exists. + */ + // TODO Investigate how this differs from createProject. + public static Project createNewProject (Path saveDir, + String name, + String filePassword) + throws Exception + { + + Path projDir = saveDir.resolve (Utils.sanitizeForFilename (name)); + + if (Files.exists (projDir)) + { + + throw new IllegalArgumentException ("A project with name: " + + name + + " already exists at: " + + projDir); + + } + + Project p = new Project (); + p.setName (name); + + // Get the username and password. + String username = UserProperties.get (Constants.DB_USERNAME_PROPERTY_NAME); + String password = UserProperties.get (Constants.DB_PASSWORD_PROPERTY_NAME); + + ObjectManager dBMan = new ObjectManager (); + // TODO Change to use the path. + dBMan.init (projDir.resolve (Constants.PROJECT_DB_FILE_NAME_PREFIX).toFile (), + username, + password, + filePassword, + 0); + + // Create a file that indicates that the directory can be deleted. + Utils.createQuollWriterDirFile (projDir); + + // TODO Change to use the path. + p.setProjectDirectory (projDir.toFile ()); + p.setEncrypted (filePassword != null); + + Book b = new Book (p, + p.getName ()); + + p.addBook (b); + + dBMan.saveObject (p, + null); + + dBMan.closeConnectionPool (); + + ProjectInfo pi = new ProjectInfo (p); + +/* +TODO NEeded? + Environment.fireProjectInfoChangedEvent (pi, + ProjectInfoChangedEvent.ADDED); +*/ + return p; + + } + + /** + * Creates the specified project (containing the relevant information) at the saveDir/p.getName () location. + * If the project is to be encrypted then a filePassword should be supplied. The schema will be created. + * + * @param saveDir The directory where the project should be stored. + * @param p The project. + * @throws An exception if the schema cannot be created or if a project already exists at the save location. + */ + // TODO Investigate how this differs from createNewProject. + public static ObjectManager createProject (Path saveDir, + Project p) + throws Exception + { + + if (saveDir == null) + { + + throw new IllegalArgumentException ("Save directory must be specified."); + + } + + if (p.getName () == null) + { + + throw new IllegalArgumentException ("Project name must be specified."); + + } + + Path projDir = saveDir.resolve (Utils.sanitizeForFilename (p.getName ())); + + if (!Utils.isDirectoryEmpty (projDir)) + { + + throw new IllegalArgumentException ("New project directory: " + projDir + " is not empty."); + + } + + if (Files.exists (projDir)) + { + + throw new IllegalArgumentException ("A project with name: " + + p.getName () + + " already exists at: " + + projDir); + + } + + // Get the username and password. + String username = UserProperties.get (Constants.DB_USERNAME_PROPERTY_NAME); + String password = UserProperties.get (Constants.DB_PASSWORD_PROPERTY_NAME); + + ObjectManager dBMan = new ObjectManager (); + dBMan.init (projDir.resolve (Constants.PROJECT_DB_FILE_NAME_PREFIX).toFile (), + username, + password, + p.getFilePassword (), + 0); + + p.setEncrypted (p.getFilePassword () != null); + + // Create a file that indicates that the directory can be deleted. + Utils.createQuollWriterDirFile (projDir); + + p.setProjectDirectory (projDir.toFile ()); + + dBMan.setProject (p); + + dBMan.saveObject (p, + null); + + ProjectInfo pi = new ProjectInfo (p); + + Environment.projectInfoManager.saveObject (pi, + null); + + Environment.allProjects.add (pi); + + return dBMan; + + } + + @Deprecated + public static void deleteProject (Project p, + java.awt.event.ActionListener onDelete) + { + + Environment.deleteProject (p, + () -> + { + + com.quollwriter.ui.UIUtils.doLater (onDelete); + + }); + + } + + public static void deleteProject (Project p, + Runnable onDelete) + { + + ProjectInfo pi = Environment.getProjectInfo (p.getId (), + p.getType ()); + + if (pi == null) + { + + return; + + } + + Environment.deleteProject (pi, + onDelete); + + } + + @Deprecated + public static void deleteProject (final ProjectInfo pr, + final java.awt.event.ActionListener onDelete) + { + + Environment.deleteProject (pr, + () -> + { + + com.quollwriter.ui.UIUtils.doLater (onDelete); + + }); + + } + + public static void deleteProject (final ProjectInfo pr, + final Runnable onDelete) + { + + AbstractProjectViewer viewer = Environment.openProjects.get (pr); + + Runnable onClose = new Runnable () + { + + @Override + public void run () + { + + // There is probably now (because of h2) a "projectdb.lobs.db" directory. + // Add a can delete file to it. + /* + TODO Is this still needed? + try + { + + // TODO Change to use a path. + Utils.createQuollWriterDirFile (new File (pr.getProjectDirectory ().getPath () + "/projectdb.lobs.db")); + + } catch (Exception e) + { + + // Ignore for now. + Environment.logError ("Unable to add can delete dir file to: " + + pr.getProjectDirectory ().getPath () + "/projectdb.lobs.db", + e); + + } +*/ + // Remove the project from the list. + try + { + + // Delete the backup directory. + Utils.deleteDir (pr.getBackupDirPath ()); + + // Delete the files directory. + Utils.deleteDir (pr.getFilesDirectory ()); + + // Delete the directory. + Utils.deleteDir (pr.getProjectDirectory ()); + + Environment.projectInfoManager.deleteObject (pr, + false, + null); + + pr.dispose (); + + } catch (Exception e) + { + + // TODO Need to do more here? Maybe move the project to a different dir first? + // How do we recover? + Environment.logError ("Unable to delete project: " + + pr, + e); + + ComponentUtils.showErrorMessage (null, + getUILanguageStringProperty (Arrays.asList (project,actions,deleteproject,actionerror), + pr.getName ())); + + } + + Environment.openProjects.remove (pr); + Environment.allProjects.remove (pr); + + if (onDelete != null) + { + + UIUtils.runLater (onDelete); + + } else { + + Environment.showAllProjectsViewerIfNoOpenProjects (); + + } + + } + + }; + + if (viewer != null) + { + + if (Environment.openViewers.size () == 1) + { + + Environment.showAllProjectsViewer (); + + } + + // Don't try and save changes. + viewer.close (false, + onClose); + + } else { + + UIUtils.runLater (onClose); + + } + + } + + public static void deleteProject (Project pr) + { + + Environment.deleteProject (Environment.getProjectInfo (pr)); + + } + + public static void deleteProject (ProjectInfo pr) + { + + if (pr == null) + { + + return; + + } + + Environment.deleteProject (pr, + // TODO Fix this. + (Runnable) null); + + } + + public static void openObjectInProject (final ProjectInfo proj, + final DataObject obj) + throws Exception + { + + Environment.openProject (proj, + () -> + { + + // View the object. + AbstractProjectViewer viewer = Environment.getProjectViewer (proj); + + try + { + + viewer.viewObject (obj, + null); + + } catch (Exception e) { + + Environment.logError ("Unable to view object: " + + obj, + e); + + // TODO Show error + + } + + }); + + } + + public static void openObjectInProject (final Project proj, + final DataObject obj) + throws Exception + { + + final DataObject dobj = obj; + + ProjectInfo p = null; + + try + { + + p = Environment.getProjectInfo (proj); + + } catch (Exception e) { + + throw new GeneralException ("Unable to get project info for project id: " + + proj.getId (), + e); + + } + + if (p == null) + { + + throw new GeneralException ("Unable to get project info for project id: " + + proj.getId ()); + + } + + Environment.openObjectInProject (p, + obj); + + } + + public static ProjectInfo getWarmupsProject () + throws Exception + { + + for (ProjectInfo pi : Environment.allProjects) + { + + if (pi.isWarmupsProject ()) + { + + return pi; + + } + + } + + return null; + + } + + public static void updateProjectInfo (ProjectInfo pi) + throws GeneralException + { + + Environment.projectInfoManager.saveObject (pi, + null); + + } + + private static void closeDown () + { + + if (Environment.getOpenViewers ().size () > 0) + { + + throw new IllegalStateException ("Cannot closedown when there are open viewers."); + + } + + Environment.generalTimer.shutdown (); + + // Go offline from the editors service (if logged in). + EditorsEnvironment.closeDown (); + + Environment.userSession.end (new Date ()); + + try + { + + Environment.projectInfoManager.addSession (Environment.userSession); + + } catch (Exception e) { + + Environment.logError ("Unable to add session", + e); + + } + + Environment.projectInfoManager.closeConnectionPool (); + + if (Environment.doOnShutdown.size () > 0) + { + + for (Runnable r : Environment.doOnShutdown) + { + + try + { + + r.run (); + + } catch (Exception e) { + + Environment.logError ("Unable to run on shutdown.", + e); + + } + + } + + } + + Platform.exit (); + + } + + public static void setUILanguage (String id) + throws Exception + { + + UILanguageStringsManager.setUILanguage (id); + + Environment.loadUserObjectTypeNames (); + + } + + /** + * Un-schedule the scheduledfuture, this is returned from Environment.schedule. + * + * @param f The scheduledfuture to remove from the executor service. + * @returns Whether it was successfully removed. + */ + public static void unschedule (ScheduledFuture f) + { + + if (f == null) + { + + return; + + } + + // Let it run to completion. + f.cancel (false); + + Environment.generalTimer.purge (); + + } + + public static ScheduledFuture scheduleImmediately (Runnable r) + { + + return Environment.schedule (r, + 0, + -1); + + } + + /** + * Schedule the runnable to run after delay and repeat (use -1 or 0 for no repeat). + * + * @param r The runnable to run. + * @param delay The delay, in millis. + * @param repeat The repeat time, in millis. + */ + public static ScheduledFuture schedule (final Runnable r, + final long delay, + final long repeat) + { + + if (Environment.generalTimer == null) + { + + Environment.logError ("Unable to schedule timer is no longer valid."); + + return null; + + } + + if (r == null) + { + + Environment.logError ("Unable to schedule, runnable is null."); + + return null; + + } + + if (Environment.generalTimer.isShutdown ()) + { + + return null; + + } + + if (repeat < 1) + { + + return Environment.generalTimer.schedule (() -> + { + + try + { + + r.run (); + + } catch (Exception e) { + + Environment.logError ("Unable to run: " + r, + e); + + } + + }, + (delay < 0 ? 0 : delay), + TimeUnit.MILLISECONDS); + + } else { + + return Environment.generalTimer.scheduleAtFixedRate (() -> + { + + try + { + + r.run (); + + } catch (Exception e) { + + Environment.logError ("Unable to run: " + r, + e); + + } + + }, + (delay < 0 ? 0 : delay), + repeat, + TimeUnit.MILLISECONDS); + + } + + } + + public static Set getAllProjectInfos (String limitToType) + throws Exception + { + + Set ret = new LinkedHashSet<> (); + + if (limitToType != null) + { + + for (ProjectInfo p : Environment.allProjects) + { + + if (p.getType ().equals (limitToType)) + { + + ret.add (p); + + } + + } + + } else { + + ret.addAll (Environment.allProjects); + + } + + return ret; + + } + + public static Set getAllProjectInfos () + throws Exception + { + + return Environment.getAllProjectInfos (null); + + } + + // LEGACY + private static void initProjectsDBFromProjectsPath () + throws Exception + { + + Path f = Environment.getUserPath (Constants.PROJECTS_FILE_NAME); + + if (Files.notExists (f)) + { + + return; + + } + + // Get the projects file. + Element root = DOM4JUtils.fileAsElement (f); + + for (Element pEl : root.elements (Project.OBJECT_TYPE)) + { + + Project p = null; + + try + { + + p = new Project (pEl); + + } catch (Exception e) { + + Environment.logError ("Unable to convert element: " + + DOM4JUtils.getPath (pEl) + + " to a project", + e); + + continue; + + } + + ProjectInfo pi = null; + + // Try and load the project. + try + { + + pi = new ProjectInfo (p); + + ObjectManager om = Environment.createProjectObjectManager (pi, + null); + + // Now deal with the real project. + pi = new ProjectInfo (om.getProject ()); + + pi.setEncrypted (p.isEncrypted ()); + pi.setNoCredentials (p.isNoCredentials ()); + + om.closeConnectionPool (); + + } catch (Exception e) { + + Environment.logError ("Unable to load project: " + + p, + e); + + } + + if (pi == null) + { + + try + { + + pi = new ProjectInfo (p); + + } catch (Exception e) { + + Environment.logError ("Unable to convert project: " + + p + + " to a project info", + e); + + continue; + + } + + } + + try + { + + Environment.projectInfoManager.saveObject (pi, + null); + + } catch (Exception e) { + + Environment.logError ("Unable to load project: " + + p + + ", path: " + + DOM4JUtils.getPath (pEl) + + " into the project db", + e); + + } + + } + + // Remove the projects file (rename for now). + // TODO Check this. + Files.move (f, f.getParent ().resolve (f.getFileName () + ".old")); + + } + + public static ReadOnlyBooleanProperty startupCompleteProperty () + { + + return Environment.startupCompleteProp.readOnlyBooleanProperty (Environment.startupCompleteProp); + + } + + public static void startupComplete () + { + + Environment.startupCompleteProp.setValue (true); + Environment.startupProgressProp.setValue (1); + + } + + public static void incrStartupProgress () + { + + if (Environment.startupCompleteProperty ().getValue ()) + { + + return; + + } + + double v = Environment.startupProgressProp.getValue () + 0.09d; + + if (v > 1) + { + + v = 1; + + } + + Environment.startupProgressProp.setValue (v); + + } + + public static boolean isDistractionFreeModeEnabled () + { + + for (AbstractProjectViewer pv : Environment.openProjects.values ()) + { + + if (pv.isDistractionFreeModeEnabled ()) + { + + return true; + + } + + } + + return false; + + } + + public static AllProjectsViewer getAllProjectsViewer () + { + + return Environment.allProjectsViewer; + + } + + public static AbstractViewer showAllProjectsViewer () + { + + if (Environment.allProjectsViewer == null) + { + + try + { + + Environment.allProjectsViewer = new AllProjectsViewer (); + Environment.allProjectsViewer.createViewer (); + Environment.allProjectsViewer.init (null); + + UIUtils.forceRunLater (() -> + { + + if (Environment.allProjectsViewer != null) + { + + Environment.allProjectsViewer.requestFocus (); + + } + + }); + + Environment.allProjectsViewer.getViewer ().addEventHandler (Viewer.ViewerEvent.CLOSE_EVENT, + (ev -> + { + + Environment.openViewers.remove (Environment.allProjectsViewer); + Environment.allProjectsViewer = null; + + })); + + } catch (Exception e) { + + Environment.logError ("Unable to create all projects viewer.", + e); + + // TODO Add show error message when no viewer... + ComponentUtils.showErrorMessage (null, + getUILanguageStringProperty (allprojects,actionerror)); + + return null; + + } + + } + + Environment.allProjectsViewer.setVisible (true); + Environment.allProjectsViewer.toFront (); + Environment.allProjectsViewer.requestFocus (); + + return Environment.allProjectsViewer; + + } + + public static ObservableSet getAllProjects () + { + + return Environment.allProjects; + + } + + public static AbstractViewer getFocusedViewer () + { + + if (Environment.openViewers.size () == 0) + { + + return null; + + } + + for (AbstractViewer viewer : Environment.openViewers) + { + + if (viewer.focusedProperty ().getValue ()) + { + + return viewer; + + } + + } + + // Return the first viewer that is showing. + for (AbstractViewer viewer : Environment.openViewers) + { + + if (viewer.getViewer ().showingProperty ().getValue ()) + { + + return viewer; + + } + + } + + // What the derp... Return the first. + return Environment.openViewers.iterator ().next (); + + } + + public static ProjectInfo getProjectInfo (Project p) + { + + ProjectInfo pi = Environment.getProjectInfo (p.getId (), + p.getType ()); + + if (pi != null) + { + + pi.setFilePassword (p.getFilePassword ()); + + } + + return pi; + + } + + public static ProjectInfo getProjectInfo (String id, + String type) + { + + try + { + + for (ProjectInfo p : Environment.getAllProjectInfos ()) + { + + if (p.getId ().equals (id)) + { + + if (type == null) + { + + return p; + + } + + if (type.equals (p.getType ())) + { + + return p; + + } + + } + + } + + } catch (Exception e) { + + Environment.logError ("Unable to get all project infos to check for project: " + + id + + ", type: " + + type, + e); + + } + + return null; + + } + + public static int getProjectInfoSchemaVersion () + { + + Path p = Environment.getProjectInfoDBPath (); + + Path f = p.getParent ().resolve (p.getFileName () + Constants.H2_DB_FILE_SUFFIX); + + // See if we already have a project info db. + if (Files.exists (f)) + { + + return Environment.projectInfoSchemaVersion; + + } + + // No file, so need to create the schema. + return 0; + + } + + public static Path getLogDir () + throws IOException + { + + Path d = Environment.getUserPath (Constants.LOGS_DIR); + + Files.createDirectories (d); + + return d; + + } + + public static Path getProjectInfoDBPath () + { + + Path dir = null; + + String dv = UserProperties.get (Constants.PROJECT_INFO_DB_DIR_PROPERTY_NAME); + + if (dv != null) + { + + dir = Paths.get (dv); + + } else { + + dir = Environment.userQuollWriterDirPath; + + } + + return dir.resolve (Constants.PROJECT_INFO_DB_FILE_NAME_PREFIX); + + } + + public static void saveUserProperties () + throws Exception + { + + Environment.projectInfoManager.setUserProperties (UserProperties.getProperties ());//Environment.userProperties); + + } + + public static DoubleProperty objectTypeNameChangedProperty () + { + + return Environment.objectTypeNameChangedProp; + + } + + /** + * TODO: Remove, causes an inifinite loop since it is asking for the names from the user file anyway... + */ + @Deprecated + public static void resetObjectTypeNamesToDefaults () + throws IOException + { + + Environment.objectTypeNamesSingular.clear (); + Environment.objectTypeNamesPlural.clear (); +/* + // Load the default object type names. + try + { + + Environment.loadObjectTypeNames (JDOMUtils.getStringAsElement (Environment.getResourceFileAsString (Constants.DEFAULT_OBJECT_TYPE_NAMES_FILE))); + + } catch (Exception e) { + + Environment.logError ("Unable to load default object type names from resource file: " + + Constants.DEFAULT_OBJECT_TYPE_NAMES_FILE); + + } +*/ + Path otf = UserProperties.getUserObjectTypeNamesPath (); + + // Remove the file. + Files.deleteIfExists (otf); + + otf = Environment.getUserPath (Constants.LEGACY_OBJECT_TYPE_NAMES_FILE_NAME); + + Files.deleteIfExists (otf); + Environment.loadUserConfigurableObjectTypeNames (); + + // Load the + UserConfigurableObjectType chapterType = Environment.getUserConfigurableObjectType (Chapter.OBJECT_TYPE); + + if (chapterType != null) + { + + Environment.objectTypeNamesPlural.put (Chapter.OBJECT_TYPE, + getUILanguageStringProperty (objectnames,plural,Chapter.OBJECT_TYPE)); + Environment.objectTypeNamesSingular.put (Chapter.OBJECT_TYPE, + getUILanguageStringProperty (objectnames,singular,Chapter.OBJECT_TYPE)); + + } + + Environment.objectTypeNameChangedProp.setValue (Environment.objectTypeNameChangedProp.getValue () + 1); + + } + + private static void loadUserObjectTypeNames () + throws Exception + { + + Path f = UserProperties.getUserObjectTypeNamesPath (); + + if (Files.exists (f)) + { + + // Use this one. + Map t = (Map) JSONDecoder.decode (Utils.getFileContentAsString (f)); + + Map sing = (Map) t.get (LanguageStrings.singular); + Map plur = (Map) t.get (LanguageStrings.plural); + + Map singv = new HashMap<> (); + Map plurv = new HashMap<> (); + + if (sing != null) + { + + Iterator iter = sing.keySet ().iterator (); + + while (iter.hasNext ()) + { + + Object k = iter.next (); + Object v = sing.get (k); + + if (v.toString ().contains ("${")) + { + + Environment.logError ("Singular user object type key: " + k + ", " + v); + + } + + singv.put (k.toString (), + new SimpleStringProperty (v.toString ())); + + } + + } + + if (plur != null) + { + + Iterator iter = plur.keySet ().iterator (); + + while (iter.hasNext ()) + { + + Object k = iter.next (); + Object v = plur.get (k); + + if (v.toString ().contains ("${")) + { + + Environment.logError ("Plural user object type key: " + k + ", " + v); + + } + + plurv.put (k.toString (), + new SimpleStringProperty (v.toString ())); + + } + + } + + Environment.updateUserObjectTypeNames (singv, + plurv); + + } else { + + // Legacy: pre 2.6.2 + f = Environment.getUserPath (Constants.LEGACY_OBJECT_TYPE_NAMES_FILE_NAME); + + if (Files.exists (f)) + { + + Environment.loadLegacyObjectTypeNames (DOM4JUtils.stringAsElement (Utils.getFileContentAsString (f))); + + Environment.updateUserObjectTypeNames (Environment.objectTypeNamesSingular, + Environment.objectTypeNamesPlural); + + Files.deleteIfExists (f); + + } + + } + + Environment.loadUserConfigurableObjectTypeNames (); + + } + + private static void loadUserConfigurableObjectTypeNames () + { + + Map singular = Environment.objectTypeNamesSingular; + Map plural = Environment.objectTypeNamesPlural; + + // Load the names from the configurable types. + for (UserConfigurableObjectType t : Environment.userConfigObjTypes) + { + + if (t.isAssetObjectType ()) + { + + plural.put ("asset:" + t.getKey (), + t.objectTypeNamePluralProperty ()); + singular.put ("asset:" + t.getKey (), + t.objectTypeNameProperty ()); + + } + + } +/* + // TODO: Fix this, special for now. + UserConfigurableObjectType chapterType = Environment.getUserConfigurableObjectType (Chapter.OBJECT_TYPE); + + if (chapterType != null) + { +xxx + plural.put (Chapter.OBJECT_TYPE, + chapterType.getObjectTypeNamePlural ()); + singular.put (Chapter.OBJECT_TYPE, + chapterType.getObjectTypeName ()); + + } +*/ + + } + + private static void loadLegacyObjectTypeNames (Element root) + throws Exception + { + + Map singular = new HashMap<> (); + Map plural = new HashMap<> (); + + for (Element el : root.elements (XMLConstants.object)) + { + + String objType = DOM4JUtils.attributeValue (el, + XMLConstants.type); + + objType = objType.toLowerCase (); + + String s = DOM4JUtils.childElementContent (el, + XMLConstants.singular, + false, + null); + + if (s != null) + { + + if (s.contains ("${")) + { + + Environment.logError ("Singular legacy user object type key: " + objType + ", " + s); + + } + + singular.put (objType, + new SimpleStringProperty (s)); + + } + + String p = DOM4JUtils.childElementContent (el, + XMLConstants.plural, + false, + null); + + if (p != null) + { + + if (p.contains ("${")) + { + + Environment.logError ("Plural legacy user object type key: " + objType + ", " + p); + + } + + plural.put (objType, + new SimpleStringProperty (p)); + + } + + } + + Environment.updateUserObjectTypeNames (singular, + plural); + + } +/* + public static File getGeneralLogFile () + throws IOException + { + + return Environment.getLogDir ().resolve (Constants.GENERAL_LOG_NAME).toFile (); + + } + + public static File getSQLLogFile () + throws IOException + { + + return Environment.getLogDir ().resolve (Constants.SQL_LOG_NAME).toFile (); + + } + + public static File getErrorLogFile () + throws IOException + { + + return Environment.getLogDir ().resolve (Constants.ERROR_LOG_NAME).toFile (); + + } + + public static Path getErrorLogPath () + throws IOException + { + + return Environment.getLogDir ().resolve (Constants.ERROR_LOG_NAME); + + } +*/ + + public static Path getLogPath () + { + + Set paths = Environment.getLogPaths (); + + if (paths.size () > 0) + { + + return paths.iterator ().next (); + + } + + return null; + + } + + public static Set getLogPaths () + { + + Path p = Paths.get (System.getProperty ("user.home")); + + p = p.resolve ("QuollWriter"); + + Set paths = new TreeSet<> ((p1, p2) -> + { + + try + { + + return Files.getLastModifiedTime (p1).compareTo (Files.getLastModifiedTime (p2)); + + } catch (Exception e) { + + Environment.logError ("Unable to compare last modified times for: " + p1 + " and: " + p2, + e); + return 0; + + } + + }); + + if (Files.exists (p)) + { + + try + { + + Files.list (p) + .filter (path -> + { + + return ((path.getFileName ().toString ().startsWith ("QuollWriter.log")) + && + (!path.getFileName ().toString ().endsWith (".lck")) + ); + + }) + .forEach (path -> + { + + paths.add (path); + + }); + + } catch (Exception e) { + + Environment.logError ("Unable to walk files in path: " + p, + e); + + } + + } + + return paths; + + } + + private static void saveUserObjectTypeNames () + throws Exception + { + + Map> t = new HashMap<> (); + + t.put (LanguageStrings.singular, + Environment.objectTypeNamesSingular); + t.put (LanguageStrings.plural, + Environment.objectTypeNamesPlural); + + Utils.writeStringToFile (UserProperties.getUserObjectTypeNamesPath (), + JSONEncoder.encode (t)); + + } + + /** + * Get an object manager for the specified project and init it. + * + * @param p The project. + * @param filePassword Optional, the password for the project if it is encrypted. + * @returns The object manager for the project. + * @throws An exception if the object manager cannot be inited. + * TODO: Move the filepassword into the project and expect it there instead. + */ + public static ObjectManager createProjectObjectManager (ProjectInfo p, + String filePassword) + throws GeneralException + { + + // TODO Investigate using this in the AbstractProjectViewer. + + // Get the username and password. + String username = UserProperties.get (Constants.DB_USERNAME_PROPERTY_NAME); + String password = UserProperties.get (Constants.DB_PASSWORD_PROPERTY_NAME); + + if (p.isNoCredentials ()) + { + + username = null; + password = null; + + } + + ObjectManager dBMan = new ObjectManager (); + dBMan.init (p.getProjectDirectory ().resolve (Constants.PROJECT_DB_FILE_NAME_PREFIX).toFile (), + username, + password, + filePassword, + Environment.getSchemaVersion ()); + + try + { + + dBMan.getProject (); + + } catch (Exception e) { + + dBMan.closeConnectionPool (); + + throw e; + + } + + return dBMan; + + } + + public static int getSchemaVersion () + { + + return Environment.schemaVersion; + + } + + public static void doNewsAndVersionCheck (final AbstractViewer viewer) + { + + if (Environment.doneVersionCheck) + { + + return; + + } + + String updaterClass = UserProperties.get (Constants.UPDATER_CLASS_PROPERTY_NAME, + null); + + Class updaterCl = null; + + try + { + + updaterCl = Class.forName (updaterClass); + + if (!QuollWriterUpdater.class.isAssignableFrom (updaterCl)) + { + + Environment.logError (String.format ("Expected class: %s, given by property: %s to be an instance of: %s", + updaterClass, + Constants.UPDATER_CLASS_PROPERTY_NAME, + QuollWriterUpdater.class.getName ())); + + updaterCl = null; + + } + + } catch (Exception e) { + + Environment.logError (String.format ("Unable to load class: %s given by property: %s", + updaterClass, + Constants.UPDATER_CLASS_PROPERTY_NAME), + e); + + } + + QuollWriterUpdater updater = null; + + if (updaterCl != null) + { + + try + { + + updater = (QuollWriterUpdater) updaterCl.getDeclaredConstructor ().newInstance (); + + } catch (Exception e) { + + Environment.logError (String.format ("Unable to create new instance of: %s, given by property: %s", + updaterClass, + Constants.UPDATER_CLASS_PROPERTY_NAME), + e); + + } + + } + + if ((UserProperties.getAsBoolean (Constants.DO_AUTO_UPDATE_CHECK_PROPERTY_NAME)) + && + (updater != null) + ) + { + + Environment.doneVersionCheck = true; + + final QuollWriterUpdater _updater = updater; + + Environment.scheduleImmediately (() -> + { + + try + { + + _updater.doUpdate (viewer); + + } catch (Exception e) + { + + Environment.logError ("Unable to perform update check", + e); + + } + + }); + + } + + } + + public static BooleanProperty debugModeProperty () + { + + return Environment.debugModeProp; + + } + + public static boolean isDebugModeEnabled () + { + + return Environment.debugModeProp.getValue (); + + } + + public static void setDebugModeEnabled (boolean v) + { + + Environment.debugModeProp.setValue (v); + + // TODO: Maybe have an EnvironmentEvent? + + } + + public static void addOpenedProject (AbstractProjectViewer pv) + throws Exception + { + + final Project proj = pv.getProject (); + + ProjectInfo p = Environment.getProjectInfo (proj.getId (), + proj.getType ()); + + if (p == null) + { + + // We don't have this project, so add it. + p = new ProjectInfo (proj); + + try + { + + Environment.projectInfoManager.saveObject (p, + null); + + } catch (Exception e) { + + Environment.logError ("Unable to add new project info for project: " + + proj, + e); + + } + + } else { + + p.setProject (proj); + + } + + ProjectInfo _p = p; + + // This is needed to remove the handler after use. + // Using a lambda won't work because of the "this" problem and this creates + // a hard reference to the viewer and proejct. + EventHandler h = new EventHandler<> () + { + + @Override + public void handle (Viewer.ViewerEvent ev) + { + + Environment.openProjects.remove (_p); +/* + pv.getViewer ().removeEventHandler (Viewer.ViewerEvent.CLOSE_EVENT, + this); +*/ + } + + }; + + pv.getViewer ().addEventHandler (Viewer.ViewerEvent.CLOSE_EVENT, + h); + Environment.openProjects.put (p, + pv); + + } + + public static SynonymProvider getSynonymProvider (String language) + throws GeneralException + { + + if (language == null) + { + + language = Constants.ENGLISH; + + } + + if (UILanguageStrings.isEnglish (language)) + { + + language = Constants.ENGLISH; + + } + + // For now, until we are able to support other languages return null for non-english. + if (!language.equals (Constants.ENGLISH)) + { + + return null; + + } + + SynonymProvider prov = Environment.synonymProviders.get (language.toLowerCase ()); + + if (prov != null) + { + + return prov; + + } + + String synCl = UserProperties.get (Constants.SYNONYM_PROVIDER_CLASS_PROPERTY_NAME); + + if (synCl != null) + { + + Class c = null; + + try + { + + c = Class.forName (synCl); + + } catch (Exception e) + { + + throw new GeneralException ("Unable to load synonym provider class: " + + synCl + + " specified by property: " + + Constants.SYNONYM_PROVIDER_CLASS_PROPERTY_NAME, + e); + + } + + if (!SynonymProvider.class.isAssignableFrom (c)) + { + + throw new GeneralException ("Expected synonym provider class: " + + synCl + + " specified by property: " + + Constants.SYNONYM_PROVIDER_CLASS_PROPERTY_NAME + + " to implement interface: " + + SynonymProvider.class.getName ()); + + } + + // Create the instance. + try + { + + prov = (SynonymProvider) c.getDeclaredConstructor ().newInstance (); + + } catch (Exception e) + { + + // Record the error but don't barf, it's just a service that isn't available + Environment.logError ("Unable to create new instance of synonym provider class: " + + synCl + + " specified by property: " + + Constants.SYNONYM_PROVIDER_CLASS_PROPERTY_NAME, + e); + + } + + if (!prov.isLanguageSupported (language)) + { + + return null; + + } + + try + { + + prov.init (language); + + } catch (Exception e) { + + Environment.logError ("Unable to init synonym provider instance for language: " + + language + + ", class: " + + synCl + + ", specified by property: " + + Constants.SYNONYM_PROVIDER_CLASS_PROPERTY_NAME, + e); + + } + + Environment.synonymProviders.put (language.toLowerCase (), + prov); + + } + + return prov; + + } + + // TODO Remove this add instead add a listener for the close event on the viewer. + public static void unregisterViewer (AbstractViewer v, + Runnable afterUnregister) + { + + // TODO Remove + + } + + public static void registerViewer (AbstractViewer v) + { + + Environment.openViewers.add (v); + + EventHandler h = new EventHandler<> () + { + + @Override + public void handle (Viewer.ViewerEvent ev) + { + + v.getViewer ().removeEventHandler (Viewer.ViewerEvent.CLOSE_EVENT, + this); + + Environment.openViewers.remove (v); + + int ops = Environment.openProjects.size (); + + // Have to do it this way because we can't predict the ordering that event handlers are called. + if (Environment.openProjects.values ().contains (v)) + { + + ops--; + + } + + if (ops <= 0) + { + + if ((v != Environment.allProjectsViewer) + && + (UserProperties.getAsBoolean (Constants.SHOW_PROJECTS_WINDOW_WHEN_NO_OPEN_PROJECTS_PROPERTY_NAME)) + ) + { + + Environment.showAllProjectsViewer (); + + return; + + } + + if ((Environment.allProjectsViewer != null) + && + (v != Environment.allProjectsViewer) + && + (Environment.allProjectsViewer.isVisible ()) + ) + { + + Environment.allProjectsViewer.toFront (); + return; + + } + + if ((Environment.closeDownAllowed) + && + (Environment.openViewers.size () == 0) + ) + { + + Environment.closeDown (); + + } + + return; + + } + + if (Environment.openViewers.size () == 0) + { + + if (Environment.closeDownAllowed) + { + + Environment.closeDown (); + + } + + } + + } + + }; + + v.getViewer ().addEventHandler (Viewer.ViewerEvent.CLOSE_EVENT, + h); + + } + + public static String getDefaultTextAlignment () + { + + return getUIString (textalignments,left); + + } + + public static String getDefaultChapterName () + { + + return getUIString (general,defaultchaptername); + + } + + public static com.gentlyweb.properties.Properties getDefaultProperties (String objType) + { + + com.gentlyweb.properties.Properties props = (com.gentlyweb.properties.Properties) Environment.defaultObjectProperties.get (objType); + + if (props == null) + { + + // Create some new blank properties. + props = new com.gentlyweb.properties.Properties (); + + Environment.defaultObjectProperties.put (objType, + props); + + } + + if (props.getId () == null) + { + + props.setId ("default-" + objType); + + } + + if (props.getParentProperties () == null) + { + + props.setParentProperties (UserProperties.getProperties ()); + + } + + return props; + + } + + public static void saveDefaultProperty (String objType, + String propName, + Boolean value) + throws Exception + { + + com.gentlyweb.properties.Properties props = Environment.getDefaultProperties (objType); + + props.setProperty (propName, + new com.gentlyweb.properties.BooleanProperty (propName, + value)); + + Environment.saveDefaultProperties (objType, + props); + + } + + public static void saveDefaultProperty (String objType, + String propName, + String value) + throws Exception + { + + com.gentlyweb.properties.Properties props = Environment.getDefaultProperties (objType); + + props.setProperty (propName, + new com.gentlyweb.properties.StringProperty (propName, + value)); + + Environment.saveDefaultProperties (objType, + props); + + } + + // TODO Improve this... + public static void saveDefaultProperties (String objType, + com.gentlyweb.properties.Properties props) + throws Exception + { + + // TODO Use a constant here. + Path f = Environment.getUserPath ("default-" + objType + "-properties.xml"); + + DOM4JUtils.writeToFile (props.getAsElement (), + f, + true); + + } + + // TODO Make a singleton accessible to any class. + public static AchievementsManager getAchievementsManager () + { + + return Environment.achievementsManager; + + } + + public static void removeUserProjectEventListener (ProjectEventListener l) + { + + Environment.userProjectEventListeners.remove (l); + + } + + public static void addUserProjectEventListener (ProjectEventListener l) + { + + Environment.userProjectEventListeners.put (l, + Environment.listenerFillObj); + + } + + public static void fireUserProjectEvent (Object source, + ProjectEvent.Type type, + ProjectEvent.Action action, + Object contextObject) + { + + Environment.fireUserProjectEvent (new ProjectEvent (source, + type, + action, + contextObject)); + + } + + public static void fireUserProjectEvent (Object source, + ProjectEvent.Type type, + ProjectEvent.Action action) + { + + Environment.fireUserProjectEvent (source, + type, + action, + null); + + } + + public static void fireUserProjectEvent (ProjectEvent.Type type, + ProjectEvent.Action action) + { + + Environment.fireUserProjectEvent (new ProjectEvent (new Object (), + type, + action, + null)); + + } + + public static void fireUserProjectEvent (final ProjectEvent ev) + { + + UIUtils.runLater (() -> + { + + Set ls = null; + + // Get a copy of the current valid listeners. + synchronized (Environment.userProjectEventListeners) + { + + ls = new LinkedHashSet (Environment.userProjectEventListeners.keySet ()); + + } + + for (ProjectEventListener l : ls) + { + + l.eventOccurred (ev); + + } + + }); + + } + + public static FullScreenTextProperties getFullScreenTextProperties () + { + + return Environment.fullScreenTextProps; + + } + + public static ProjectTextProperties getProjectTextProperties () + { + + return Environment.projectTextProps; + + } + + public static Path getUserQuollWriterDirPath () + { + + return Environment.userQuollWriterDirPath; + + } + + public static Path getUserPath (String name) + { + + if (name.startsWith ("/")) + { + + name = name.substring (1); + + } + + return Environment.userQuollWriterDirPath.resolve (name); + + } + + public static void removeSideBarFromAllProjectViewers (String id) + { + + for (AbstractProjectViewer pv : Environment.openProjects.values ()) + { + + pv.removeSideBar (pv.getSideBarById (id)); + + } + + } + + public static StringProperty canOpenProject (Project p) + { + + return Environment.canOpenProject (Environment.getProjectInfo (p)); + + } + + public static StringProperty canOpenProject (ProjectInfo p) + { + + List prefix = Arrays.asList (LanguageStrings.project,LanguageStrings.actions,LanguageStrings.openproject,LanguageStrings.openerrors); + + if (p == null) + { + + return getUILanguageStringProperty (Utils.newList (prefix,projectnotexist)); + //return "{Project} does not exist."; + + } + + if (Files.notExists (p.getProjectDirectory ())) + { + + return getUILanguageStringProperty (Utils.newList (prefix,projectdirnotexist), + p.getProjectDirectory ()); + //return "Cannot find {project} directory " + p.getProjectDirectory () + "."; + + } + + if (!Files.isDirectory (p.getProjectDirectory ())) + { + + return getUILanguageStringProperty (Utils.newList (prefix,projectdirisfile), + p.getProjectDirectory ()); + //return "Path to {project} " + p.getProjectDirectory () + " is a file, but a directory is expected."; + + } + + if (Files.notExists (Utils.getQuollWriterDirFile (p.getProjectDirectory ()))) + { + + return getUILanguageStringProperty (Utils.newList (prefix,invalidprojectdir), + p.getProjectDirectory ()); + //return "{Project} directory " + p.getProjectDirectory () + " doesn't appear to be a valid Quoll Writer {project}."; + + } + + if ((p.isEditorProject ()) + && + (p.getForEditor () != null) + && + (EditorsEnvironment.getEditorByEmail (p.getForEditor ().getEmail ()) == null) + ) + { + + return getUILanguageStringProperty (Utils.newList (prefix,cantfindeditor), + //"Unable to find {contact}: %s you are editing the {project} for.", + p.getForEditor ().getEmail ()); + + } + + return null; + + } + + // TODO Move to own helper class, no need for it to be here. + public static Double parseToDouble (String v) + throws GeneralException + { + + if (v == null) + { + + return null; + + } + + try + { + + return Double.valueOf (Environment.floatNumFormat.parse (v, + new ParsePosition (0)).doubleValue ()); + + } catch (Exception e) { + + throw new GeneralException ("Unable to convert: " + + v + + " to a double.", + e); + + } + + } + + public static String formatNumber (int i) + { + + return Environment.numFormat.format (i); + + } + + public static String formatNumber (long i) + { + + return Environment.numFormat.format (i); + + } + + public static String formatNumber (float f) + { + + return Environment.floatNumFormat.format (f); + + } + + public static String formatNumber (double f) + { + + return Environment.floatNumFormat.format (f); + + } + + public static String formatLocalDate (LocalDate d) + { + + return d.format (DateTimeFormatter.ofPattern ("d MMM yyyy")); + + } + + public static String formatDateTime (Date d) + { + + return Environment.formatDate (d) + " " + Environment.formatTime (d); + + } + + public static String formatDate (Date d) + { + + return Environment.dateFormatter.format (d); + + } + + public static String formatTime (Date d) + { + + return Environment.timeFormatter.format (d); + + } + + @Deprecated + public static String getUIString (String... ids) + { + + return UILanguageStringsManager.getUIString (Arrays.asList (ids)); + + } + + @Deprecated + public static String getUIString (List prefix, + String id) + { + + return UILanguageStringsManager.getUIString (Utils.newList (prefix, id)); +/* +TODO Remove + List ids = new ArrayList (prefix); + + ids.add (id); + + return Environment.getUIString (ids); +*/ + } + + @Deprecated + public static String getUIString (List prefix, + String... ids) + { + + return UILanguageStringsManager.getUIString (Utils.newList (prefix, ids)); +/* +TODO Remove + List _ids = new ArrayList (prefix); + + for (String s : ids) + { + + _ids.add (s); + + } + + return Environment.getUIString (_ids); +*/ + } + +/* +TODO Remove + private static String getUIString (List ids) + { + + String s = Environment.uiLanguageStrings.getString (ids); + + if (s == null) + { + + s = BaseStrings.toId (ids); + + } + + return s; + + } +*/ + + public static void logDebugMessage (String m) + { + + if (Environment.isDebugModeEnabled ()) + { + + Environment.logMessage (m); + + } + + } + + public static void logMessage (String m) + { + + if (Environment.isDebugModeEnabled ()) + { + + //System.out.println (m); + + } + + Environment.logger.info (m); + + } + + public static void logError (String m) + { + + Environment.logError (m, + null); + + } + + public static void logSQLStatement (String s, + List params) + { + + if (!Environment.isDebugModeEnabled ()) + { + + return; + + } + + Environment.sqlLog.info ("SQL:=============================\n" + s + "\nPARAMS:\n" + params); + + } + + public static void logError (String m, + Exception ex) + { + + Environment.logger.log (Level.SEVERE, + m, + ex); + + if ((!Environment.isDebugModeEnabled ()) + && + (UserProperties.getAsBoolean (Constants.AUTO_SEND_ERRORS_TO_SUPPORT_PROPERTY_NAME)) + ) + { + + Map details = new HashMap (); + /* + try + { + + details.put ("errorLog", + IOUtils.getFile (Environment.getErrorLogFile ())); + details.put ("generalLog", + IOUtils.getFile (Environment.getGeneralLogFile ())); + + } catch (Exception e) { + + // NOt much we can do here! + + } + */ + details.put ("reason", + m); + + if (ex != null) + { + + details.put ("stackTrace", + Utils.getStackTrace (ex)); + + } + + try + { + + Environment.sendMessageToSupport ("error", + details, + (Runnable) null); + + } catch (Exception e) { + + // Nothing we can do. + + } + + } + + } + + public static void addDoOnShutdown (Runnable r) + { + + Environment.doOnShutdown.add (r); + + } + + @Deprecated + public static void sendMessageToSupport (final String type, + final Map info, + final java.awt.event.ActionListener onComplete) + { + + Environment.sendMessageToSupport (type, + info, + () -> + { + + com.quollwriter.ui.fx.swing.SwingUIUtils.doLater (onComplete); + + }); + + } + + public static void sendMessageToSupport (final String type, + final Map info, + final Runnable onComplete) + { + + Environment.scheduleImmediately (() -> + { + + try + { + + info.put ("quollWriterVersion", + Environment.getQuollWriterVersion ().toString ()); + info.put ("beta", + Environment.appVersion.isBeta ()); + info.put ("javaVersion", + System.getProperty ("java.version")); + info.put ("osName", + System.getProperty ("os.name")); + info.put ("osVersion", + System.getProperty ("os.version")); + info.put ("osArch", + System.getProperty ("os.arch")); + + Element root = new DefaultElement ("message"); + root.addAttribute ("quollWriterVersion", + Environment.getQuollWriterVersion ().toString ()); + root.addAttribute ("beta", + String.valueOf (Environment.appVersion.isBeta ())); + root.addAttribute ("javaVersion", + System.getProperty ("java.version")); + root.addAttribute ("osName", + System.getProperty ("os.name")); + root.addAttribute ("osVersion", + System.getProperty ("os.version")); + root.addAttribute ("osArch", + System.getProperty ("os.arch")); + root.addAttribute ("type", + type); + + // Encode as XML. + Iterator iter = info.keySet ().iterator (); + + while (iter.hasNext ()) + { + + String k = iter.next (); + + Object v = info.get (k); + + Element el = new DefaultElement (k.toString ()); + + if (v != null) + { + + el.add (new DefaultCDATA (v.toString ())); + + } + + root.add (el); + + } + + // Get as a string. + String data = DOM4JUtils.elementAsString (root); + + URL u = Environment.getSupportUrl (Constants.SEND_MESSAGE_TO_SUPPORT_PAGE_PROPERTY_NAME); + + HttpURLConnection conn = (HttpURLConnection) u.openConnection (); + + conn.setDoInput (true); + conn.setDoOutput (true); + + conn.connect (); + + BufferedWriter bout = new BufferedWriter (new OutputStreamWriter (conn.getOutputStream (), + StandardCharsets.UTF_8)); + + bout.write (data); + bout.flush (); + bout.close (); + + BufferedReader b = new BufferedReader (new InputStreamReader (conn.getInputStream (), + StandardCharsets.UTF_8)); + + String detail = b.readLine (); + + b.close (); + + if (((detail == null) + || + (!detail.equals ("SUCCESS")) + ) + && + (!type.equals ("error")) + ) + { + + throw new GeneralException ("Unable to get send message to support for url: " + + u + + ", response is: " + + detail); + + } + + if (onComplete != null) + { + + UIUtils.runLater (onComplete); + + } + + } catch (Exception e) { + + if (onComplete != null) + { + + UIUtils.runLater (onComplete); + + } + + if (!type.equals ("error")) + { + + Environment.logError ("Unable to send message to support", + e); + + } + + } + + }); + + } + + // TODO Is this needed? + public static void setUserObjectTypeIcon (String objType, + java.awt.image.BufferedImage image) + throws Exception + { + + javax.imageio.ImageIO.write (image, + "png", + Environment.getUserObjectTypeIconFilePath (objType).toFile ()); + + } + + // TODO Is this needed? + public static Path getUserObjectTypeIconFilePath (String objType) + { + + return Environment.getUserPath (Constants.USER_OBJECT_TYPE_ICON_FILES_DIR).resolve (objType); + + } + + public static Set getAssetUserConfigurableObjectTypes (boolean sortOnName) + { + + Set types = new LinkedHashSet<> (); + + for (UserConfigurableObjectType t : Environment.userConfigObjTypes) + { + + if (t.isAssetObjectType ()) + { + + types.add (t); + + } + + } + + if (sortOnName) + { + + List stypes = new ArrayList<> (types); + + Collections.sort (stypes, + (o1, o2) -> o1.getObjectTypeName ().compareTo (o2.getObjectTypeName ())); + + types = new LinkedHashSet<> (stypes); + + } + + return types; + + } + + public static UserConfigurableObjectTypeField getUserConfigurableObjectTypeField (long key) + throws GeneralException + { + + return (UserConfigurableObjectTypeField) Environment.projectInfoManager.getObjectByKey (UserConfigurableObjectTypeField.class, + key, + null, + null, + true); + + } + + public static UserConfigurableObjectType getUserConfigurableObjectType (long key) + throws GeneralException + { + + return (UserConfigurableObjectType) Environment.projectInfoManager.getObjectByKey (UserConfigurableObjectType.class, + key, + null, + null, + true); + + } + + public static boolean hasUserConfigurableObjectType (String userObjType) + { + + return Environment.getUserConfigurableObjectType (userObjType) != null; + + } + + public static ObservableSet getUserConfigurableObjectTypes () + { + + return Environment.userConfigObjTypes; + + } + + public static UserConfigurableObjectType getUserConfigurableObjectType (String userObjType) + { + + for (UserConfigurableObjectType t : Environment.userConfigObjTypes) + { + + if ((t.getUserObjectType () != null) + && + (t.getUserObjectType ().equals (userObjType)) + ) + { + + return t; + + } + + } + + return null; + + } + + public static void removeUserConfigurableObjectType (UserConfigurableObjectType type) + throws GeneralException + { + + Environment.projectInfoManager.deleteObject (type, + true); + + Environment.userConfigObjTypes.remove (type); + + // TODO type.removePropertyChangedListener (Environment.userConfigurableObjectTypeNameListener); + + String id = type.getObjectTypeId (); + + Environment.objectTypeNamesSingular.remove (id); + + Environment.objectTypeNamesPlural.remove (id); + + // Tell all projects about it. + Environment.fireUserProjectEvent (type, + ProjectEvent.Type.userobjecttype, + ProjectEvent.Action.delete, + type); + + } + + // TODO Remove + public static void updateUserConfigurableObjectTypeFieldOrdering (UserConfigurableObjectType type) + throws GeneralException + { + + UserConfigurableObjectTypeDataHandler dh = (UserConfigurableObjectTypeDataHandler) Environment.projectInfoManager.getHandler (type.getClass ()); + + // TODO Remove dh.updateFieldOrdering (type); + + // Tell all projects about it. + Environment.fireUserProjectEvent (type, + ProjectEvent.Type.userobjecttype, + ProjectEvent.Action.changed, + type); + + } + + public static void updateUserConfigurableObjectType (UserConfigurableObjectType type) + throws GeneralException + { + + if (!Environment.userConfigObjTypes.contains (type)) + { + + Environment.addUserConfigurableObjectType (type); + + return; + + } + + Environment.projectInfoManager.saveObject (type); + + String id = type.getObjectTypeId (); + + Environment.objectTypeNamesSingular.put (id, + type.objectTypeNameProperty ()); + + Environment.objectTypeNamesPlural.put (id, + type.objectTypeNamePluralProperty ()); + + // Tell all projects about it. + Environment.fireUserProjectEvent (type, + ProjectEvent.Type.userobjecttype, + ProjectEvent.Action.changed, + type); + + } + + public static void addUserConfigurableObjectType (UserConfigurableObjectType type) + throws GeneralException + { + + if (type.getKey () == null) + { + + Environment.projectInfoManager.saveObject (type); + + } + + Environment.userConfigObjTypes.add (type); + + // Need to now update the column/field state and save again since the field keys are now + // available. + type.updateSortableFieldsState (); + + // Register ourselves as a listener for the name changes. + // TODO type.addPropertyChangedListener (Environment.userConfigurableObjectTypeNameListener); + + String id = type.getObjectTypeId (); + + if (!type.isLegacyObjectType ()) + { + + Environment.objectTypeNamesSingular.put (id, + type.objectTypeNameProperty ()); + + Environment.objectTypeNamesPlural.put (id, + type.objectTypeNamePluralProperty ()); + + } + + // Tell all projects about it. + Environment.fireUserProjectEvent (type, + ProjectEvent.Type.userobjecttype, + ProjectEvent.Action._new, + type); + + } + + public static void removeUserConfigurableObjectTypeField (UserConfigurableObjectTypeField field) + throws GeneralException + { + + Environment.projectInfoManager.deleteObject (field, + true); + + // Tell all projects about it. + Environment.fireUserProjectEvent (field, + ProjectEvent.Type.userobjecttypefield, + ProjectEvent.Action.delete, + field); + + } + + public static void updateUserConfigurableObjectTypeField (UserConfigurableObjectTypeField field) + throws GeneralException + { + + ProjectEvent.Action ev = ProjectEvent.Action.changed; + + if (field.getKey () == null) + { + + ev = ProjectEvent.Action._new; + + } + + Environment.projectInfoManager.saveObject (field); + + // Tell all projects about it. + Environment.fireUserProjectEvent (field, + ProjectEvent.Type.userobjecttypefield, + ev, + field); + + Environment.fireUserProjectEvent (field.getUserConfigurableObjectType (), + ProjectEvent.Type.userobjecttype, + ProjectEvent.Action.changed, + field.getUserConfigurableObjectType ()); + + } + + public static void updateUserObjectTypeNames (Map singular, + Map plural) + throws Exception + { +/* +TODO: IS THIS NEEDED? + UserConfigurableObjectType type = Environment.getUserConfigurableObjectType (Chapter.OBJECT_TYPE); + + // TODO: Fix this nonsense... + if (singular.containsKey (Chapter.OBJECT_TYPE)) + { + + type.setObjectTypeName (singular.get (Chapter.OBJECT_TYPE).getValue ()); + + } + + if (plural.containsKey (Chapter.OBJECT_TYPE)) + { + + type.setObjectTypeNamePlural (plural.get (Chapter.OBJECT_TYPE).getValue ()); + + } + + Environment.updateUserConfigurableObjectType (type); +*/ + Object o = new Object (); + + synchronized (o) + { + + Environment.objectTypeNamesSingular.putAll (singular); + Environment.objectTypeNamesPlural.putAll (plural); + + } + + Environment.saveUserObjectTypeNames (); + + Environment.objectTypeNameChangedProp.setValue (Environment.objectTypeNameChangedProp.getValue () + 1); + + } + + // TODO Move the tag related stuff to a TagManager/Tags or similar. + /** + * Save a tag, this will either create or update it. + * + * @param tag The tag. + * @throws GeneralException If the tag can't be saved. + */ + public static void saveTag (Tag tag) + throws GeneralException + { + + ProjectEvent.Action ev = ProjectEvent.Action.changed; + + if (tag.getKey () == null) + { + + ev = ProjectEvent.Action._new; + + } + + Environment.projectInfoManager.saveObject (tag); + + if (ev.equals (ProjectEvent.Action._new)) + { + + Environment.tags.add (tag); + + } + + // Tell all projects about it. + Environment.fireUserProjectEvent (tag, + ProjectEvent.Type.tag, + ev, + tag); + + } + + /** + * Delete a tag. + * + * @param tag The tag to delete. + * @throws GeneralException If the delete goes wrong. + */ + public static void deleteTag (Tag tag) + throws GeneralException + { + + Environment.projectInfoManager.deleteObject (tag, + true); + + Environment.tags.remove (tag); + + // Tell all projects about it. + Environment.fireUserProjectEvent (tag, + ProjectEvent.Type.tag, + ProjectEvent.Action.delete, + tag); + + } + + /** + * Get a tag by its key. + * + * @param key The key. + * @return The tag. + */ + public static Tag getTagByKey (long key) + { + + Set tags = Environment.getAllTags (); + + for (Tag t : tags) + { + + if (t.getKey () == key) + { + + return t; + + } + + } + + return null; + + } + + /** + * Get a tag by name. + * + * @return The tag, if found. + */ + public static Tag getTagByName (String name) + { + + Set tags = Environment.getAllTags (); + + for (Tag t : tags) + { + + if (t.getName ().equalsIgnoreCase (name)) + { + + return t; + + } + + } + + return null; + + } + + /** + * Get all the tags. + * + * @return The tags. + */ + public static ObservableSet getAllTags () + { + + return Environment.tags; + + } + + /** For a given project, get the project version object by its id. + * + * @param p The project. + * @param id The project version id. + * @param filePassword The password for the project file if it is encrypted. + * @return The project version, if it can be found. + * @throws Exception If something goes wrong. + * TODO: Move the filepassword into the project and expect it there instead. + */ + public static ProjectVersion getProjectVersionById (ProjectInfo p, + String id, + String filePassword) + throws Exception + { + + AbstractProjectViewer pv = Environment.getProjectViewer (p); + + ObjectManager om = null; + + if (pv != null) + { + + // Load up the chapters. + om = pv.getObjectManager (); + + } else { + + // Open the project. + om = Environment.getProjectObjectManager (p, + filePassword); + + om.getProject (); + + } + + ProjectVersionDataHandler pdh = (ProjectVersionDataHandler) om.getHandler (ProjectVersion.class); + + return pdh.getById (id); + + } + + public static boolean openLastEditedProject () + throws Exception + { + + List projs = new ArrayList<> (Environment.getAllProjectInfos ()); + + Collections.sort (projs, + new ProjectInfoSorter ()); + + ProjectInfo p = null; + + if (projs.size () > 0) + { + + p = projs.get (0); + + } + + if (p != null) + { + + // Check to see if the project directory exists. + if (Environment.canOpenProject (p) != null) + { + + return false; + + } + + try + { + + // Get the first. + Environment.openProject (p, + null); + + } catch (Exception e) + { + + Environment.logError ("Unable to open project: " + + p, + e); + + return false; + + } + + return true; + + } + + return false; + + } + +// TODO If this needed? + public static boolean checkCanOpenProject (ProjectInfo p, + boolean showLanding) + { + + StringProperty r = Environment.canOpenProject (p); + + if (r != null) + { + + // Do this first to ensure the error shows above it. + if (showLanding) + { + + // TODO Maybe pass the error as a runnable? On show? + Environment.showAllProjectsViewer (); + + } + + ComponentUtils.showErrorMessage (Environment.getFocusedViewer (), + getUILanguageStringProperty (Arrays.asList (project,actions,openproject,openerrors,general), + p.getName (), + r)); + //"Unable to open {project} " + p.getName () + ", reason:

    " + r); + + return false; + + } + + return true; + + } + + public static boolean hasSynonymsDirectory (String lang) + { + + Path f = Environment.getUserPath (Constants.THESAURUS_DIR).resolve (lang); + + return Files.exists (f) && Files.isDirectory (f); + + } + + @Deprecated + public static String getQuollWriterHelpLink (String url, + String linkText) + { + + if (linkText == null) + { + + return String.format ("%s:%s", + Constants.HELP_PROTOCOL, + url); + + } + + return String.format ("%s", + Constants.HELP_PROTOCOL, + url, + linkText); + + } + + public static String getQuollWriterWebsite () + { + + if (Environment.isDebugModeEnabled ()) + { + + return UserProperties.get (Constants.QUOLL_WRITER_DEBUG_WEBSITE_PROPERTY_NAME); + + } else { + + return UserProperties.get (Constants.QUOLL_WRITER_WEBSITE_PROPERTY_NAME); + + } + + } + + /** + * For a given project get the text/data for the versions of the chapters passed in. This assumes that the + * text is not already available in the chapter object, for example when you only know the id and version. + * + * @param p The project. + * @param chaps The chapters to look up. + * @param filePassword The password for the project file if it is encrypted. + * @return The set of versioned chapters. + * @throws If something goes wrong. + * TODO: Move the filepassword into the project and expect it there instead. + */ + public static Set getVersionedChapters (ProjectInfo p, + Collection chaps, + String filePassword) + throws Exception + { + + AbstractProjectViewer pv = Environment.getProjectViewer (p); + + ObjectManager om = null; + + if (pv != null) + { + + // Load up the chapters. + om = pv.getObjectManager (); + + } else { + + // Open the project. + om = Environment.getProjectObjectManager (p, + filePassword); + + om.getProject (); + + } + + ChapterDataHandler cdh = (ChapterDataHandler) om.getHandler (Chapter.class); + + return cdh.getVersionedChapters (chaps); + + } + + public static ProjectInfo getProjectById (String id, + String projType) + throws Exception + { + + if (id == null) + { + + return null; + + } + + for (ProjectInfo p : Environment.allProjects) + { + + String pid = p.getId (); + + if (pid == null) + { + + continue; + + } + + if (projType != null) + { + + if (!p.getType ().equals (projType)) + { + + continue; + + } + + } + + if (pid.equals (id)) + { + + return p; + + } + + } + + return null; + + } + + public static Path getDefaultSaveProjectDirPath () + { + + try + { + + List pis = new ArrayList<> (Environment.getAllProjectInfos (Project.NORMAL_PROJECT_TYPE)); + + Collections.sort (pis, + new ProjectInfoSorter ()); + + if (pis.size () > 0) + { + + return pis.get (0).getProjectDirectory ().getParent (); + + } + + } catch (Exception e) { + + Environment.logError ("Unable to get last edited project directory", + e); + + } + + return Environment.getUserPath (Constants.DEFAULT_PROJECTS_DIR_NAME); + + } + + /** + * Get an object manager for the specified project and init it. + * + * @param p The project. + * @param filePassword Optional, the password for the project if it is encrypted. + * @returns The object manager for the project. + * @throws An exception if the object manager cannot be inited. + * TODO: Move the filepassword into the project and expect it there instead. + */ + public static ObjectManager getProjectObjectManager (ProjectInfo p, + String filePassword) + throws GeneralException + { + + // TODO Reexamine this... what if the project is already open? + + // Get the username and password. + String username = UserProperties.get (Constants.DB_USERNAME_PROPERTY_NAME); + String password = UserProperties.get (Constants.DB_PASSWORD_PROPERTY_NAME); + + if (p.isNoCredentials ()) + { + + username = null; + password = null; + + } + + ObjectManager dBMan = new ObjectManager (); + dBMan.init (p.getProjectDirectory ().resolve (Constants.PROJECT_DB_FILE_NAME_PREFIX).toFile (), + username, + password, + filePassword, + Environment.getSchemaVersion ()); + + try + { + + dBMan.getProject (); + + } catch (Exception e) { + + dBMan.closeConnectionPool (); + + throw e; + + } + + return dBMan; + + } + + // TODO Move to an ObjectTypeNameManager... singleton + public static Map getObjectTypeNamePlurals () + { + + return new HashMap<> (Environment.objectTypeNamesPlural); + + } + + public static Map getObjectTypeNames () + { + + return new HashMap<> (Environment.objectTypeNamesSingular); + + } + + public static StringProperty getObjectTypeNamePlural (DataObject t) + { + + if (t == null) + { + + return null; + + } + + if (t instanceof UserConfigurableObjectType) + { + + UserConfigurableObjectType ut = (UserConfigurableObjectType) t; + + if (ut.isLegacyObjectType ()) + { + + return Environment.getObjectTypeNamePlural (ut.getUserObjectType ()); + + } + + return ut.objectTypeNamePluralProperty (); + + } + + if ((t instanceof UserConfigurableObject) + && + (!(t instanceof LegacyUserConfigurableObject)) + ) + { + + UserConfigurableObject ut = (UserConfigurableObject) t; + + return ut.objectTypeNamePluralProperty (); + + } + + if (t instanceof Note) + { + + Note n = (Note) t; + + if (n.isEditNeeded ()) + { + + return Environment.getObjectTypeNamePlural ("editneeded" + t.getObjectType ()); + + } + + } + + return Environment.getObjectTypeNamePlural (t.getObjectType ()); + + } + + public static StringProperty getObjectTypeNamePlural (String t) + { + + if (t == null) + { + + return null; + + } + + t = t.toLowerCase (); + + StringProperty v = Environment.objectTypeNamesPlural.get (t); + + if (v == null) + { + + v = getUILanguageStringProperty (objectnames,plural,t); + + } + + return v; + + //return Environment.objectTypeNamesPlural.get (t); + + } + + public static Version getQuollWriterVersion () + { + + return Environment.appVersion; + + } + + public static StringProperty getObjectTypeName (DataObject t) + { + + if (t == null) + { + + return null; + + } + + if (t instanceof UserConfigurableObject) + { + + UserConfigurableObject ut = (UserConfigurableObject) t; + + StringProperty p = ut.objectTypeNameProperty (); + + if (p == null) + { + + if (ut.getUserConfigurableObjectType ().isAssetObjectType ()) + { + + p = getUILanguageStringProperty (objectnames,singular,ut.getUserConfigurableObjectType ().getUserObjectType ()); + + } + + } + + return p; + + } + + if (t instanceof Note) + { + + Note n = (Note) t; + + if (n.isEditNeeded ()) + { + + return Environment.getObjectTypeName ("editneeded" + t.getObjectType ()); + + } + + } + + return Environment.getObjectTypeName (t.getObjectType ()); + + } + + public static StringProperty getObjectTypeName (String t) + { + + if (t == null) + { + + return null; + + } + + t = t.toLowerCase (); + + if (t.equals ("qw")) + { + + return new SimpleStringProperty (Constants.QUOLL_WRITER_NAME); + + } + + StringProperty v = Environment.objectTypeNamesSingular.get (t); + + if (v == null) + { + + v = getUILanguageStringProperty (objectnames,singular,t); + + } + + return v; + + } + + public static DictionaryProvider2 getDefaultDictionaryProvider () + throws Exception + { + + String lang = UserProperties.get (Constants.DEFAULT_SPELL_CHECK_LANGUAGE_PROPERTY_NAME); + + if ((lang == null) + || + ("US English".equals (lang)) + || + ("UK English".equals (lang)) + ) + { + + lang = Constants.ENGLISH; + + } + + return new UserDictionaryProvider (lang); + + } + + public static TargetsData getUserTargets () + { + + return Environment.targets; + + } + + public static void saveUserTargets () + { + + try + { + + Environment.saveUserProperties (); + + } catch (Exception e) { + + Environment.logError ("Unable to update user properties", + e); + + } + + } + + public static TargetsData getDefaultUserTargets () + { + + TargetsData td = new TargetsData (UserProperties.getProperties ().getParentProperties ()); + + return td; + + } + + public static IntegerProperty sessionWordCountProperty () + { + + return Environment.userSession.currentSessionWordCountProperty (); + + } + + public static int getSessionWordCount () + { + + return Environment.userSession.getCurrentSessionWordCount (); + + } + + public static List getSessions (int daysPast) + throws GeneralException + { + + return Environment.projectInfoManager.getSessions (daysPast); + + } + + private static int getPastSessionsWordCount (int daysPast) + throws GeneralException + { + + List sess = Environment.projectInfoManager.getSessions (daysPast); + + int c = 0; + + Session last = null; + + for (Session s : sess) + { + + c += s.getWordCount (); + + last = s; + + } + + c += Environment.userSession.getCurrentSessionWordCount (); + + return c; + + } + + public static Date parseDate (String d) + { + + if (d == null) + { + + return null; + + } + + try + { + + return Environment.dateFormatter.parse (d); + + } catch (Exception e) { + + // Bugger + Environment.logError ("Unable to parse date: " + + d, + e); + + } + + return null; + + } + + // TODO Use a property? + public static DecimalFormat getNumberFormatter () + { + + return Environment.numFormat; + + } + + // TODO Move to UserPropertyHandler, have it register and store them there. + public static com.quollwriter.ui.UserPropertyHandler getUserPropertyHandler (String userProp) + { + + return Environment.userPropertyHandlers.get (userProp); + + } + + public static String getJSONFileAsString (String url) + throws Exception + { + + String data = Utils.getUrlFileAsString (new URL (Environment.getQuollWriterWebsite () + "/" + url)); + + if (data == null) + { + + return null; + + } + + if (data.startsWith (Constants.JSON_RETURN_PREFIX)) + { + + data = data.substring (Constants.JSON_RETURN_PREFIX.length ()); + + } + + return data; + + } + + public static String formatObjectToStringProperties (DataObject d) + { + + Map props = new LinkedHashMap<> (); + + d.fillToStringProperties (props); + + return Environment.formatObjectToStringProperties (props); + + } + + public static String formatObjectToStringProperties (Map props) + { + + try + { + + return JSONEncoder.encode (props, + true, + ""); + + } catch (Exception e) { + + Environment.logError ("Unable to encode properties: " + + props, + e); + + return props + ""; + + } + + } + + public static boolean isFirstUse () + { + + return Environment.isFirstUse; + + } + + public static URL getSupportUrl (String pagePropertyName) + throws Exception + { + + return Environment.getSupportUrl (pagePropertyName, + null); + + } + + public static URL getSupportUrl (String pagePropertyName, + String parms) + throws Exception + { + + String prefName = Constants.SUPPORT_URL_BASE_PROPERTY_NAME; + + if (Environment.isDebugModeEnabled ()) + { + + prefName = Constants.DEBUG_SUPPORT_URL_BASE_PROPERTY_NAME; + + } + + // TODO Change to use String.format. + return new URL (UserProperties.get (prefName) + UserProperties.get (pagePropertyName) + (parms != null ? parms : "")); + + } + + // TODO Move to a better place. + public static String getQuollWriterWebsiteLink (String url, + String linkText) + { + + if (linkText == null) + { + + return String.format ("%s:%s", + Constants.QUOLLWRITER_PROTOCOL, + url); + + } + + return String.format ("%s", + Constants.QUOLLWRITER_PROTOCOL, + url, + linkText); + + } + + public static boolean isInFullScreen () + { + + for (AbstractViewer v : Environment.openViewers) + { + + if (v.isInFullScreenMode ()) + { + + return true; + + } + + } + + return false; + + } + + public static void showAllProjectsViewerIfNoOpenProjects () + { + + // Show the welcome screen if there are no projects open. + if (Environment.openProjects.size () == 0) + { + + Environment.showAllProjectsViewer (); + + } + + } + + /** + * Update the chapters to the versions provided. This creates new chapter objects with new keys but + * keeps the id/version in the chapter. + * + * @param p The project. + * @param projVer The new project version to update to. + * @param chaps The chapters to update. + * @param filePassword The password for the project file if it is encrypted. + * @return The set of versioned chapters. + * @throws If something goes wrong. + * TODO: Move the filepassword into the project and expect it there instead. + */ + public static Set updateToNewVersions (ProjectInfo p, + ProjectVersion projVer, + Collection chaps, + String filePassword) + throws Exception + { + + boolean closePool = false; + + AbstractProjectViewer pv = Environment.getProjectViewer (p); + + ObjectManager om = null; + + if (pv != null) + { + + // Load up the chapters. + om = pv.getObjectManager (); + + } else { + + // Open the project. + om = Environment.getProjectObjectManager (p, + filePassword); + + om.getProject (); + + closePool = true; + + } + + try + { + + ChapterDataHandler cdh = (ChapterDataHandler) om.getHandler (Chapter.class); + + // Check to see if we already have a version with the specified id. + ProjectVersionDataHandler pvdh = (ProjectVersionDataHandler) om.getHandler (ProjectVersion.class); + + if (pvdh.getById (projVer.getId ()) != null) + { + + // Already have this version. + return cdh.getChaptersForVersion (projVer, + om.getProject ().getBook (0), + null, + true); + + } + + return cdh.updateToNewVersions (projVer, + chaps); + + } finally { + + if (closePool) + { + + if (om != null) + { + + om.closeConnectionPool (); + + } + + } + + } + + } + + public static Path getProjectInfoDBFilePath () + { + + Path dir = null; + + String dv = UserProperties.get (Constants.PROJECT_INFO_DB_DIR_PROPERTY_NAME); + + if (dv != null) + { + + dir = Paths.get (dv); + + } else { + + dir = Environment.getUserQuollWriterDirPath (); + + } + + return dir.resolve (Constants.PROJECT_INFO_DB_FILE_NAME_PREFIX); + + } + + public static URL getUpgradeURL (Version version) + throws Exception + { + + String parms = "?version=" + version.getVersion (); + + return Environment.getSupportUrl (Constants.GET_UPGRADE_FILE_PAGE_PROPERTY_NAME, + parms); + + } + + public static Book createTestBook () + throws Exception + { + + Element root = DOM4JUtils.stringAsElement (Utils.getResourceFileAsString (Constants.TEST_BOOK_FILE)); + + String name = DOM4JUtils.attributeValue (root, + XMLConstants.name); + + Book b = new Book (); + + b.setName (name); + + for (Element el : root.elements (Chapter.OBJECT_TYPE)) + { + + name = DOM4JUtils.attributeValue (el, + XMLConstants.name); + + Chapter ch = new Chapter (); + ch.setName (name); + + String text = el.getTextTrim (); + + ch.setText (new StringWithMarkup (text)); + + b.addChapter (ch); + + } + + return b; + + } + + public static Set getWindowIcons () + { + + if (Environment.windowIcons == null) + { + + Environment.windowIcons = new HashSet<> (); + // TODO Improve to use a path. + // TODO Add more icon sizes. + Environment.windowIcons.add (new Image (Utils.getResourceStream (Constants.IMGS_DIR + Constants.WINDOW_ICON_PNG_NAME))); + + } + + return Environment.windowIcons; + + } + + @Deprecated + public static int getIconPixelWidthForType (int type) + { + + return 0; + + } + + @Deprecated + public static javax.swing.ImageIcon getObjectIcon (String ot, + int iconType) + { + + return null; + + } + + @Deprecated + public static javax.swing.ImageIcon getObjectIcon (DataObject d, + int iconType) + { + + return null; + + } + + @Deprecated + public static String getButtonLabel (String l) + { + + return l; + + } + + @Deprecated + public static String getButtonLabel (String l, + String t) + { + + return l; + + } + + @Deprecated + public static String replaceObjectNames (String t) + { + + return t; + + } + + @Deprecated + public static java.awt.Image getTransparentImage () + { + + return null; + + } + + @Deprecated + public static java.awt.image.BufferedImage getNoEditorAvatarImage () + { + + return null; + + } + + @Deprecated + public static javax.swing.ImageIcon getTypingIcon () + { + + return null; + + } + + @Deprecated + public static javax.swing.ImageIcon getLoadingIcon () + { + + return null; + + } + + @Deprecated + public static URL getIconURL (String name, + int type) + { + + return null; + + } + + @Deprecated + public static javax.swing.ImageIcon getIcon (String name, int type) + { + + return null; + + } + + @Deprecated + public static java.awt.image.BufferedImage getImage (String fileName) + { + + return null; + + } + + @Deprecated + public static javax.swing.ImageIcon getAchievementIcon () + { + + return null; + + } + + @Deprecated + public static javax.swing.ImageIcon getWindowIcon () + { + + return null; + + } + + @Deprecated + public static String getWindowNameSuffix () + { + + return null; + + } + + @Deprecated + public static Set getBackgroundImages () + throws Exception + { + + Set ret = new LinkedHashSet<> (); + + Set bgImages = Utils.getResourceListing (Constants.BACKGROUND_THUMB_IMGS_DIR); + + for (String s : bgImages) + { + + ret.add (new com.quollwriter.ui.BackgroundImage (s)); + + } + + return ret; + + } + + @Deprecated + public static java.awt.Image getBackgroundImage (String name) + { + + // TODO Remove Image im = Environment.backgroundImages.get (name); + + java.awt.Image im = null; + + if (im != null) + { + + return im; + + } + + if (name == null) + { + + return null; + + } + + name = Constants.BACKGROUND_IMGS_DIR + name; + + URL url = Environment.class.getResource (name); + + if (url == null) + { + + // Can't find image, log the problem but keep going. + Environment.logError ("Unable to find/load image: " + + name + + ", check images jar to ensure file is present.", + + // Gives a stack trace + new Exception ()); + + return null; + + } + + im = new javax.swing.ImageIcon (url).getImage (); +/* +TODO + Environment.backgroundImages.put (name, + im); +*/ + return im; + + } + + @Deprecated + public static java.awt.Image getBackgroundThumbImage (String name) + { + + if (name == null) + { + + return null; + + } + + name = Constants.BACKGROUND_THUMB_IMGS_DIR + name; + + URL url = Environment.class.getResource (name); + + if (url == null) + { + + // Can't find image, log the problem but keep going. + Environment.logError ("Unable to find/load image: " + + name + + ", check images jar to ensure file is present.", + + // Gives a stack trace + new Exception ()); + + return null; + + } + + return new javax.swing.ImageIcon (url).getImage (); + + } + + public static WarmupProjectViewer getWarmupProjectViewer () + throws Exception + { + + ProjectInfo pi = Environment.allProjects.stream () + .filter (pr -> pr.isWarmupsProject ()) + .findFirst () + .orElse (null); + + if (pi == null) + { + + WarmupProjectViewer v = new WarmupProjectViewer (); + + Project p = new Project (Constants.DEFAULT_WARMUPS_PROJECT_NAME); + p.setType (Project.WARMUPS_PROJECT_TYPE); + + try + { + + v.createViewer (); + + // Put it in the user's directory. + v.newProject (Environment.getUserQuollWriterDirPath (), + p, + null); + + QuollPopup.messageBuilder () + .withViewer (v) + .title (dowarmup,createwarmupsproject,title) + .message (dowarmup,createwarmupsproject,text) + .build (); + + return v; + + } catch (Exception e) { + + Environment.logError ("Unable to create warmups project", + e); + + ComponentUtils.showErrorMessage (getUILanguageStringProperty (dowarmup,createwarmupsproject,actionerror)); + //"Unable to create {Warmups} project please contact Quoll Writer support for assistance."); + + return null; + + } + + } else { + + WarmupProjectViewer v = (WarmupProjectViewer) Environment.openProjects.get (pi); + + if (v != null) + { + + v.toFront (); + v.show (); + return v; + + } + + } + + Environment.openProject (pi, + null); + + WarmupProjectViewer v = (WarmupProjectViewer) Environment.openProjects.get (pi); + + return v; + + } + + public static ProjectInfo getProjectByDirectory (Path dir) + throws Exception + { + + if (dir == null) + { + + return null; + + } + + for (ProjectInfo p : Environment.allProjects) + { + + if (p.getProjectDirectory ().equals (dir)) + { + + return p; + + } + + } + + return null; + + } + + public static Image getBackgroundImage (String name, + double width, + double height) + { + + // TODO Cache the images? + + Image im = null; + + if (im != null) + { + + return im; + + } + + if (name == null) + { + + return null; + + } + + name = Constants.BACKGROUND_IMGS_DIR + name; + + InputStream s = Utils.getResourceStream (name); + + if (s == null) + { + + // Can't find image, log the problem but keep going. + Environment.logError ("Unable to find/load image: " + + name + + ", check images jar to ensure file is present.", + // Gives a stack trace + new Exception ()); + + return null; + + } + + if ((width == -1) + && + (height == -1) + ) + { + + return new Image (s); + + } + + return new Image (s, + width, + height, + false, + true); + + } + + public static Set getAvailableUILanguageStrings () + { + + String l = null; + + Collection ls = null; + + try + { + + l = Utils.getUrlFileAsString (new URL (Environment.getQuollWriterWebsite () + "/" + UserProperties.get (Constants.QUOLL_WRITER_AVAILABLE_UI_LANGUAGE_STRINGS_URL_PROPERTY_NAME) + "?version=" + Environment.getQuollWriterVersion ().toString ())); + + ls = (Collection) JSONDecoder.decode (l); + + } catch (Exception e) { + + // Something gone wrong, so just add our local langs. + + ls = new LinkedHashSet<> (); + + Environment.logError ("Unable to get the ui language strings files url", + e); + + } + + Set ret = new LinkedHashSet<> (); + final Map objs = new LinkedHashMap<> (); + + Set langIds = new LinkedHashSet<> (); + + try + { + + // Add in any user generated ones. + for (UILanguageStrings _ls : UILanguageStringsManager.getAllUserUILanguageStrings (Environment.getQuollWriterVersion ())) + { + + ret.add (_ls.getInfo ()); + + } + + } catch (Exception e) { + + Environment.logError ("Unable to get the user ui language strings", + e); + + } + + // Add our local ones. + Set uistrs = null; + + try + { + + uistrs = UILanguageStringsManager.getAllUILanguageStrings (Environment.getQuollWriterVersion ()); + + } catch (Exception e) { + + Environment.logError ("Unable to get local ui language strings", + e); + + } + + int s = 0; + UILanguageStrings enStrs = null; + + try + { + enStrs = UILanguageStringsManager.getUserUIEnglishLanguageStrings (Environment.getQuollWriterVersion ()); + s = UILanguageStringsManager.getUserUIEnglishLanguageStrings (Environment.getQuollWriterVersion ()).getAllTextValues ().size (); + + } catch (Exception e) { + + Environment.logError ("Unable to get english ui language strings count.", + e); + + } + + for (UILanguageStrings uistr : uistrs) + { + + ret.add (uistr.getInfo ()); + + } + + Iterator iter = ls.iterator (); + + while (iter.hasNext ()) + { + + Map m = (Map) iter.next (); + + String id = (String) m.get ("id"); + + if (!id.equals (UILanguageStrings.ENGLISH_ID)) + { + + int c = 100; + + Object v = m.get ("strcount"); + + if (v != null) + { + + if (v instanceof Number) + { + + c = ((Number) v).intValue (); + + } else { + + try + { + + c = Integer.parseInt (m.get ("strcount").toString ()); + + } catch (Exception e) { + + // Ignore + + } + + } + + } + + Object langName = m.get ("languagename"); + + UILanguageStringsInfo info = new UILanguageStringsInfo (id, + m.get ("nativename").toString (), + (langName != null ? langName.toString () : null), + Utils.getPercent (c, s), + Environment.getQuollWriterVersion (), + false); + + ret.add (info); +/* + objs.put (id, String.format (format, + m.get ("nativename").toString (), + m.get ("languagename"), + Environment.formatNumber (Utils.getPercent (c, s)))); +*/ + } else { + + //objs.put (id, m.get ("nativename").toString ()); + + } + + //langIds.add (id); + + } + + ret.add (enStrs.getInfo ()); + + return ret; + + } + + public static KeyCombination getActionKeyCombination (String action) + { + + if (action.equals (QTextEditor.BOLD_ACTION_NAME)) + { + + return new KeyCodeCombination (KeyCode.B, + KeyCombination.SHORTCUT_DOWN); + + } + + if (action.equals (QTextEditor.ITALIC_ACTION_NAME)) + { + + return new KeyCodeCombination (KeyCode.I, + KeyCombination.SHORTCUT_DOWN); + + } + + if (action.equals (QTextEditor.UNDERLINE_ACTION_NAME)) + { + + return new KeyCodeCombination (KeyCode.U, + KeyCombination.SHORTCUT_DOWN); + + } + + if (action.equals (QTextEditor.CUT_ACTION_NAME)) + { + + return new KeyCodeCombination (KeyCode.X, + KeyCombination.SHORTCUT_DOWN); + + } + + if (action.equals (QTextEditor.COPY_ACTION_NAME)) + { + + return new KeyCodeCombination (KeyCode.C, + KeyCombination.SHORTCUT_DOWN); + + } + + if (action.equals (QTextEditor.PASTE_ACTION_NAME)) + { + + return new KeyCodeCombination (KeyCode.V, + KeyCombination.SHORTCUT_DOWN); + + } + + if (action.equals (QTextEditor.UNDO_ACTION_NAME)) + { + + return new KeyCodeCombination (KeyCode.Z, + KeyCombination.SHORTCUT_DOWN); + + } + + if (action.equals (QTextEditor.REDO_ACTION_NAME)) + { + + return new KeyCodeCombination (KeyCode.Y, + KeyCombination.SHORTCUT_DOWN); + + } + + throw new IllegalArgumentException ("Action: " + action + " is not supported."); + + } + + public static KeyCombination getNewObjectTypeKeyCombination (String objType) + { + + // TODO, make nicer. + if (objType.equals (com.quollwriter.data.Scene.OBJECT_TYPE)) + { + + return new KeyCodeCombination (KeyCode.S, + KeyCombination.SHORTCUT_DOWN, + KeyCombination.SHIFT_DOWN); + + } + + if (objType.equals (OutlineItem.OBJECT_TYPE)) + { + + return new KeyCodeCombination (KeyCode.O, + KeyCombination.SHORTCUT_DOWN, + KeyCombination.SHIFT_DOWN); + + } + + if (objType.equals (Chapter.OBJECT_TYPE)) + { + + return new KeyCodeCombination (KeyCode.H, + KeyCombination.SHORTCUT_DOWN, + KeyCombination.SHIFT_DOWN); + + } + + if (objType.equals (Note.EDIT_NEEDED_OBJECT_TYPE)) + { + + return new KeyCodeCombination (KeyCode.E, + KeyCombination.SHORTCUT_DOWN, + KeyCombination.SHIFT_DOWN); + + } + + if (objType.equals (Note.OBJECT_TYPE)) + { + + return new KeyCodeCombination (KeyCode.N, + KeyCombination.SHORTCUT_DOWN, + KeyCombination.SHIFT_DOWN); + + } + + throw new IllegalArgumentException ("Object type: " + objType + " not supported."); + + } + + public static void showCSSViewer (javafx.stage.Window v, + javafx.scene.Node n) + throws GeneralException + { + + if (Environment.cssViewer == null) + { + Environment.cssViewer = new CSSViewer (v); + Environment.cssViewer.createViewer (); + Environment.cssViewer.init (null); + + Environment.cssViewer.getViewer ().addEventHandler (Viewer.ViewerEvent.CLOSE_EVENT, + (ev -> + { + + Environment.cssViewer = null; + + })); + + } + + UIUtils.forceRunLater (() -> + { + + Environment.cssViewer.requestFocus (); + + }); + + Environment.cssViewer.updateForNode (n); + Environment.cssViewer.toFront (); + + } + + public static void showCSSViewer (AbstractViewer v, + javafx.scene.Node n) + throws GeneralException + { + + if (Environment.cssViewer == null) + { + Environment.cssViewer = new CSSViewer (v); + Environment.cssViewer.createViewer (); + Environment.cssViewer.init (null); + + Environment.cssViewer.getViewer ().addEventHandler (Viewer.ViewerEvent.CLOSE_EVENT, + (ev -> + { + + Environment.cssViewer = null; + + })); + + } + + UIUtils.forceRunLater (() -> + { + + Environment.cssViewer.requestFocus (); + + }); + + Environment.cssViewer.updateForNode (n); + Environment.cssViewer.toFront (); + + } + + public static void setCloseDownAllowed (boolean v) + { + + Environment.closeDownAllowed = v; + + } + + public static String getOSPlatform () + { + + OsCheck.OSType type = OsCheck.getOperatingSystemType (); + + if (type == OsCheck.OSType.Windows) + { + + return "windows"; + + } + + if (type == OsCheck.OSType.MacOS) + { + + return "macos"; + + } + + if (type == OsCheck.OSType.Linux) + { + + return "linux"; + + } + + return null; + + } + + /** + * helper class to check the operating system this Java VM runs in + * + * please keep the notes below as a pseudo-license + * + * http://stackoverflow.com/questions/228477/how-do-i-programmatically-determine-operating-system-in-java + * compare to http://svn.terracotta.org/svn/tc/dso/tags/2.6.4/code/base/common/src/com/tc/util/runtime/Os.java + * http://www.docjar.com/html/api/org/apache/commons/lang/SystemUtils.java.html + */ + public static final class OsCheck { + /** + * types of Operating Systems + */ + public enum OSType { + Windows, MacOS, Linux, Other + }; + + // cached result of OS detection + protected static OSType detectedOS; + + /** + * detect the operating system from the os.name System property and cache + * the result + * + * @returns - the operating system detected + */ + public static OSType getOperatingSystemType() { + if (detectedOS == null) { + String OS = System.getProperty("os.name", "generic").toLowerCase(Locale.ENGLISH); + if ((OS.indexOf("mac") >= 0) || (OS.indexOf("darwin") >= 0)) { + detectedOS = OSType.MacOS; + } else if (OS.indexOf("win") >= 0) { + detectedOS = OSType.Windows; + } else if (OS.indexOf("nux") >= 0) { + detectedOS = OSType.Linux; + } else { + detectedOS = OSType.Other; + } + } + return detectedOS; + } + } +} diff --git a/src/main/java/com/quollwriter/Environment_old.java b/src/main/java/com/quollwriter/Environment_old.java new file mode 100644 index 00000000..6a378ae3 --- /dev/null +++ b/src/main/java/com/quollwriter/Environment_old.java @@ -0,0 +1,6288 @@ +package com.quollwriter; + +import java.awt.Color; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.Image; +import java.awt.Insets; +import java.awt.Font; +import java.awt.KeyboardFocusManager; +import java.awt.image.*; +import java.awt.event.*; + +import java.nio.channels.*; + +import java.beans.*; + +import java.io.*; +import java.nio.charset.*; +import java.nio.file.*; + +import java.net.*; + +import java.security.*; + +import java.text.*; + +import java.util.*; +import java.util.jar.*; +import java.util.logging.*; +import java.util.prefs.*; +import java.util.concurrent.*; + +import javax.swing.*; +import javax.swing.border.*; +import javax.swing.plaf.*; + +import javax.imageio.*; + +import javax.sound.sampled.*; + +import javafx.beans.binding.*; + +import com.gentlyweb.properties.*; + +import com.jgoodies.looks.*; +import com.jgoodies.looks.windows.*; + +import com.quollwriter.data.*; +import com.quollwriter.editors.*; +import com.quollwriter.data.editors.*; +import com.quollwriter.data.comparators.*; + +import com.quollwriter.text.*; + +import com.quollwriter.events.*; + +import com.quollwriter.importer.*; + +import com.quollwriter.synonyms.*; + +import com.quollwriter.text.rules.*; + +import com.quollwriter.db.*; + +import com.quollwriter.ui.*; +import com.quollwriter.ui.components.ActionAdapter; +import com.quollwriter.ui.components.GradientPanel; +import com.quollwriter.ui.components.Header; +import com.quollwriter.ui.components.IconProvider; +import com.quollwriter.ui.components.Runner; + +import com.quollwriter.achievements.*; +import com.quollwriter.achievements.rules.*; + +import com.quollwriter.editors.ui.*; +import com.quollwriter.uistrings.*; + +import static com.quollwriter.LanguageStrings.*; +import static com.quollwriter.uistrings.UILanguageStringsManager.getUIString; +import static com.quollwriter.uistrings.UILanguageStringsManager.getUILanguageStringProperty; + +import javafx.beans.property.*; + +import org.dom4j.*; + +public class Environment_old +{ + + public static String GZIP_EXTENSION = ".gz"; + + private static Landing landingViewer = null; + private static Map openProjects = new HashMap<> (); + private static Set openViewers = new HashSet<> (); + + public static Map defaultObjectProperties = new HashMap (); + + //public static com.gentlyweb.properties.Properties userProperties = new com.gentlyweb.properties.Properties (); + public static PrintStream out = null; + + private static Logger generalLog = null; + private static Logger errorLog = null; + private static Logger sqlLog = null; + + // Get rid of this value once bug reporting is via the web. + public static boolean seenReportBugMessage = false; + + private static Version appVersion = null; + //private static String appVersion = null; + //private static boolean betaVersion = false; + private static int schemaVersion = 0; + private static int projectInfoSchemaVersion = 0; + + private static SimpleDateFormat dateFormatter = null; + private static SimpleDateFormat timeFormatter = null; + + private static boolean debugMode = false; + private static boolean doneVersionCheck = false; + public static boolean isWindows = false; + public static boolean isMac = false; + public static boolean isLinux = false; + private static boolean isFirstUse = false; + + private static List installJarFilesToDelete = new ArrayList (); + + private static Map userPropertyHandlers = new HashMap (); + + private static DecimalFormat numFormat = new DecimalFormat ("###,###"); + private static DecimalFormat floatNumFormat = new DecimalFormat ("###,###.#"); + + private static Map backgroundImages = new HashMap (); + + private static AchievementsManager achievementsManager = null; + + private static Map objectTypeNamesSingular = new HashMap (); + private static Map objectTypeNamesPlural = new HashMap (); + + private static Map synonymProviders = new WeakHashMap (); + //private static DictionaryProvider defaultDictProv = null; + + private static List startupProgressListeners = new ArrayList (); + private static int startupProgress = 0; + + private static FileLock lock = null; + + private static ProjectInfoObjectManager projectInfoManager = null; + + private static Map projectInfoChangedListeners = null; + + private static Map userProjectEventListeners = null; + + // Just used in the maps above as a placeholder for the listeners. + private static final Object listenerFillObj = new Object (); + + private static boolean playSoundOnKeyStroke = false; + private static Clip keyStrokeSound = null; + + private static UserSession userSession = null; + private static TargetsData targets = null; + + private static ScheduledThreadPoolExecutor generalTimer = null; + + private static ProjectTextProperties projectTextProps = null; + private static FullScreenTextProperties fullScreenTextProps = null; + + private static List doOnShutdown = new ArrayList (); + + private static Set userConfigObjTypes = new HashSet (); + + private static PropertyChangedListener userConfigurableObjectTypeNameListener = null; + + private static Set tags = null; + + private static UILanguageStrings uiLanguageStrings = null; + private static UILanguageStrings defaultUILanguageStrings = null; +/* + private static SimpleStringProperty uilangProp = new SimpleStringProperty ("English"); + private static SimpleSetProperty projectsProp = new SimpleSetProperty (); + private static SimpleStringProperty projectInfoFormatProp = new SimpleStringProperty (); +*/ + static + { + + // We use a synchronized weak hash map here so that we don't have to worry about all the + // references since they will be transient compared to the potential length of the service + // running. + + // Where possible listeners should de-register as normal but this just ensure that objects + // that don't have a controlled pre-defined lifecycle (as opposed say to AbstractSideBar) + // won't leak. + //Environment.projectInfoChangedListeners = Collections.synchronizedMap (new WeakHashMap ()); + + //Environment.userProjectEventListeners = Collections.synchronizedMap (new WeakHashMap ()); +/* + try + { + + // Put a wrapper around System.out to ensure that non ascii characters show up correctly when debugging. + Environment.out = new java.io.PrintStream (System.out, true, "utf-8"); + + } catch (Exception e) { + + Environment.out = System.out; + + } +*/ + } + + public class XMLConstants + { + + public static final String projects = "projects"; + public static final String type = "type"; + public static final String name = "name"; + public static final String object = "object"; + public static final String singular = "singular"; + public static final String plural = "plural"; + public static final String file = "file"; + public static final String files = "files"; + public static final String stats = "stats"; + public static final String stat = "stat"; + public static final String id = "id"; + + } +/* + public static SimpleStringProperty projectInfoFormatProperty () + { + + return Environment.projectInfoFormatProp; + + } + + public static SetProperty projectsProperty () + { + + return Environment.projectsProp; + + } + + public static SimpleStringProperty uilangProperty () + { + + return Environment.uilangProp; + + } +*/ +/* + public static void fireProjectInfoChangedEvent (final ProjectInfo proj, + final String changeType) + { + + UIUtils.doActionLater (new ActionListener () + { + + public void actionPerformed (ActionEvent aev) + { + + ProjectInfoChangedEvent ev = new ProjectInfoChangedEvent (proj, + changeType); + + Set ls = null; + + // Get a copy of the current valid listeners. + synchronized (Environment.projectInfoChangedListeners) + { + + ls = new LinkedHashSet (Environment.projectInfoChangedListeners.keySet ()); + + } + + for (ProjectInfoChangedListener l : ls) + { + + l.projectInfoChanged (ev); + + } + + } + + }); + + } +*/ +/* + public static void unregisterViewer (AbstractViewer v, + ActionListener afterUnregister) + { + + Environment.openViewers.remove (v); + + if (v == Environment.landingViewer) + { + + Environment.landingViewer = null; + + } + + if (afterUnregister != null) + { + + UIUtils.doLater (afterUnregister); + + return; + + } + + if (Environment.openViewers.size () == 0) + { + + Environment.closeDown (); + + } + + } +*/ +/* + public static void registerViewer (AbstractViewer v) + { + + Environment.openViewers.add (v); + + } +*/ +/* + public static void removeProjectInfoChangedListener (ProjectInfoChangedListener l) + { + + Environment.projectInfoChangedListeners.remove (l); + + } + + public static void addProjectInfoChangedListener (ProjectInfoChangedListener l) + { + + Environment.projectInfoChangedListeners.put (l, + Environment.listenerFillObj); + + } +*/ +/* + public static void addStartupProgressListener (PropertyChangedListener l) + { + + Environment.startupProgressListeners.add (l); + + } +*/ +/* + private static void fireStartupProgressEvent () + { + + PropertyChangedEvent ev = new PropertyChangedEvent (new Object (), + "progress", + 0, + Environment.startupProgress); + + for (PropertyChangedListener l : Environment.startupProgressListeners) + { + + l.propertyChanged (ev); + + } + + } +*/ +/* + public static void incrStartupProgress () + { + + if (Environment.isStartupComplete ()) + { + + return; + + } + + Environment.startupProgress += 9; + + Environment.fireStartupProgressEvent (); + + } +*/ +/* + public static void startupComplete () + { + + if (Environment.isStartupComplete ()) + { + + return; + + } + + Environment.startupProgress = 100; + + Environment.fireStartupProgressEvent (); + + } +*/ +/* + public static boolean isStartupComplete () + { + + return Environment.startupProgress == 100; + + } +*/ +/* + public static boolean isDistractionFreeModeEnabled () + { + + for (AbstractProjectViewer pv : Environment.openProjects.values ()) + { + + if (pv.isDistractionFreeModeEnabled ()) + { + + return true; + + } + + } + + return false; + + } +*/ +/* + public static AbstractViewer getFocusedViewer () + { + + if (Environment.landingViewer != null) + { + + if (Environment.landingViewer.isFocused ()) + { + + return Environment.landingViewer; + + } + + } + + if (Environment.openViewers.size () == 0) + { + + return null; + + } + + for (AbstractViewer viewer : Environment.openViewers) + { + + if (viewer.isFocused ()) + { + + return viewer; + + } + + } + + // Return the first viewer that is showing. + for (AbstractViewer viewer : Environment.openViewers) + { + + if (viewer.isShowing ()) + { + + return viewer; + + } + + } + + // What the derp... Return the first. + return Environment.openViewers.iterator ().next (); + + } +*/ +/* + public static AbstractProjectViewer getProjectViewer (ProjectInfo p) + { + + return Environment.openProjects.get (p); + + } + + public static AbstractProjectViewer getProjectViewer (Project p) + { + + return Environment.openProjects.get (Environment.getProjectInfo (p)); + + } +*/ +/* + public static void removeSideBarFromAllProjectViewers (String id) + { + + for (AbstractProjectViewer pv : Environment.openProjects.values ()) + { + + pv.removeSideBar (pv.getSideBar (id)); + + } + + } +*/ +/* + public static Book createTestBook () + throws Exception + { + + Element root = JDOMUtils.getStringAsElement (Environment.getResourceFileAsString (Constants.TEST_BOOK_FILE)); + + String name = JDOMUtils.getAttributeValue (root, + XMLConstants.name); + + Book b = new Book (); + + b.setName (name); + + List chEls = JDOMUtils.getChildElements (root, + Chapter.OBJECT_TYPE, + false); + + for (int i = 0; i < chEls.size (); i++) + { + + Element el = (Element) chEls.get (i); + + name = JDOMUtils.getAttributeValue (el, + XMLConstants.name); + + Chapter ch = new Chapter (); + ch.setName (name); + + String text = JDOMUtils.getChildContent (el); + + ch.setText (new StringWithMarkup (text)); + + b.addChapter (ch); + + } + + return b; + + } +*/ + public static boolean areDifferent (Comparable o, + Comparable n) + { + + if ((o == null) && + (n == null)) + { + + return false; + + } + + if ((o != null) && + (n == null)) + { + + return true; + + } + + if ((o == null) && + (n != null)) + { + + return true; + + } + + return o.compareTo (n) != 0; + + } +/* + public static void addInstallJarToDelete (File oldFile, + File newFile) + { + + Environment.installJarFilesToDelete.add (oldFile); + + } +*/ +/* + public static Date zeroTimeFieldsForDate (Date d) + { + + GregorianCalendar gc = new GregorianCalendar (); + gc.setTime (d); + + Environment.zeroTimeFields (gc); + + return gc.getTime (); + + } +*/ + public static void zeroTimeFields (GregorianCalendar gc) + { + + // Zero-out the non date fields. + gc.set (Calendar.HOUR_OF_DAY, + 0); + gc.set (Calendar.MINUTE, + 0); + gc.set (Calendar.SECOND, + 0); + gc.set (Calendar.MILLISECOND, + 0); + + } +/* + public static void updateUserObjectTypeNames (Map singular, + Map plural) + throws Exception + { + + //Map newSingular = new HashMap (); + //newSingular.putAll (Environment.objectTypeNamesSingular); + + //newSingular.putAll (singular); + + //Map newPlural = new HashMap (); + //newPlural.putAll (Environment.objectTypeNamesPlural); + + //newPlural.putAll (plural); + + UserConfigurableObjectType type = Environment.getUserConfigurableObjectType (Chapter.OBJECT_TYPE); + + // TODO: Fix this nonsense... + if (singular.containsKey (Chapter.OBJECT_TYPE)) + { + + type.setObjectTypeName (singular.get (Chapter.OBJECT_TYPE)); + + } + + if (plural.containsKey (Chapter.OBJECT_TYPE)) + { + + type.setObjectTypeNamePlural (plural.get (Chapter.OBJECT_TYPE)); + + } + + Environment.updateUserConfigurableObjectType (type); + + Environment.setUserObjectTypeNames (singular, + plural); + + + } +*/ + public static void setUserObjectTypeNames (Map singular, + Map plural) + throws Exception + { + + Map> t = new HashMap (); + + t.put (LanguageStrings.singular, + singular); + t.put (LanguageStrings.plural, + plural); +/* + IOUtils.writeStringToFile (Environment.getUserObjectTypeNamesFile (), + JSONEncoder.encode (t), + false); + + Environment.loadUserObjectTypeNames (); +*/ + /* + Element root = new Element ("object-names"); + + Map els = new HashMap (); + + for (String ot : singular.keySet ()) + { + + ot = ot.toLowerCase (); + + String s = singular.get (ot); + + Element el = els.get (ot); + + if (el == null) + { + + el = new Element (XMLConstants.object); + + el.setAttribute (XMLConstants.type, + ot); + + els.put (ot, + el); + + root.addContent (el); + + } + + Element sel = new Element (XMLConstants.singular); + + CDATA cd = new CDATA (s); + + sel.addContent (cd); + + el.addContent (sel); + + } + + for (String ot : plural.keySet ()) + { + + ot = ot.toLowerCase (); + + String p = plural.get (ot); + + Element el = els.get (ot); + + if (el == null) + { + + el = new Element (XMLConstants.object); + + el.setAttribute (XMLConstants.type, + ot); + + els.put (ot, + el); + + root.addContent (el); + + } + + Element pel = new Element (XMLConstants.plural); + + CDATA cd = new CDATA (p); + + pel.addContent (cd); + + el.addContent (pel); + + } + + JDOMUtils.writeElementToFile (root, + Environment.getUserObjectTypeNamesFile (), + true); + + // Now force a reload. + Environment.loadObjectTypeNames (root); +*/ + } +/* + public static Map getObjectTypeNamePlurals () + { + + return new HashMap (Environment.objectTypeNamesPlural); + + } + + public static Map getObjectTypeNames () + { + + return new HashMap (Environment.objectTypeNamesSingular); + + } +*/ + public static int getPercent (float t, + float b) + { + + if (b == 0) + { + + return 0; + + } + + return (int) ((t / b) * 100); + + } + +/* + public static String getObjectTypeName (NamedObject n) + { + + if (n == null) + { + + return null; + + } + + return Environment.getObjectTypeName (n.getObjectType ()); + + } + + public static String getObjectTypeNamePlural (NamedObject n) + { + + if (n == null) + { + + return null; + + } + + return Environment.getObjectTypeNamePlural (n.getObjectType ()); + + } +*/ +/* + public static Map getOpenProjects () + { + + return new HashMap (Environment.openProjects); + + } +*/ +/* + public static boolean projectsEqual (Project p1, + Project p2) + { + + if ((p1 == null) || + (p2 == null)) + { + + return false; + + } + + if ((p1.getId () != null) + && + (p2.getId () != null) + ) + { + + return p1.equals (p2); + + } + + if (p1.getName ().equalsIgnoreCase (p2.getName ())) + { + + return true; + + } + + return false; + + } +*/ + public static ProjectInfo getProjectInfo (Project p) + { + + ProjectInfo pi = Environment.getProjectInfo (p.getId (), + p.getType ()); + + if (pi != null) + { + + pi.setFilePassword (p.getFilePassword ()); + + } + + return pi; + + } + + public static ProjectInfo getProjectInfo (String id, + String type) + { + + try + { + + for (ProjectInfo p : Environment.getAllProjectInfos ()) + { + + if (p.getId ().equals (id)) + { + + if (type == null) + { + + return p; + + } + + if (type.equals (p.getType ())) + { + + return p; + + } + + } + + } + + } catch (Exception e) { + + Environment.logError ("Unable to get all project infos to check for project: " + + id + + ", type: " + + type, + e); + + } + + return null; + + } +/* + public static void showLandingIfNoOpenProjects () + { + + // Show the welcome screen if there are no projects open. + if (Environment.getOpenProjects ().size () == 0) + { + + Environment.showLanding (); + + } + + } +*/ +/* + public static File getQuollWriterJarsDir () + { + + String userDir = System.getProperty ("user.dir"); + + if (!userDir.endsWith ("jars")) + { + + userDir += "/jars"; + + } + + File dir = null; + + try + { + + dir = new File (userDir).getCanonicalFile (); + + } catch (Exception e) { + + return null; + + } + + if ((!dir.exists ()) + || + (dir.isFile ()) + ) + { + + return null; + + } + + return dir; + + } +*/ +/* + public static void closeDown () + { + + if (Environment.openViewers.size () > 0) + { + + throw new IllegalStateException ("Cannot closedown when there are open viewers."); + + } + + Environment_old.generalTimer.shutdown (); + + // Go offline from the editors service (if logged in). + EditorsEnvironment.closeDown (); + + Environment.userSession.end (new Date ()); + + try + { + + Environment.projectInfoManager.addSession (Environment.userSession); + + } catch (Exception e) { + + Environment.logError ("Unable to add session", + e); + + } + + Environment.projectInfoManager.closeConnectionPool (); + + if (Environment.doOnShutdown.size () > 0) + { + + for (Runnable r : Environment.doOnShutdown) + { + + try + { + + r.run (); + + } catch (Exception e) { + + Environment.logError ("Unable to run on shutdown.", + e); + + } + + } + + } + + System.exit (0); + + } +*/ + /** + * Inform the environment about a project closing. + * + * If onClose is provided then it is assumed that the caller + * is doing something after the project has been deregistered with the + * environment, for example opening another project or window. + * + * If onClose is not provided (null) then a check is made to see if + * the projects window should be shown or should shutdown occur because + * there are no projects open. + * + * @param pv The project viewer being closed. + * @param onClose The action to take once the project is deregistered. + * @throws Exception If something goes wrong (the list is long). + */ + /* + public static void projectClosed (AbstractProjectViewer pv, + boolean tryShowLanding) + throws Exception + { + + Project proj = pv.getProject (); + + ProjectInfo p = Environment.getProjectInfo (pv.getProject ().getId (), + pv.getProject ().getType ()); + + if (p != null) + { + + Object r = Environment.openProjects.remove (p); + + } + + Environment.userSession.updateCurrentSessionWordCount (pv.getSessionWordCount ()); + + if ((tryShowLanding) + && + (UserProperties.getAsBoolean (Constants.SHOW_PROJECTS_WINDOW_WHEN_NO_OPEN_PROJECTS_PROPERTY_NAME)) + ) + { + + Environment.showLandingIfNoOpenProjects (); + + } + + } +*/ +/* + public static void addOpenedProject (AbstractProjectViewer pv) + throws Exception + { + + final Project proj = pv.getProject (); + + ProjectInfo p = Environment.getProjectInfo (proj.getId (), + proj.getType ()); + + if (p == null) + { + + // We don't have this project, so add it. + p = new ProjectInfo (proj); + + try + { + + Environment.projectInfoManager.saveObject (p, + null); + + } catch (Exception e) { + + Environment.logError ("Unable to add new project info for project: " + + proj, + e); + + } + + } else { + + p.setProject (proj); + + } + + Environment.openProjects.put (p, + pv); + + } +*/ +/* + public static void updateProjectInfo (ProjectInfo pi) + throws GeneralException + { + + Environment.projectInfoManager.saveObject (pi, + null); + + Environment.fireProjectInfoChangedEvent (pi, + ProjectInfoChangedEvent.CHANGED); + + } +*/ +/* + public static void updateProjectInfos (List pis) + throws GeneralException + { + + Environment.projectInfoManager.saveObjects (pis, + null); + + for (ProjectInfo pi : pis) + { + + Environment.fireProjectInfoChangedEvent (pi, + ProjectInfoChangedEvent.CHANGED); + + } + + } +*/ + public static String replaceObjectNames (String t) + { + + if (t == null) + { + + return t; + + } + + StringBuilder b = new StringBuilder (t); + + int start = b.indexOf ("{"); + + while (start > -1) + { + + int end = b.indexOf ("}", + start); + + if (end > -1) + { + + String ot = b.substring (start + 1, + end); + + String newot = ot.toLowerCase (); + + if (newot.equals ("qw")) + { + + newot = Constants.QUOLL_WRITER_NAME; + + } + +/* + boolean an = newot.startsWith ("an "); + + if (an) + { + + newot = newot.substring (3); + + } + + if (newot.endsWith ("s")) + { + + newot = Environment.getObjectTypeNamePlural (newot.substring (0, + newot.length () - 1)); + + } else + { + + newot = Environment.getObjectTypeName (newot); + + } + + if (newot == null) + { + + newot = ot; + + } else + { + + if (Character.isUpperCase (ot.charAt (0))) + { + + newot = Character.toUpperCase (newot.charAt (0)) + newot.substring (1); + + } else + { + + newot = newot.toLowerCase (); + + } + + } + + if (an) + { + + if (TextUtilities.isVowel (newot.toLowerCase ().charAt (0))) + { + + newot = "an " + newot; + + } else { + + newot = "a " + newot; + + } + + } +*/ + b.replace (start, + end + 1, + newot); + + start += newot.length (); + + } else { + + start++; + + } + + start = b.indexOf ("{", + start); + + } + + return b.toString (); + + } + + public static String canOpenProject (Project p) + { + + java.util.List prefix = new ArrayList (); + prefix.add (LanguageStrings.project); + prefix.add (LanguageStrings.actions); + prefix.add (LanguageStrings.openproject); + prefix.add (LanguageStrings.openerrors); + + if (p == null) + { + + return Environment.getUIString (prefix, + LanguageStrings.projectnotexist); + //"{Project} does not exist."; + + } + + if (!p.getProjectDirectory ().exists ()) + { + + return String.format (Environment.getUIString (prefix, + LanguageStrings.projectdirnotexist), + p.getProjectDirectory ()); + //"Cannot find {project} directory " + p.getProjectDirectory () + "."; + + } + + if (!p.getProjectDirectory ().isDirectory ()) + { + + return String.format (Environment.getUIString (prefix, + LanguageStrings.projectdirisfile), + p.getProjectDirectory ()); + //"Path to {project} " + p.getProjectDirectory () + " is a file, but a directory is expected."; + + } + + if (Files.notExists (Utils.getQuollWriterDirFile (p.getProjectDirectory ().toPath ()))) + { + + return String.format (Environment.getUIString (prefix, + LanguageStrings.invalidprojectdir), + p.getProjectDirectory ()); + //"{Project} directory " + p.getProjectDirectory () + " doesn't appear to be a valid Quoll Writer {project}."; + + } + + if ((p.isEditorProject ()) + && + (EditorsEnvironment.getEditorByEmail (p.getForEditor ().getEmail ()) == null) + ) + { + + return String.format (Environment.getUIString (prefix, + LanguageStrings.cantfindeditor), + //"Unable to find {contact}: %s you are editing the {project} for.", + p.getForEditor ().getEmail ()); + + } + + return null; + + } +/* + public static String canOpenProject (ProjectInfo p) + { + + java.util.List prefix = new ArrayList<> (); + prefix.add (LanguageStrings.project); + prefix.add (LanguageStrings.actions); + prefix.add (LanguageStrings.openproject); + prefix.add (LanguageStrings.openerrors); + + if (p == null) + { + + return Environment.getUIString (prefix, + LanguageStrings.projectnotexist); + //return "{Project} does not exist."; + + } + + if (!p.getProjectDirectory ().exists ()) + { + + return String.format (Environment.getUIString (prefix, + LanguageStrings.projectdirnotexist), + p.getProjectDirectory ()); + //return "Cannot find {project} directory " + p.getProjectDirectory () + "."; + + } + + if (!p.getProjectDirectory ().isDirectory ()) + { + + return String.format (Environment.getUIString (prefix, + LanguageStrings.projectdirisfile), + p.getProjectDirectory ()); + //return "Path to {project} " + p.getProjectDirectory () + " is a file, but a directory is expected."; + + } + + if (!Utils.getQuollWriterDirFile (p.getProjectDirectory ()).exists ()) + { + + return String.format (Environment.getUIString (prefix, + LanguageStrings.invalidprojectdir), + p.getProjectDirectory ()); + //return "{Project} directory " + p.getProjectDirectory () + " doesn't appear to be a valid Quoll Writer {project}."; + + } + + if ((p.isEditorProject ()) + && + (p.getForEditor () != null) + && + (EditorsEnvironment.getEditorByEmail (p.getForEditor ().getEmail ()) == null) + ) + { + + return String.format (Environment.getUIString (prefix, + LanguageStrings.cantfindeditor), + //"Unable to find {contact}: %s you are editing the {project} for.", + p.getForEditor ().getEmail ()); + + } + + return null; + + } +*/ +/* + public static boolean isFirstUse () + { + + return Environment.isFirstUse; + + } +*/ +/* + public static boolean checkCanOpenProject (ProjectInfo p, + boolean showLanding) + { + + String r = Environment.canOpenProject (p); + + if (r != null) + { + + // Do this first to ensure the error shows above it. + if (showLanding) + { + + Environment.showLanding (); + + } + + UIUtils.showErrorMessage (null, + String.format (Environment.getUIString (LanguageStrings.project, + LanguageStrings.actions, + LanguageStrings.openproject, + LanguageStrings.openerrors, + LanguageStrings.general), + p.getName (), + r)); + //"Unable to open {project} " + p.getName () + ", reason:

    " + r); + + return false; + + } + + return true; + + } +*/ +/* + public static ProjectInfo getProjectByDirectory (File dir) + throws Exception + { + + if (dir == null) + { + + return null; + + } + + Set projs = Environment.getAllProjectInfos (); + + for (ProjectInfo p : projs) + { + + if (p.getProjectDirectory ().equals (dir)) + { + + return p; + + } + + } + + return null; + + } +*/ + /** For a given project, get the project version object by its id. + * + * @param p The project. + * @param id The project version id. + * @param filePassword The password for the project file if it is encrypted. + * @return The project version, if it can be found. + * @throws Exception If something goes wrong. + * TODO: Move the filepassword into the project and expect it there instead. + */ +/* + public static ProjectVersion getProjectVersionById (ProjectInfo p, + String id, + String filePassword) + throws Exception + { + + AbstractProjectViewer pv = Environment.getProjectViewer (p); + + ObjectManager om = null; + + if (pv != null) + { + + // Load up the chapters. + om = pv.getObjectManager (); + + } else { + + // Open the project. + om = Environment.getProjectObjectManager (p, + filePassword); + + om.getProject (); + + } + + ProjectVersionDataHandler pdh = (ProjectVersionDataHandler) om.getHandler (ProjectVersion.class); + + return pdh.getById (id); + + } +*/ + /** + * Update the chapters to the versions provided. This creates new chapter objects with new keys but + * keeps the id/version in the chapter. + * + * @param p The project. + * @param projVer The new project version to update to. + * @param chaps The chapters to update. + * @param filePassword The password for the project file if it is encrypted. + * @return The set of versioned chapters. + * @throws If something goes wrong. + * TODO: Move the filepassword into the project and expect it there instead. + */ + /* + public static Set updateToNewVersions (ProjectInfo p, + ProjectVersion projVer, + Collection chaps, + String filePassword) + throws Exception + { + + boolean closePool = false; + + AbstractProjectViewer pv = Environment.getProjectViewer (p); + + ObjectManager om = null; + + if (pv != null) + { + + // Load up the chapters. + om = pv.getObjectManager (); + + } else { + + // Open the project. + om = Environment.getProjectObjectManager (p, + filePassword); + + om.getProject (); + + closePool = true; + + } + + try + { + + ChapterDataHandler cdh = (ChapterDataHandler) om.getHandler (Chapter.class); + + // Check to see if we already have a version with the specified id. + ProjectVersionDataHandler pvdh = (ProjectVersionDataHandler) om.getHandler (ProjectVersion.class); + + if (pvdh.getById (projVer.getId ()) != null) + { + + // Already have this version. + return cdh.getChaptersForVersion (projVer, + om.getProject ().getBook (0), + null, + true); + + } + + return cdh.updateToNewVersions (projVer, + chaps); + + } finally { + + if (closePool) + { + + if (om != null) + { + + om.closeConnectionPool (); + + } + + } + + } + + } + */ +/* + public static void restoreBackupForProject (ProjectInfo p, + File restoreFile) + throws Exception + { + + // Get the project db file. + + File dbFile = new File (p.getProjectDirectory (), + Constants.PROJECT_DB_FILE_NAME_PREFIX + Constants.H2_DB_FILE_SUFFIX); + + if (!dbFile.exists ()) + { + + throw new GeneralException ("No project database file found at: " + + dbFile + + ", for project: " + + p); + + } + + File oldDBFile = new File (dbFile.getPath () + ".old"); + + // Rename to .old + // TODO: Investigate using java.nio.file.Files.move instead. + if (!dbFile.renameTo (oldDBFile)) + { + + throw new GeneralException ("Unable to rename project database file to: " + + dbFile.getPath () + ".old" + + ", for project: " + + p); + + } + + try + { + + Utils.extractZipFile (restoreFile, + p.getProjectDirectory ()); + + // See if there is a project db file in there now. + if (!dbFile.exists ()) + { + + throw new GeneralException ("Backup file does not contain a valid project db file"); + + } + + oldDBFile.delete (); + + } catch (Exception e) { + + // Try and rename back. + oldDBFile.renameTo (dbFile); + + throw e; + + } + + } +*/ +/* + public static File createBackupForProject (Project p, + boolean noPrune) + throws Exception + { + + return Environment.createBackupForProject (Environment.getProjectInfo (p), + noPrune); + + } +*/ +/* + public static File createBackupForProject (ProjectInfo p, + boolean noPrune) + throws Exception + { + + boolean closePool = false; + + AbstractProjectViewer pv = Environment.getProjectViewer (p); + + ObjectManager om = null; + Project proj = null; + + if (pv != null) + { + + // Load up the chapters. + om = pv.getObjectManager (); + + proj = pv.getProject (); + + } else { + + if ((p.isEncrypted ()) + && + (p.getFilePassword () == null) + ) + { + + throw new IllegalArgumentException ("The file password must be specified for encrypted projects when the project is not already open."); + + } + + // Open the project. + try + { + + om = Environment.getProjectObjectManager (p, + p.getFilePassword ()); + + proj = om.getProject (); + + } catch (Exception e) { + + // Can't open the project. + if (om != null) + { + + om.closeConnectionPool (); + + } + + throw e; + + } + + proj.setBackupDirectory (p.getBackupDirectory ()); + + closePool = true; + + } + + String backupCount = proj.getProperty (Constants.BACKUPS_TO_KEEP_COUNT_PROPERTY_NAME); + + int count = -1; + + if ((backupCount != null) + && + // Legacy, pre 2.6.5 + (!backupCount.equals ("All")) + ) + { + + try + { + + count = Integer.parseInt (backupCount); + + } catch (Exception e) {} + + } + + try + { + + File f = om.createBackup (proj, + (noPrune ? -1 : count)); + + Environment.fireUserProjectEvent (proj, + ProjectEvent.BACKUPS, + ProjectEvent.NEW, + proj); + + return f; + + } finally { + + if (closePool) + { + + if (om != null) + { + + om.closeConnectionPool (); + + } + + } + + } + + } +*/ + /** + * Get an object manager for the specified project and init it. + * + * @param p The project. + * @param filePassword Optional, the password for the project if it is encrypted. + * @returns The object manager for the project. + * @throws An exception if the object manager cannot be inited. + * TODO: Move the filepassword into the project and expect it there instead. + */ + /* + public static ObjectManager getProjectObjectManager (ProjectInfo p, + String filePassword) + throws GeneralException + { + + // Get the username and password. + String username = Environment.getProperty (Constants.DB_USERNAME_PROPERTY_NAME); + String password = Environment.getProperty (Constants.DB_PASSWORD_PROPERTY_NAME); + + if (p.isNoCredentials ()) + { + + username = null; + password = null; + + } + + ObjectManager dBMan = new ObjectManager (); + dBMan.init (new File (p.getProjectDirectory ().getPath (), Constants.PROJECT_DB_FILE_NAME_PREFIX), + username, + password, + filePassword, + Environment.getSchemaVersion ()); + + try + { + + dBMan.getProject (); + + } catch (Exception e) { + + dBMan.closeConnectionPool (); + + throw e; + + } + + return dBMan; + + } +*/ + /** + * Creates a completely new project with the specified name at the saveDir/name location. + * If the project is to be encrypted then a filePassword should be supplied. The schema will be created. + * + * @param saveDir The directory to save the project to. + * @param name The name of the project. + * @param filePassword Optional, provide if the project is to be encrypted. + * @returns The new project object created. + * @throws An exception if the schema cannot be created or if the save location already exists. + */ + /* + public static Project createNewProject (File saveDir, + String name, + String filePassword) + throws Exception + { + + File projDir = new File (saveDir, + Utils.sanitizeForFilename (name)); + + if (projDir.exists ()) + { + + throw new IllegalArgumentException ("A project with name: " + + name + + " already exists at: " + + projDir); + + } + + Project p = new Project (); + p.setName (name); + + // Get the username and password. + String username = Environment.getProperty (Constants.DB_USERNAME_PROPERTY_NAME); + String password = Environment.getProperty (Constants.DB_PASSWORD_PROPERTY_NAME); + + ObjectManager dBMan = new ObjectManager (); + dBMan.init (new File (projDir.getPath (), Constants.PROJECT_DB_FILE_NAME_PREFIX), + username, + password, + filePassword, + 0); + + // Create a file that indicates that the directory can be deleted. + Utils.createQuollWriterDirFile (projDir); + + p.setProjectDirectory (projDir); + p.setEncrypted (filePassword != null); + + Book b = new Book (p, + p.getName ()); + + p.addBook (b); + + dBMan.saveObject (p, + null); + + dBMan.closeConnectionPool (); + + ProjectInfo pi = new ProjectInfo (p); + + Environment.fireProjectInfoChangedEvent (pi, + ProjectInfoChangedEvent.ADDED); + + return p; + + } +*/ + /** + * Creates the specified project (containing the relevant information) at the saveDir/p.getName () location. + * If the project is to be encrypted then a filePassword should be supplied. The schema will be created. + * + * @param saveDir The directory to save the project to. + * @param p The project. + * @param filePassword Optional, provide if the project is to be encrypted. + * @throws An exception if the schema cannot be created or if a project already exists at the save location. + */ + /* + public static ObjectManager createProject (File saveDir, + Project p, + String filePassword) + throws Exception + { + + File projDir = new File (saveDir, + Utils.sanitizeForFilename (p.getName ())); + + if (projDir.exists ()) + { + + throw new IllegalArgumentException ("A project with name: " + + p.getName () + + " already exists at: " + + projDir); + + } + + // Get the username and password. + String username = Environment.getProperty (Constants.DB_USERNAME_PROPERTY_NAME); + String password = Environment.getProperty (Constants.DB_PASSWORD_PROPERTY_NAME); + + ObjectManager dBMan = new ObjectManager (); + dBMan.init (new File (projDir.getPath (), Constants.PROJECT_DB_FILE_NAME_PREFIX), + username, + password, + filePassword, + 0); + + // Create a file that indicates that the directory can be deleted. + Utils.createQuollWriterDirFile (projDir); + + p.setProjectDirectory (projDir); + p.setEncrypted (filePassword != null); + + dBMan.setProject (p); + + dBMan.saveObject (p, + null); + + ProjectInfo pi = new ProjectInfo (p); + + Environment.projectInfoManager.saveObject (pi, + null); + + Environment.fireProjectInfoChangedEvent (pi, + ProjectInfoChangedEvent.ADDED); + + return dBMan; + + } + */ +/* + public static void openObjectInProject (final ProjectInfo proj, + final DataObject obj) + throws Exception + { + + Environment.openProject (proj, + new ActionListener () + { + + public void actionPerformed (ActionEvent ev) + { + + // View the object. + AbstractProjectViewer viewer = Environment.getProjectViewer (proj); + + viewer.viewObject (obj); + + } + + }); + + } +*/ +/* + public static void openObjectInProject (final Project proj, + final DataObject obj) + throws Exception + { + + final DataObject dobj = obj; + + ProjectInfo p = null; + + try + { + + p = Environment.getProjectInfo (proj); + + } catch (Exception e) { + + throw new GeneralException ("Unable to get project info for project id: " + + proj.getId (), + e); + + } + + if (p == null) + { + + throw new GeneralException ("Unable to get project info for project id: " + + proj.getId ()); + + } + + Environment.openObjectInProject (p, + obj); + + } +*/ +/* + public static void openProjectWithId (String projId, + String projType) + throws Exception + { + + Environment.openProject (projId, + projType, + null); + + } +*/ +/* + public static void openProject (Project p) + throws Exception + { + + Environment.openProject (p, + null); + + } +*/ +/* + public static void openProject (Project p, + ActionListener onProjectOpen) + throws Exception + { + + if (p == null) + { + + return; + + } + + Environment.openProject (p.getId (), + p.getType (), + onProjectOpen); + + } +*/ +/* + public static void openProject (final String projId, + final String projType, + final ActionListener onProjectOpen) + throws Exception + { + + ProjectInfo p = Environment.getProjectInfo (projId, + projType); + + if (p != null) + { + + Environment.openProject (p, + onProjectOpen); + + } + + } +*/ +/* + public static void openProject (final ProjectInfo p) + throws Exception + { + + Environment.openProject (p, + null); + + } +*/ +/* + public static void openProject (final ProjectInfo p, + final ActionListener onProjectOpen) + throws Exception + { + + if (p == null) + { + + return; + + } + + if (p.isOpening ()) + { + + return; + + } + + AbstractProjectViewer pv = (AbstractProjectViewer) Environment.openProjects.get (p); + + if (pv != null) + { + + p.setOpening (false); + + pv.setVisible (true); + pv.setState (java.awt.Frame.NORMAL); + pv.toFront (); + + if (onProjectOpen != null) + { + + onProjectOpen.actionPerformed (new ActionEvent ("open", 1, "open")); + + } + + } else + { + + try + { + + pv = Environment.getProjectViewerForType (p); + + } catch (Exception e) + { + + throw new GeneralException ("Unable to open project: " + + p, + e); + + } + + if (pv == null) + { + + throw new GeneralException ("Unable to open project: " + + p); + + } + + final AbstractProjectViewer fpv = pv; + Environment.incrStartupProgress (); + + java.util.List prefix = new ArrayList (); + prefix.add (LanguageStrings.project); + prefix.add (LanguageStrings.actions); + prefix.add (LanguageStrings.openproject); + prefix.add (LanguageStrings.enterpasswordpopup); + + if (p.isEncrypted ()) + { + + Environment.startupComplete (); + + PasswordInputWindow.create (Environment.getUIString (prefix, + LanguageStrings.title), + //"Enter password", + "lock", + String.format (Environment.getUIString (prefix, + LanguageStrings.text), + p.getName ()), + //"{Project}: " + p.getName () + " is encrypted, please enter the password.", + Environment.getUIString (prefix, + LanguageStrings.buttons, + LanguageStrings.open), + //"Open", + new ValueValidator () + { + + public String isValid (String v) + { + + if ((v == null) + || + (v.trim ().equals ("")) + ) + { + + return Environment.getUIString (prefix, + LanguageStrings.errors, + LanguageStrings.novalue); + //"Please enter the password."; + + } + + try + { + + fpv.openProject (p, + v, + onProjectOpen); + + } catch (Exception e) { + + if (ObjectManager.isDatabaseAlreadyInUseException (e)) + { + + return Environment.getUIString (prefix, + LanguageStrings.errors, + LanguageStrings.projectalreadyopen); + //"Sorry, the {project} appears to already be open in Quoll Writer. Please close all other instances of Quoll Writer first before trying to open the {project}."; + + } + + if (ObjectManager.isEncryptionException (e)) + { + + return Environment.getUIString (prefix, + LanguageStrings.errors, + LanguageStrings.invalidpassword); + //return "Password is not valid."; + + } + + Environment.logError ("Cant open project: " + + p, + e); + + UIUtils.showErrorMessage (null, + Environment.getUIString (prefix, + LanguageStrings.errors, + LanguageStrings.general)); + //"Sorry, the {project} can't be opened. Please contact Quoll Writer support for assistance."); + + return null; + + } finally { + + p.setOpening (false); + + } + + return null; + + } + + }, + new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + // All handled by the validator. + + } + + }, + new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + Environment.showLanding (); + + } + + }).resize (); + + return; + + } + + try + { + + pv.openProject (p, + null, + onProjectOpen); + + } catch (final Exception e) { + + try + { + + pv.close (false, + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + // This prevents QW from going into a shutdown. + // TODO: Make this nicer. + + } + + }); + + } catch (Exception ee) { + + Environment.logError ("Unable to close project after try open, project: " + p, + ee); + + } + + if (ObjectManager.isDatabaseAlreadyInUseException (e)) + { + + UIUtils.showErrorMessage (null, + Environment.getUIString (prefix, + LanguageStrings.errors, + LanguageStrings.projectalreadyopen)); + //"Sorry, the {project} appears to already be open in Quoll Writer. Please close all other instances of Quoll Writer first before trying to open the {project}."); + + return; + + } + + throw e; + + } finally { + + p.setOpening (false); + + } + + Environment.startupComplete (); + + } + + //return pv; + + } +*/ +/* + public static void addToAchievementsManager (AbstractProjectViewer viewer) + { + + try + { + + Environment.achievementsManager.addProjectViewer (viewer); + + } catch (Exception e) { + + Environment.logError ("Unable to init achievements for viewer: " + + viewer, + e); + + } + + } +*/ +/* + public static void removeFromAchievementsManager (AbstractViewer viewer) + { + + try + { + + Environment.achievementsManager.removeViewer (viewer); + + } catch (Exception e) { + + Environment.logError ("Unable to remove from achievements: " + + viewer, + e); + + } + + } +*/ +/* + public static boolean isDebugModeEnabled () + { + + return Environment.debugMode; + + } +*/ +/* + public static void setDebugModeEnabled (boolean v) + { + + Environment.debugMode = v; + + // TODO: Maybe have an EnvironmentEvent? + + } +*/ +/* + public static com.gentlyweb.properties.Properties getDefaultProperties (String objType) + { + + com.gentlyweb.properties.Properties props = (com.gentlyweb.properties.Properties) Environment.defaultObjectProperties.get (objType); + + if (props == null) + { + + // Create some new blank properties. + props = new com.gentlyweb.properties.Properties (); + + Environment.defaultObjectProperties.put (objType, + props); + + } + + if (props.getId () == null) + { + + props.setId ("default-" + objType); + + } + + if (props.getParentProperties () == null) + { + + props.setParentProperties (UserProperties.getProperties ()); + + } + + return props; + + } +*/ + private static void initProjectId (Project envProj, + Project realProj) + { + + if ((envProj.getId () == null) + && + (realProj.getId () != null) + ) + { + + envProj.setId (realProj.getId ()); + + } + + } +/* + public static void setUILanguage (String id) + throws Exception + { + + UILanguageStrings ls = null; + + ls = Environment.getUILanguageStrings (id); + + if (ls == null) + { + + throw new GeneralException ("No language strings found for id: " + + id); + + } + + Environment.uiLanguageStrings = ls; + + UserProperties.set (Constants.USER_UI_LANGUAGE_PROPERTY_NAME, id); + + Environment.loadUserObjectTypeNames (); + + } +*/ +/* + private static File getUILanguageStringsDir () + { + + File d = new File (Environment.getUserQuollWriterDir (), + Constants.UI_LANGUAGES_DIR_NAME); + + if (!d.exists ()) + { + + d.mkdirs (); + + } + + return d; + + } +*/ +/* + private static File getUserUILanguageStringsDir (Version v) + { + + File d = new File (Environment.getUserQuollWriterDir (), + Constants.USER_UI_LANGUAGES_DIR_NAME + "/" + v.toString ()); + + if (!d.exists ()) + { + + d.mkdirs (); + + } + + return d; + + } +*/ +/* + public static UILanguageStrings getDefaultUILanguageStrings () + { + + return Environment.defaultUILanguageStrings; + + } +*/ +/* + public static UILanguageStrings getCurrentUILanguageStrings () + { + + return Environment.uiLanguageStrings; + + } +*/ +/* + public static UILanguageStrings getUILanguageStrings (String id, + Version ver) + throws Exception + { + + if (ver == null) + { + + ver = Environment.getQuollWriterVersion (); + + } + + if (id.startsWith ("user-")) + { + + id = id.substring ("user-".length ()); + + return Environment.getUserUILanguageStrings (ver, + id); + + } + + if (id.equals (UILanguageStrings.ENGLISH_ID)) + { + + return Environment.getDefaultUILanguageStrings (); + + } + + File f = Environment.getUILanguageStringsFile (id); + + if (!f.exists ()) + { + + return null; + + } + + String data = Utils.getFileAsString (f, + StandardCharsets.UTF_8); + + UILanguageStrings s = new UILanguageStrings (data); + + return s; + + } +*/ +/* + public static UILanguageStrings getUILanguageStrings (String id) + throws Exception + { + + return Environment.getUILanguageStrings (id, + Environment.getQuollWriterVersion ()); + + } +*/ +/* + public static Set getAllUserUILanguageStrings (Version qwVer) + throws GeneralException + { + + Set ret = new LinkedHashSet<> (); + + for (UILanguageStrings ls : Environment.getAllUserUILanguageStrings ()) + { + + if (ls.getQuollWriterVersion ().equals (qwVer)) + { + + ret.add (ls); + + } + + } + + return ret; + + } +*/ +/* + public static Set getAllUserUILanguageStrings () + throws GeneralException + { + + Set s = new TreeSet<> (); + + File d = new File (Environment.getUserQuollWriterDir (), + Constants.USER_UI_LANGUAGES_DIR_NAME); + + File[] files = d.listFiles (); + + if (files != null) + { + + for (int i = 0; i < files.length; i++) + { + + File fd = files[i]; + + File[] dfiles = fd.listFiles (); + + if (dfiles != null) + { + + for (int j = 0; j < dfiles.length; j++) + { + + UILanguageStrings ls = new UILanguageStrings (dfiles[j]); + + if (ls.isEnglish ()) + { + + continue; + + } + + s.add (ls); + + } + + } + + } + + } + + return s; + + } +*/ +/* + public static void saveUserUILanguageStrings (UILanguageStrings ls) + throws Exception + { + + File f = Environment.getUserUILanguageStringsFile (ls); + + f.getParentFile ().mkdirs (); + + String json = JSONEncoder.encode (ls.getAsJSON ()); + + Writer out = new BufferedWriter (new OutputStreamWriter (new FileOutputStream (f), + "utf-8")); + + char[] chars = json.toCharArray (); + + out.write (chars, 0, chars.length); + out.flush (); + out.close (); + + } +*/ +/* + public static void downloadUILanguageFile (final String id, + final ActionListener onComplete, + final ActionListener onError) + { + + Environment.schedule (new Runnable () + { + + @Override + public void run () + { + + String lastMod = ""; + + UILanguageStrings ls = null; + + try + { + + ls = Environment.getUILanguageStrings (id); + + } catch (Exception e) { + + Environment.logError ("Unable to get language strings: " + id, + e); + + onError.actionPerformed (new ActionEvent (getUIString (uilanguage,download,actionerror), 0, "error")); + + return; + + } + + if (ls != null) + { + + Date d = ls.getLastModified (); + + if (d == null) + { + + d = ls.getDateCreated (); + + } + + lastMod = d.getTime () + ""; + + } + + String url = Environment.getProperty (Constants.QUOLL_WRITER_GET_UI_LANGUAGE_STRINGS_URL_PROPERTY_NAME); + + url = StringUtils.replaceString (url, + Constants.VERSION_TAG, + Environment.getQuollWriterVersion ().toString ()); + + url = StringUtils.replaceString (url, + Constants.ID_TAG, + id); + + url = StringUtils.replaceString (url, + Constants.LAST_MOD_TAG, + lastMod); + + try + { + + String data = Environment.getUrlFileAsString (new URL (Environment.getQuollWriterWebsite () + "/" + url)); + + if (data.startsWith (Constants.JSON_RETURN_PREFIX)) + { + + data = data.substring (Constants.JSON_RETURN_PREFIX.length ()); + + } + + if (data.trim ().length () == 0) + { + + Environment.logError ("No language strings data available for: " + id + ", " + Environment.getQuollWriterVersion ()); + + onError.actionPerformed (new ActionEvent (getUIString (uilanguage,download,actionerror), 0, "error")); + + return; + + } + + // Will be a collection. + Collection col = null; + + try + { + + col = (Collection) JSONDecoder.decode (data); + + } catch (Exception e) { + + Environment.logError ("Unable to decode language strings data for id: " + id + ", " + Environment.getQuollWriterVersion (), + e); + + onError.actionPerformed (new ActionEvent (getUIString (uilanguage,download,actionerror), 0, "error")); + + return; + + } + + Iterator iter = col.iterator (); + + int updated = 0; + + while (iter.hasNext ()) + { + + Map m = (Map) iter.next (); + + String id = (String) m.get (":id"); + + if (id == null) + { + + throw new GeneralException ("No id found."); + + } + + updated++; + + File f = Environment.getUILanguageStringsFile (id); + + Writer out = new BufferedWriter (new OutputStreamWriter (new FileOutputStream (f), + StandardCharsets.UTF_8)); + + char[] chars = JSONEncoder.encode (m).toCharArray (); + + out.write (chars, 0, chars.length); + out.flush (); + out.close (); + + } + + onComplete.actionPerformed (new ActionEvent (this, updated, "success")); + + } catch (Exception e) { + + Environment.logError ("Unable to get user interface files for: " + id + ", " + Environment.getQuollWriterVersion (), + e); + + onError.actionPerformed (new ActionEvent (getUIString (uilanguage,download,actionerror), 0, "error")); + + } + + } + + }, + 1 * Constants.SEC_IN_MILLIS, + -1); + + } + */ +/* + public static Set getAllUILanguageStrings () + { + + return Environment.getAllUILanguageStrings (null); + + } +*/ +/* + public static Set getAllUILanguageStrings (Version ver) + { + + Set ret = new LinkedHashSet<> (); + + File[] files = Environment.getUILanguageStringsDir ().listFiles (); + + if (files == null) + { + + return ret; + + } + + for (int i = 0; i < files.length; i++) + { + + File f = files[i]; + + if (f.isFile ()) + { + + try + { + + UILanguageStrings ls = new UILanguageStrings (f); + + if (ver != null) + { + + if (!ls.getQuollWriterVersion ().equals (ver)) + { + + continue; + + } + + } + + ret.add (ls); + + } catch (Exception e) { + + Environment.logError ("Unable to create strings from: " + f, + e); + + // Delete the file. + f.delete (); + + } + + } + + } + + return ret; + + } +*/ +/* + public static File getUILanguageStringsFile (String id) + { + + return new File (Environment.getUILanguageStringsDir (), + id); + + } +*/ +/* + public static File getUserUILanguageStringsFile (Version qwVersion, + String id) + { + + if (id.equals (UILanguageStrings.ENGLISH_ID)) + { + + id = id.substring (1); + + } + + return new File (Environment.getUserUILanguageStringsDir (qwVersion), + id); + + } +*/ +/* + public static File getUserUILanguageStringsFile (UILanguageStrings ls) + { + + return Environment.getUserUILanguageStringsFile (ls.getQuollWriterVersion (), + ls.getId ()); + + } +*/ +/* + private static File getUserDefaultProjectPropertiesFile () + { + + return new File (Environment.getUserQuollWriterDir () + "/" + Constants.DEFAULT_PROJECT_PROPERTIES_FILE_NAME); + + } +*/ +/* + public static AbstractProjectViewer getProjectViewerForType (Project p) + throws Exception + { + + AbstractProjectViewer v = null; + + if (p.getType ().equals (Project.NORMAL_PROJECT_TYPE)) + { + + v = new ProjectViewer (); + + } + + if (p.getType ().equals (Project.EDITOR_PROJECT_TYPE)) + { + + v = new EditorProjectViewer (); + + } + + if (p.getType ().equals (Project.WARMUPS_PROJECT_TYPE)) + { + + v = new WarmupsViewer (); + + } + + if (v == null) + { + + throw new GeneralException ("Project type: " + + p.getType () + + " is not supported."); + + } + + v.init (); + + return v; + + } +*/ +/* + public static AbstractProjectViewer getProjectViewerForType (ProjectInfo p) + throws Exception + { + + AbstractProjectViewer v = null; + + if (p.getType ().equals (Project.NORMAL_PROJECT_TYPE)) + { + + v = new ProjectViewer (); + + } + + if (p.getType ().equals (Project.EDITOR_PROJECT_TYPE)) + { + + v = new EditorProjectViewer (); + + } + + if (p.getType ().equals (Project.WARMUPS_PROJECT_TYPE)) + { + + v = new WarmupsViewer (); + + } + + if (v == null) + { + + throw new GeneralException ("Project type: " + + p.getType () + + " is not supported."); + + } + + v.init (); + + return v; + + } +*/ + public static String getButtonLabel (String preferredValue, + String id) + { + + if (preferredValue != null) + { + + return preferredValue; + + } + + return Environment.getButtonLabel (id); + + } + + public static String getButtonLabel (String id) + { + + if (!id.startsWith (Constants.BUTTON_LABEL_ID_PREFIX)) + { + + return id; + + } + + + return Environment.getUIString (LanguageStrings.buttons, + id); + + } +/* + private static void initProjectsDBFromProjectsFile () + throws Exception + { + + File f = new File (Environment.getUserQuollWriterDir () + "/" + Constants.PROJECTS_FILE_NAME); + + if (!f.exists ()) + { + + return; + + } + + // Get the projects file. + Element root = JDOMUtils.getFileAsElement (f, + Environment.GZIP_EXTENSION); + + List pels = JDOMUtils.getChildElements (root, + Project.OBJECT_TYPE, + false); + + for (int i = 0; i < pels.size (); i++) + { + + Element pEl = (Element) pels.get (i); + + Project p = null; + + try + { + + p = new Project (pEl); + + } catch (Exception e) { + + Environment.logError ("Unable to convert element: " + + JDOMUtils.getPath (pEl) + + " to a project", + e); + + continue; + + } + + ProjectInfo pi = null; + + // Try and load the project. + try + { + + pi = new ProjectInfo (p); + + ObjectManager om = Environment.getProjectObjectManager (pi, + null); + + // Now deal with the real project. + pi = new ProjectInfo (om.getProject ()); + + pi.setEncrypted (p.isEncrypted ()); + pi.setNoCredentials (p.isNoCredentials ()); + + om.closeConnectionPool (); + + } catch (Exception e) { + + Environment.logError ("Unable to load project: " + + p, + e); + + } + + if (pi == null) + { + + try + { + + pi = new ProjectInfo (p); + + } catch (Exception e) { + + Environment.logError ("Unable to convert project: " + + p + + " to a project info", + e); + + continue; + + } + + } + + try + { + + Environment.projectInfoManager.saveObject (pi, + null); + + } catch (Exception e) { + + Environment.logError ("Unable to load project: " + + p + + ", path: " + + JDOMUtils.getPath (pEl) + + " into the project db", + e); + + } + + } + + // Remove the projects file (rename for now). + f.renameTo (new File (f.getParentFile (), f.getName () + ".old")); + + } +*/ +/* + public static Set getAllProjectInfos (String limitToType) + throws Exception + { + + Set all = new LinkedHashSet (Environment.projectInfoManager.getObjects (ProjectInfo.class, + null, + null, + true)); + + if (limitToType != null) + { + + Set pis = new LinkedHashSet (); + + for (ProjectInfo p : all) + { + + if (p.getType ().equals (limitToType)) + { + + pis.add (p); + + } + + } + + all = pis; + + } + + return all; + + } +*/ +/* + public static Set getAllProjectInfos () + throws Exception + { + + return Environment.getAllProjectInfos (null); + + } +*/ + public static boolean getPropertyAsBoolean (String name) + { + + return UserProperties.getAsBoolean (name); + //return Environment.userProperties.getPropertyAsBoolean (name); + + } + + public static String getProperty (String name) + { + + return UserProperties.get (name); + //return Environment.userProperties.getProperty (name); + + } + + public static File getUserQuollWriterDir () + { + + File d = new File (System.getProperty ("user.home") + "/" + Constants.QUOLL_WRITER_DIR_NAME + "/"); + + d.mkdirs (); + + return d; + + } +/* + public static File getDictionaryDirectory (String lang) + { + + return new File (Environment.getUserQuollWriterDir ().getPath () + Constants.DICTIONARIES_DIR + lang); + + } + */ +/* + public static File getLogDir () + { + + File d = Environment.getUserFile (Constants.LOGS_DIR); + + d.mkdirs (); + + return d; + + } +*/ +/* + public static File getUserFile (String name) + { + + return new File (Environment.getUserQuollWriterDir ().getPath (), name); + + } + + public static File getUserObjectTypeNamesFile () + { + + return Environment.getUserFile (Constants.OBJECT_TYPE_NAMES_FILE_NAME); + + } +*/ + /** + * No longer used, since properties now stored in projects db. + * This is only used for legacy versions that need to port the properties over + * to the new storage method. + */ + /* + private static File getUserPropertiesFile () + { + + return Environment.getUserFile (Constants.PROPERTIES_FILE_NAME); + + } + */ +/* + public static void saveUserProperties () + throws Exception + { + + Environment.projectInfoManager.setUserProperties (UserProperties.getProperties ());//Environment.userProperties); + + } +*/ +/* + public static void saveDefaultProperties (String objType, + com.gentlyweb.properties.Properties props) + throws Exception + { + + File f = new File (Environment.getUserQuollWriterDir ().getPath () + "/default-" + objType + "-properties.xml"); + + JDOMUtils.writeElementToFile (props.getAsJDOMElement (), + f, + true); + + } +*/ +/* + public static String formatDateTime (Date d) + { + + return Environment.formatDate (d) + " " + Environment.formatTime (d); + + } + + public static String formatDate (Date d) + { + + return Environment.dateFormatter.format (d); + + } + + public static String formatTime (Date d) + { + + return Environment.timeFormatter.format (d); + + } +*/ + public static void init () + throws Exception + { + + Thread.setDefaultUncaughtExceptionHandler (new Thread.UncaughtExceptionHandler () + { + + @Override + public void uncaughtException (Thread t, + Throwable e) + { + + Environment.logError ("Unexcepted error from thread: " + t.getId () + "\n\nStack Trace: \n" + Utils.getStackTrace (e)); + + } + + }); + + // Start the timer, it is done here so that any other code that needs it can start running things + // straightaway. + Environment_old.generalTimer = new ScheduledThreadPoolExecutor (5, + new ThreadFactory () + { + + @Override + public Thread newThread (Runnable r) + { + + Thread t = new Thread (r); + + t.setDaemon (true); + t.setPriority (Thread.MIN_PRIORITY); + t.setName ("Environment-general-" + t.getId ()); + + return t; + + } + + }); +/* + File f = Environment.getErrorLogFile (); + + f.delete (); + + Environment.errorLog = new Logger (); + Environment.errorLog.initLogFile (f); + + f = Environment.getGeneralLogFile (); + + f.delete (); + + Environment.generalLog = new Logger (); + Environment.generalLog.initLogFile (f); + + f = Environment.getSQLLogFile (); + + f.delete (); + + Environment.sqlLog = new Logger (); + Environment.sqlLog.initLogFile (f); + + Environment.incrStartupProgress (); +*/ + Header.defaultPaintLeftColor = UIUtils.getComponentColor (); //UIUtils.getColor ("#516CA3"); + GradientPanel.defaultPaintLeftColor = UIUtils.getComponentColor (); //UIUtils.getColor ("#516CA3"); + Header.defaultPaintRightColor = UIUtils.getComponentColor (); //UIUtils.getColor ("#516CA3"); + GradientPanel.defaultPaintRightColor = UIUtils.getComponentColor (); //UIUtils.getColor ("#516CA3"); + Header.defaultTitleColor = UIUtils.getTitleColor (); + + //Environment.isWindows = System.getProperty ("os.name").startsWith ("Windows"); + + //Environment.isMac = System.getProperty ("os.name").startsWith ("Mac"); + + //Environment.isLinux = System.getProperty ("os.name").startsWith ("Linux"); + + //System.setErr (Environment.nullOut); + //System.setOut (Environment.nullOut); + + // Setup our stream handler for the objectref protocol. + URL.setURLStreamHandlerFactory (new ObjectRefURLStreamHandlerFactory ()); + + //Environment.dateFormatter = new SimpleDateFormat ("d MMM yyyy"); + //Environment.timeFormatter = new SimpleDateFormat ("HH:mm"); + + UIManager.put("SplitPane.background", UIUtils.getComponentColor ()); + UIManager.put("TabbedPane.contentBorderInsets", new Insets(0, 0, 1, 0)); + //UIManager.put("TabbedPane.tabInsets", new Insets(0, 5, 0, 0)); + UIManager.put("Tree.selectionBackground", UIUtils.getColor ("#aaaaaa"));//UIUtils.getTitleColor ()); + UIManager.put("SplitPane.shadow", UIUtils.getColor ("#aaaaaa")); + UIManager.put("Tree.textForeground", UIUtils.getTitleColor ()); + UIManager.put("Tree.rowHeight", 0); + UIManager.put("Tree.leftChildIndent", 6); + UIManager.put("ProgressBar.cellSpacing", 0); + UIManager.put("PopupMenu.background", UIUtils.getComponentColor ()); + UIManager.put("PopupMenu.foreground", UIUtils.getTitleColor ()); + + if (Environment.isWindows) + { + + try + { + + com.jgoodies.looks.Options.setUseSystemFonts (true); + + // TODO ??? UIManager.setLookAndFeel (new WindowsLookAndFeel ()); + + } catch (Exception e) + { + + Environment.logError ("Unable to set laf to: " + + WindowsLookAndFeel.class.getName (), + e); + + } + + } +/* + System.setProperty ("swing.aatext", + "true"); + + System.setProperty ("aawt.useSystemAAFontSettings", + "true"); + + // Remove border around splitpane divider. + UIManager.put ("SplitPaneDivider.border", + BorderFactory.createEmptyBorder ()); + + UIManager.put ("Button.margin", + new java.awt.Insets (3, + 3, + 3, + 3)); +*/ +/* + // Try and get a lock on the file. + File l = new File (Environment.getUserQuollWriterDir (), + "___quollwriter_lock.lock"); + + FileChannel ch = new RandomAccessFile (l, "rw").getChannel (); + + FileLock lock = ch.tryLock (); + + if (lock == null) + { + + throw new OverlappingFileLockException (); + + } + + Environment.lock = lock; + + l.deleteOnExit (); +*/ +/* + Environment.appVersion = new Version (Environment.getResourceFileAsString (Constants.VERSION_FILE).trim ()); + + try + { + + Environment.schemaVersion = Integer.parseInt (Environment.getResourceFileAsString (Constants.SCHEMA_VERSION_FILE).trim ()); + + } catch (Exception e) + { + + // Ignore. + + } +*/ +/* + try + { + + Environment.projectInfoSchemaVersion = Integer.parseInt (Environment.getResourceFileAsString (Constants.PROJECT_INFO_SCHEMA_VERSION_FILE).trim ()); + + } catch (Exception e) + { + + // Ignore. + + } +*/ + com.gentlyweb.properties.Properties sysProps = new com.gentlyweb.properties.Properties (Environment.class.getResourceAsStream (Constants.DEFAULT_PROPERTIES_FILE), + null); + + sysProps.setId ("system"); + + // Temporarily set the user properties to the system properties. + UserProperties.init (sysProps); + //Environment.userProperties = sysProps; + + com.gentlyweb.properties.Properties userProps = sysProps; + + //Environment.incrStartupProgress (); + + //Environment.defaultUILanguageStrings = new UILanguageStrings (Environment.getResourceFileAsString (Constants.DEFAULT_UI_LANGUAGE_STRINGS_FILE)); +/* + Map> errs = Environment.defaultUILanguageStrings.getErrors (); + + for (LanguageStrings.Value v : errs.keySet ()) + { + + System.out.println (v); + System.out.println (errs.get (v)); + System.out.println (); + } +*/ + //Environment.uiLanguageStrings = Environment.defaultUILanguageStrings; + + // Load the default object type names. + // Object type names may be needed when initing the legacy object types. + /* + try + { + + Environment.loadObjectTypeNames (JDOMUtils.getStringAsElement (Environment.getResourceFileAsString (Constants.DEFAULT_OBJECT_TYPE_NAMES_FILE))); + + } catch (Exception e) { + + Environment.logError ("Unable to load default object type names from resource file: " + + Constants.DEFAULT_OBJECT_TYPE_NAMES_FILE); + + } +*/ + // See if this is first use. + //Environment.isFirstUse = (Environment.getProjectInfoSchemaVersion () == 0); +/* + // Get the username and password. + String username = Environment.getProperty (Constants.DB_USERNAME_PROPERTY_NAME); + String password = Environment.getProperty (Constants.DB_PASSWORD_PROPERTY_NAME); + + Environment.projectInfoManager = new ProjectInfoObjectManager (); + + Environment.projectInfoManager.init (Environment.getProjectInfoDBFile (), + username, + password, + null, + Environment.getProjectInfoSchemaVersion ()); + + try + { + + userProps = Environment.projectInfoManager.getUserProperties (); + + } catch (Exception e) { + + Environment.logError ("Unable to load user properties", + e); + + } +*/ +/* + if (userProps == null) + { + + // Check for legacy properties.xml. Pre v2.5. + File pf = Environment.getUserPropertiesFile (); + + if (pf.exists ()) + { + + try + { + + userProps = new com.gentlyweb.properties.Properties (pf, + Constants.GZIP_EXTENSION); + + } catch (Exception e) + { + + Environment.logError ("Unable to load user properties from file: " + + pf, + e); + + } + + pf.delete (); + + } + + } + + if (userProps == null) + { + + userProps = new com.gentlyweb.properties.Properties (); + + } + + if (userProps != sysProps) + { + + userProps.setId ("user"); + + userProps.setParentProperties (sysProps); + + } + + if (userProps == null) + { + + // If this is legacy and we can't load the properties file (is corrupted) then + // use the system properties as the properties. + userProps = sysProps; + + } + + UserProperties.init (userProps); + + // Do a save here so that if we are loading for the first time they will be saved. + try + { + + Environment.saveUserProperties (); + + } catch (Exception e) { + + Environment.logError ("Unable to save user properties", + e); + + } +*/ + // Load the user default, if appropriate. +/* + final String uilangid = UserProperties.get (Constants.USER_UI_LANGUAGE_PROPERTY_NAME); + + if (uilangid != null) + { + + if (!UILanguageStrings.isEnglish (uilangid)) + { + + UILanguageStrings ls = Environment.getUILanguageStrings (uilangid); + + if ((ls == null) + || + // Have we updated QW and need to get newer versions? + ((ls != null) + && + (ls.getQuollWriterVersion ().isNewer (Environment.getQuollWriterVersion ())) + ) + ) + { + + // Something has gone wrong, try and download again. + Environment.downloadUILanguageFile (uilangid, + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + try + { + + Environment.setUILanguage (uilangid); + + } catch (Exception e) { + + Environment.logError ("Unable to set ui language to: " + uilangid, + e); + + UIUtils.showErrorMessage (null, + getUIString (uilanguage,set,downloading,errors,download)); + //"Warning! Quoll Writer has been unable to re-download the User Interface strings for your selected language. There may be multiple reasons for this, such as a connection error to the internet or that the Quoll Writer server is unavailable.

    It is recommended that you either restart Quoll Writer to try again or try downloading the strings from the Options panel.

    In the interim Quoll Writer has fallen back to using English."); + + } + + UIUtils.showMessage (null, + getUIString (uilanguage,set,downloading,redownload,confirmpopup,title), + //"Language strings re-downloaded", + getUIString (uilanguage,set,downloading,redownload,confirmpopup,text), + //"Quoll Writer has re-downloaded the User Interface language strings you are using because they were missing from your local system. In the interim the User Interface has fallen back to using English.

    To return to using your selected language Quoll Writer must be restarted.", + null, + null); + + } + + }, + // On error. + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + UIUtils.showErrorMessage (null, + getUIString (uilanguage,set,downloading,redownload,actionerror)); + //"Warning! Quoll Writer has been unable to re-download the User Interface strings for your selected language. There may be multiple reasons for this, such as a connection error to the internet or that the Quoll Writer server is unavailable.

    It is recommended that you either restart Quoll Writer to try again or try downloading the strings from the Options panel.

    In the interim Quoll Writer has fallen back to using English."); + + } + + }); + + } else { + + Environment.uiLanguageStrings = ls; + + if (!ls.isUser ()) + { + + // See if there is an update to the strings. + Environment.downloadUILanguageFile (uilangid, + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + if (ev.getID () > 0) + { + + try + { + + Environment.setUILanguage (uilangid); + + } catch (Exception e) { + + Environment.logError ("Unable to set ui language to: " + uilangid, + e); + + UIUtils.showErrorMessage (null, + getUIString (uilanguage,set,downloading,update,actionerror)); + //"Warning! Quoll Writer has been unable to update the User Interface strings for your selected language. There may be multiple reasons for this, such as a connection error to the internet or that the Quoll Writer server is unavailable.

    It is recommended that you either restart Quoll Writer to try again or try downloading the strings from the Options panel.

    In the interim Quoll Writer has fallen back to using English."); + + } + + UIUtils.showMessage (null, + getUIString (uilanguage,set,downloading,update,confirmpopup,title), + //"Language strings updated", + getUIString (uilanguage,set,downloading,update,confirmpopup,text), + //"Quoll Writer has updated the User Interface language strings you are using because a new version was available.

    To make full use of the updated strings Quoll Writer must be restarted.", + null, + null); + + } + + } + + }, + // On error. + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + } + + }); + + } + + } + + } + + } +*/ + try + { + + //Environment.loadUserObjectTypeNames (); + + } catch (Exception e) { + + Environment.logError ("Unable to load user object type names.", + e); + + } +/* + // Add a property listener for name changes to user config object types. + Environment.userConfigurableObjectTypeNameListener = new PropertyChangedListener () + { + + @Override + public void propertyChanged (PropertyChangedEvent ev) + { + + UserConfigurableObjectType type = (UserConfigurableObjectType) ev.getSource (); + + String id = type.getObjectTypeId (); + + Environment.objectTypeNamesSingular.put (id, + type.getObjectTypeName ()); + + Environment.objectTypeNamesPlural.put (id, + type.getObjectTypeNamePlural ()); + + } + + }; +*/ + // Init our legacy object types, if needed. + //Environment.projectInfoManager.initLegacyObjectTypes (); + + // The user session needs the properties. + //Environment.userSession = new UserSession (); + + // Override the debug mode. + /* + if (UserProperties.get (Constants.DEBUG_MODE_PROPERTY_NAME) != null) + { + + Environment.setDebugModeEnabled (UserProperties.getAsBoolean (Constants.DEBUG_MODE_PROPERTY_NAME)); + + } +*/ +/* + // Get the system default project properties. + com.gentlyweb.properties.Properties sysDefProjProps = new com.gentlyweb.properties.Properties (Environment.class.getResourceAsStream (Constants.DEFAULT_PROJECT_PROPERTIES_FILE), + UserProperties.getProperties ()); + + File defUserPropsFile = Environment.getUserDefaultProjectPropertiesFile (); + + if (defUserPropsFile.exists ()) + { + + com.gentlyweb.properties.Properties userDefProjProps = new com.gentlyweb.properties.Properties (defUserPropsFile, + Environment.GZIP_EXTENSION); + + userDefProjProps.setParentProperties (sysDefProjProps); + + sysDefProjProps = userDefProjProps; + + } +*/ + // Load the default project properties. + /* + Environment.defaultObjectProperties.put (Project.OBJECT_TYPE, + sysDefProjProps); +*/ + // Create the text properties, they are derived from the user properties so need to be done after + // the user props are inited. + //Environment.projectTextProps = new ProjectTextProperties (); + + //Environment.fullScreenTextProps = new FullScreenTextProperties (); +/* + Environment.playSoundOnKeyStroke = UserProperties.getAsBoolean (Constants.PLAY_SOUND_ON_KEY_STROKE_PROPERTY_NAME); + + String sf = UserProperties.get (Constants.KEY_STROKE_SOUND_FILE_PROPERTY_NAME); + + try + { + + File ksf = null; + + if (sf != null) + { + + ksf = new File (sf); + + } + + Environment.setKeyStrokeSoundFile (ksf); + + } catch (Exception e) + { + + Environment.logError ("Unable to get sound file to play on key stroke using file: " + sf, + e); + + } + + Environment.incrStartupProgress (); +*/ +/* + Environment.userPropertyHandlers.put (Constants.OBJECT_TYPES_PROPERTY_NAME, + new UserPropertyHandler (Constants.OBJECT_TYPES_PROPERTY_NAME, + null)); +*/ +/* + Environment.userPropertyHandlers.put (Constants.NOTE_TYPES_PROPERTY_NAME, + new UserPropertyHandler (Constants.NOTE_TYPES_PROPERTY_NAME, + null, + notetypes,defaulttypes)); + Environment.userPropertyHandlers.put (Constants.PROJECT_STATUSES_PROPERTY_NAME, + new UserPropertyHandler (Constants.PROJECT_STATUSES_PROPERTY_NAME, + null, + allprojects,defaultstatuses)); + Environment.userPropertyHandlers.put (Constants.TAGS_PROPERTY_NAME, + new UserPropertyHandler (Constants.TAGS_PROPERTY_NAME, + null, + // Prevents the compiler whining... + (String[]) null)); +*/ + // Init our properties. + + String v = UserProperties.get (Constants.PROJECT_INFO_FORMAT); + + if (v == null) + { + + v = UserProperties.get (Constants.DEFAULT_PROJECT_INFO_FORMAT); + + } + + //Environment.projectInfoFormatProp.setValue (v); + + try + { + + Prompts.init (); + + } catch (Exception e) + { + + Environment.logError ("Unable to init prompts", + e); + + } + + try + { + + RuleFactory.init (); + + } catch (Exception e) + { + + Environment.logError ("Unable to init rule factory", + e); + + } +/* + try + { + + Environment.achievementsManager = new AchievementsManager (); + + } catch (Exception e) { + + Environment.logError ("Unable to init achievements manager", + e); + + } +*/ + Environment.schedule (() -> + { + + try + { + + Importer.init (); + + } catch (Exception e) { + + Environment.logError ("Unable to init importer", + e); + + } + + }, + 1 * Constants.SEC_IN_MILLIS, + -1); + + //Environment.incrStartupProgress (); +/* +TODO Add this somewhere else? + KeyboardFocusManager.getCurrentKeyboardFocusManager ().addKeyEventPostProcessor (new java.awt.KeyEventPostProcessor () + { + + public boolean postProcessKeyEvent (KeyEvent ev) + { + + if (!(ev.getSource () instanceof JComponent)) + { + + return true; + + } + + final JComponent focused = (JComponent) ev.getSource (); + + Environment.scrollIntoView (focused); + + return true; + + } + }); + */ +/* + try + { + + // Get the user editor properties. + com.gentlyweb.properties.Properties eprops = new com.gentlyweb.properties.Properties (); + + File edPropsFile = Environment.getUserEditorsPropertiesFile (); + + if (edPropsFile.exists ()) + { + + eprops = new com.gentlyweb.properties.Properties (edPropsFile, + Environment.GZIP_EXTENSION); + + } + + eprops.setParentProperties (UserProperties.getProperties ()); + + EditorsEnvironment.init (eprops); + + } catch (Exception e) { + + Environment.logError ("Unable to init editors environment", + e); + + } +*/ + // Pre 2.4. + // See if there is a projects.xml file, if so load the db. + try + { + + //Environment.initProjectsDBFromProjectsFile (); + + } catch (Exception e) { + + Environment.logError ("Unable to init project info from projects file", + e); + + } +/* + if (Environment.isFirstUse) + { + + Environment.isFirstUse = (Environment.getAllProjectInfos ().size () == 0); + + } +*/ + //Environment.targets = new TargetsData (UserProperties.getProperties ()); +/* + Environment.addStartupProgressListener (new PropertyChangedListener () + { + + public void propertyChanged (PropertyChangedEvent ev) + { + + if (Environment.isStartupComplete ()) + { + + Environment.userSession.start (new Date ()); + + // See if we should be doing a warmup exercise. + if (UserProperties.getAsBoolean (Constants.DO_WARMUP_ON_STARTUP_PROPERTY_NAME)) + { + + UIUtils.doLater (new ActionListener () + { + + public void actionPerformed (ActionEvent ev) + { + + AbstractViewer viewer = Environment.getFocusedViewer (); + + if (viewer != null) + { + + viewer.showWarmupPromptSelect (); + + viewer.fireProjectEvent (Warmup.OBJECT_TYPE, + ProjectEvent.WARMUP_ON_STARTUP); + + } + + } + + }); + + } + + Date d = new Date (System.currentTimeMillis () + (Constants.DAY_IN_MILLIS)); + + d = Utils.zeroTimeFields (d); + + Environment.schedule (new Runnable () + { + + @Override + public void run () + { + + try + { + + Environment.projectInfoManager.addSession (Environment.userSession.createSnapshot ()); + + } catch (Exception e) { + + Environment.logError ("Unable to take session snapshot", + e); + + } + + } + + }, + d.getTime (), + // Run every 24 hours. It will drift over the days but not by much. + Constants.DAY_IN_MILLIS); + + Environment.schedule (new Runnable () + { + + @Override + public void run () + { + + java.util.List prefix = new ArrayList (); + prefix.add (LanguageStrings.targets); + prefix.add (LanguageStrings.types); + + Set met = new LinkedHashSet (); + int sessWC = 0; + + try + { + + if (!Environment.targets.isShowMessageWhenSessionTargetReached ()) + { + + return; + + } + + sessWC = Environment.userSession.getCurrentSessionWordCount (); + + // See if the user session has exceeded the session count. + if ((sessWC >= Environment.targets.getMySessionWriting ()) + && + (Environment.userSession.shouldShowSessionTargetReachedPopup ()) + ) + { + + met.add (Environment.getUIString (prefix, + LanguageStrings.session)); + //"Session"); + + Environment.userSession.shownSessionTargetReachedPopup (); + + } + + } catch (Exception e) { + + Environment.logError ("Unable show session target reached popup", + e); + + } + + // Check for the daily count. + // Get all sessions for today. + try + { + + // The order is important here, the userSession check is cheaper + // than the past sessions check since it doesn't require a db lookup. + if ((Environment.userSession.shouldShowDailyTargetReachedPopup ()) + && + (Environment.getPastSessionsWordCount (0) >= Environment.targets.getMyDailyWriting ()) + ) + { + + met.add (Environment.getUIString (prefix, + LanguageStrings.daily)); + //"Daily"); + + Environment.userSession.shownDailyTargetReachedPopup (); + + } + + } catch (Exception e) { + + Environment.logError ("Unable to get past session word counts", + e); + + } + + // Get all sessions for this week. + try + { + + // We perform the cheap check here since it will prevent the extra work + // with the calendar and db from having to be performed. + if (Environment.userSession.shouldShowWeeklyTargetReachedPopup ()) + { + + GregorianCalendar gc = new GregorianCalendar (); + + int fd = gc.getFirstDayOfWeek (); + + int cd = gc.get (Calendar.DAY_OF_WEEK); + + int diff = cd - fd; + + if (diff < 0) + { + + diff += 7; + + } + + if (Environment.getPastSessionsWordCount (diff) >= Environment.targets.getMyWeeklyWriting ()) + { + + met.add (Environment.getUIString (prefix, + LanguageStrings.weekly)); + //"Weekly"); + + Environment.userSession.shownWeeklyTargetReachedPopup (); + + } + + } + + } catch (Exception e) { + + Environment.logError ("Unable to get past session word counts", + e); + + } + + // Get all sessions for this month. + try + { + + // As above, do the cheap check first to prevent the extra work from + // being done. + if (Environment.userSession.shouldShowMonthlyTargetReachedPopup ()) + { + + GregorianCalendar gc = new GregorianCalendar (); + + int fd = gc.getFirstDayOfWeek (); + + int cd = gc.get (Calendar.DAY_OF_MONTH); + + int diff = cd - fd; + + if (Environment.getPastSessionsWordCount (diff) >= Environment.targets.getMyMonthlyWriting ()) + { + + AbstractViewer viewer = Environment.getFocusedViewer (); + + met.add (Environment.getUIString (prefix, + LanguageStrings.monthly)); + //"Monthly"); + + Environment.userSession.shownMonthlyTargetReachedPopup (); + + } + + } + + } catch (Exception e) { + + Environment.logError ("Unable to get past session word counts", + e); + + } + + try + { + + if (met.size () > 0) + { + + StringBuilder b = new StringBuilder (); + + for (String m : met) + { + + b.append (String.format ("
  • %s
  • ", + m)); + + } + + AbstractViewer viewer = Environment.getFocusedViewer (); + + UIUtils.showMessage ((PopupsSupported) viewer, + Environment.getUIString (LanguageStrings.targets, + LanguageStrings.writingtargetreachedpopup, + LanguageStrings.title), + //"Writing targets reached", + String.format (Environment.getUIString (LanguageStrings.targets, + LanguageStrings.writingtargetreachedpopup, + LanguageStrings.text), + //"You have reached the following writing targets by writing %s words.
      %s
    Well done and keep it up!", + Environment.formatNumber (sessWC), + b.toString ()), + UIUtils.defaultLeftCornerShowPopupAt); + + + } + + } catch (Exception e) { + + Environment.logError ("Unable to show writing targets reached popup", + e); + + } + + } + + }, + 5 * Constants.SEC_IN_MILLIS, + 5 * Constants.SEC_IN_MILLIS); + + } + + } + + }); +*/ + } +/* + public static File getUserEditorsPropertiesFile () + { + + return Environment.getUserFile (Constants.EDITORS_PROPERTIES_FILE_NAME); + + } +*/ +/* + public static String getQuollWriterWebsiteLink (String url, + String linkText) + { + + if (linkText == null) + { + + return String.format ("%s:%s", + Constants.QUOLLWRITER_PROTOCOL, + url); + + } + + return String.format ("%s", + Constants.QUOLLWRITER_PROTOCOL, + url, + linkText); + + } +*/ +/* + public static String getWordTypes (String word, + String language) + throws GeneralException + { + + SynonymProvider sp = Environment.getSynonymProvider (language); + + if (sp != null) + { + + return sp.getWordTypes (word); + + } + + return null; + + } +*/ +/* + public static SynonymProvider getSynonymProvider (String language) + throws GeneralException + { + + if (language == null) + { + + language = Constants.ENGLISH; + + } + + if (Environment.isEnglish (language)) + { + + language = Constants.ENGLISH; + + } + + // For now, until we are able to support other languages return null for non-english. + if (!language.equals (Constants.ENGLISH)) + { + + return null; + + } + + SynonymProvider prov = Environment.synonymProviders.get (language.toLowerCase ()); + + if (prov != null) + { + + return prov; + + } + + String synCl = Environment.getProperty (Constants.SYNONYM_PROVIDER_CLASS_PROPERTY_NAME); + + if (synCl != null) + { + + Class c = null; + + try + { + + c = Class.forName (synCl); + + } catch (Exception e) + { + + throw new GeneralException ("Unable to load synonym provider class: " + + synCl + + " specified by property: " + + Constants.SYNONYM_PROVIDER_CLASS_PROPERTY_NAME, + e); + + } + + if (!SynonymProvider.class.isAssignableFrom (c)) + { + + throw new GeneralException ("Expected synonym provider class: " + + synCl + + " specified by property: " + + Constants.SYNONYM_PROVIDER_CLASS_PROPERTY_NAME + + " to implement interface: " + + SynonymProvider.class.getName ()); + + } + + // Create the instance. + try + { + + prov = (SynonymProvider) c.newInstance (); + + } catch (Exception e) + { + + // Record the error but don't barf, it's just a service that isn't available + Environment.logError ("Unable to create new instance of synonym provider class: " + + synCl + + " specified by property: " + + Constants.SYNONYM_PROVIDER_CLASS_PROPERTY_NAME, + e); + + } + + if (!prov.isLanguageSupported (language)) + { + + return null; + + } + + try + { + + + + prov.init (language); + + } catch (Exception e) { + + Environment.logError ("Unable to init synonym provider instance for language: " + + language + + ", class: " + + synCl + + ", specified by property: " + + Constants.SYNONYM_PROVIDER_CLASS_PROPERTY_NAME, + e); + + } + + Environment.synonymProviders.put (language.toLowerCase (), + prov); + + } + + return prov; + + } +*/ + public static boolean isEnglish (String language) + { + + if (language == null) + { + + return false; + + } + + return Constants.ENGLISH.equalsIgnoreCase (language) + || + Constants.BRITISH_ENGLISH.equalsIgnoreCase (language) + || + Constants.US_ENGLISH.equalsIgnoreCase (language); + + } +/* + public static void resetObjectTypeNamesToDefaults () + { + + Environment.objectTypeNamesSingular.clear (); + Environment.objectTypeNamesPlural.clear (); + + // Load the default object type names. +// try +// { + +// Environment.loadObjectTypeNames (JDOMUtils.getStringAsElement (Environment.getResourceFileAsString (Constants.DEFAULT_OBJECT_TYPE_NAMES_FILE))); + +// } catch (Exception e) { + +// Environment.logError ("Unable to load default object type names from resource file: " + +// Constants.DEFAULT_OBJECT_TYPE_NAMES_FILE); + +// } + + File otf = Environment.getUserObjectTypeNamesFile (); + + // Remove the file. + otf.delete (); + + otf = Environment.getUserFile (Constants.LEGACY_OBJECT_TYPE_NAMES_FILE_NAME); + + otf.delete (); + + Environment.loadUserConfigurableObjectTypeNames (); + + // Load the + UserConfigurableObjectType chapterType = Environment.getUserConfigurableObjectType (Chapter.OBJECT_TYPE); + + if (chapterType != null) + { + + Environment.objectTypeNamesPlural.put (Chapter.OBJECT_TYPE, + getUIString (objectnames,plural,Chapter.OBJECT_TYPE)); + Environment.objectTypeNamesSingular.put (Chapter.OBJECT_TYPE, + getUIString (objectnames,singular,Chapter.OBJECT_TYPE)); + + } + + + } +*/ +/* + private static void loadUserObjectTypeNames () + throws Exception + { + + File f = Environment.getUserObjectTypeNamesFile (); + + if (f.exists ()) + { + + // Use this one. + Map t = (Map) JSONDecoder.decode (IOUtils.getFile (f)); + + Environment.objectTypeNamesSingular = (Map) t.get (LanguageStrings.singular); + Environment.objectTypeNamesPlural = (Map) t.get (LanguageStrings.plural); + + } else { + + // Legacy: pre 2.6.2 + f = Environment.getUserFile (Constants.LEGACY_OBJECT_TYPE_NAMES_FILE_NAME); + + if (f.exists ()) + { + + Environment.loadLegacyObjectTypeNames (JDOMUtils.getStringAsElement (IOUtils.getFile (f))); + + Environment.setUserObjectTypeNames (Environment.objectTypeNamesSingular, + Environment.objectTypeNamesPlural); + + f.delete (); + + } + + } + + Environment.loadUserConfigurableObjectTypeNames (); + + } +*/ +/* + private static void loadUserConfigurableObjectTypeNames () + { + + Map singular = Environment.objectTypeNamesSingular; + Map plural = Environment.objectTypeNamesPlural; + + // Load the names from the configurable types. + for (UserConfigurableObjectType t : Environment.userConfigObjTypes) + { + + if (t.getUserObjectType () != null) + { + +// plural.put (t.getUserObjectType (), +// t.getObjectTypeNamePlural ()); + +// singular.put (t.getUserObjectType (), +// t.getObjectTypeName ()); + + } else { + + if (t.isAssetObjectType ()) + { + + plural.put ("asset:" + t.getKey (), + t.getObjectTypeNamePlural ()); + singular.put ("asset:" + t.getKey (), + t.getObjectTypeName ()); + + } + + } + + } + + // TODO: Fix this, special for now. +// UserConfigurableObjectType chapterType = Environment.getUserConfigurableObjectType (Chapter.OBJECT_TYPE); + +// if (chapterType != null) +// { +// +// plural.put (Chapter.OBJECT_TYPE, +// chapterType.getObjectTypeNamePlural ()); +// singular.put (Chapter.OBJECT_TYPE, +// chapterType.getObjectTypeName ()); +// +// } + + } +*/ + private static void loadLegacyObjectTypeNames (Element root) + throws Exception + { +/* + Map singular = new HashMap (); + Map plural = new HashMap (); + + List els = JDOMUtils.getChildElements (root, + XMLConstants.object, + false); + + for (int i = 0; i < els.size (); i++) + { + + Element el = (Element) els.get (i); + + String objType = JDOMUtils.getAttributeValue (el, + XMLConstants.type); + + objType = objType.toLowerCase (); + + String s = JDOMUtils.getChildElementContent (el, + XMLConstants.singular, + false); + + if (!s.equals ("")) + { + + singular.put (objType, + s); + + } + + String p = JDOMUtils.getChildElementContent (el, + XMLConstants.plural, + false); + + if (!p.equals ("")) + { + + plural.put (objType, + p); + + } + + } + */ +/* + // Load the names from the configurable types. + for (UserConfigurableObjectType t : Environment.userConfigObjTypes) + { + + if (t.getUserObjectType () != null) + { + + plural.put (t.getUserObjectType (), + t.getObjectTypeNamePlural ()); + + singular.put (t.getUserObjectType (), + t.getObjectTypeName ()); + + } else { + + if (t.isAssetObjectType ()) + { + + plural.put ("asset:" + t.getKey (), + t.getObjectTypeNamePlural ()); + singular.put ("asset:" + t.getKey (), + t.getObjectTypeName ()); + + } + + } + + } + + // TODO: Fix this, special for now. + UserConfigurableObjectType chapterType = Environment.getUserConfigurableObjectType (Chapter.OBJECT_TYPE); + + if (chapterType != null) + { + + plural.put (Chapter.OBJECT_TYPE, + chapterType.getObjectTypeNamePlural ()); + singular.put (Chapter.OBJECT_TYPE, + chapterType.getObjectTypeName ()); + + } +*/ + + //Environment.objectTypeNamesSingular.putAll (singular); + //Environment.objectTypeNamesPlural.putAll (plural); + + } +/* + public static URL getSupportUrl (String pagePropertyName) + throws Exception + { + + return Environment.getSupportUrl (pagePropertyName, + null); + + } + + public static URL getSupportUrl (String pagePropertyName, + String parms) + throws Exception + { + + String prefName = Constants.SUPPORT_URL_BASE_PROPERTY_NAME; + + if (Environment.isDebugModeEnabled ()) + { + + prefName = Constants.DEBUG_SUPPORT_URL_BASE_PROPERTY_NAME; + + } + + return new URL (Environment.getProperty (prefName) + Environment.getProperty (pagePropertyName) + (parms != null ? parms : "")); + + } +*/ +/* + public static File getGeneralLogFile () + { + + return new File (Environment.getLogDir ().getPath () + "/" + Constants.GENERAL_LOG_NAME); + + } + + public static File getSQLLogFile () + { + + return new File (Environment.getLogDir ().getPath () + "/" + Constants.SQL_LOG_NAME); + + } + + public static File getErrorLogFile () + { + + return new File (Environment.getLogDir ().getPath () + "/" + Constants.ERROR_LOG_NAME); + + } +*/ +/* + public static File getUserDictionaryFile () + { + + return new File (Environment.getUserQuollWriterDir ().getPath () + "/" + Constants.USER_DICTIONARY_FILE_NAME); + + } +*/ +/* + public static Set getBackgroundImages () + throws Exception + { + + Set ret = new LinkedHashSet (); + + Set bgImages = Environment.getResourceListing (Constants.BACKGROUND_THUMB_IMGS_DIR); + + for (String s : bgImages) + { + + ret.add (new BackgroundImage (s)); + + } + + return ret; + + } +*/ +/* + public static Image getBackgroundImage (String name) + { + + Image im = Environment.backgroundImages.get (name); + + if (im != null) + { + + return im; + + } + + if (name == null) + { + + return null; + + } + + name = Constants.BACKGROUND_IMGS_DIR + name; + + URL url = Environment.class.getResource (name); + + if (url == null) + { + + // Can't find image, log the problem but keep going. + Environment.logError ("Unable to find/load image: " + + name + + ", check images jar to ensure file is present.", + + // Gives a stack trace + new Exception ()); + + return null; + + } + + im = new ImageIcon (url).getImage (); + + Environment.backgroundImages.put (name, + im); + + return im; + + } +*/ +/* + public static Image getBackgroundThumbImage (String name) + { + + if (name == null) + { + + return null; + + } + + name = Constants.BACKGROUND_THUMB_IMGS_DIR + name; + + URL url = Environment.class.getResource (name); + + if (url == null) + { + + // Can't find image, log the problem but keep going. + Environment.logError ("Unable to find/load image: " + + name + + ", check images jar to ensure file is present.", + + // Gives a stack trace + new Exception ()); + + return null; + + } + + return new ImageIcon (url).getImage (); + + } +*/ + public static ImageIcon getAchievementIcon () + { + + URL url = Environment.class.getResource (Constants.ACHIEVEMENT_ICON_FILE); + + if (url == null) + { + + // Can't find image, log the problem but keep going. + Environment.logError ("Unable to find/load achievement image: " + + Constants.ACHIEVEMENT_ICON_FILE + + ", check images jar to ensure file is present.", + + // Gives a stack trace + new Exception ()); + + return null; + + } + + return new ImageIcon (url); + + } + + public static ImageIcon getObjectIcon (String ot, + int iconType) + { + + return Environment.getIcon (ot, + iconType); + + } + + public static ImageIcon getObjectIcon (DataObject d, + int iconType) + { + + String ot = d.getObjectType (); + + if (d instanceof Note) + { + + Note n = (Note) d; + + if (n.isEditNeeded ()) + { + + ot = Constants.EDIT_NEEDED_NOTE_ICON_NAME; + + } + + } + + return Environment.getObjectIcon (ot, + iconType); + + } + + public static int getIconPixelWidthForType (int type) + { + + int size = 16; + + if (type == Constants.ICON_EDITOR_MESSAGE) + { + + size = 20; + + } + + if (type == Constants.ICON_TOOLBAR) + { + + size = 20; + + } + + if (type == Constants.ICON_MENU_INNER) + { + + size = 16; + + } + + if (type == Constants.ICON_PANEL_MAIN) + { + + size = 24; + + } + + if (type == Constants.ICON_NOTIFICATION) + { + + size = 24; + + } + + if (type == Constants.ICON_ACHIEVEMENT_HEADER) + { + + size = 24; + + } + + if (type == Constants.ICON_PANEL_ACTION) + { + + size = 20; + + } + + if (type == Constants.ICON_TITLE_ACTION) + { + + size = 24; + + } + + if (type == Constants.ICON_BG_SWATCH) + { + + size = 37; + + } + + if (type == Constants.ICON_FULL_SCREEN_ACTION) + { + + size = 24; + + } + + if (type == Constants.ICON_TITLE) + { + + size = 24; + + } + + if (type == Constants.ICON_EDITORS_LIST_TAB_HEADER) + { + + size = 24; + + } + + return size; + + } + + public static URL getIconURL (String name, + int type) + //boolean large) + { + + if (name == null) + { + + return null; + + } + + if (name.indexOf ('.') == -1) + { + + int size = Environment.getIconPixelWidthForType (type); + + name = Constants.IMGS_DIR + name + size + ".png"; + + } else + { + + name = Constants.IMGS_DIR + name; + + } + + return Environment.class.getResource (name); + + } + + public static ImageIcon getTypingIcon () + { + + URL url = Environment.class.getResource (Constants.IMGS_DIR + Constants.TYPING_GIF_NAME); + + if (url == null) + { + + if (Environment.isDebugModeEnabled ()) + { + + // Can't find image, log the problem but keep going. + Environment.logError ("Unable to find loading image: " + + Constants.TYPING_GIF_NAME + + ", check images jar to ensure file is present.", + // Gives a stack trace + new Exception ()); + + } + + return null; + + } + + try + { + + // Can't use ImageIO here, won't animate only reads first frame. + return new ImageIcon (url); + + } catch (Exception e) { + + Environment.logError ("Unable to find loading image: " + + Constants.TYPING_GIF_NAME, + e); + + } + + return null; + + } + + public static ImageIcon getLoadingIcon () + { + + URL url = Environment.class.getResource (Constants.IMGS_DIR + Constants.LOADING_GIF_NAME); + + if (url == null) + { + + if (Environment.isDebugModeEnabled ()) + { + + // Can't find image, log the problem but keep going. + Environment.logError ("Unable to find loading image: " + + Constants.LOADING_GIF_NAME + + ", check images jar to ensure file is present.", + // Gives a stack trace + new Exception ()); + + } + + return null; + + } + + try + { + + // Can't use ImageIO here, won't animate only reads first frame. + return new ImageIcon (url); + + } catch (Exception e) { + + Environment.logError ("Unable to find loading image: " + + Constants.LOADING_GIF_NAME, + e); + + } + + return null; + + } + + public static ImageIcon getIcon (String name, + int type) + { + + if (name == null) + { + + return null; + + } + + if (name.equals (Constants.LOADING_GIF_NAME)) + { + + return Environment.getLoadingIcon (); + + } + + URL url = Environment.getIconURL (name, + type); + + if (url == null) + { + + if (Environment.isDebugModeEnabled ()) + { + + // Can't find image, log the problem but keep going. + Environment.logError ("Unable to find/load image: " + + name + + ", type: " + type + + ", check images jar to ensure file is present.", + // Gives a stack trace + new Exception ()); + + } + + return null; + + } + + try + { + + return new ImageIcon (ImageIO.read (url)); + + } catch (Exception e) { + + Environment.logError ("Unable to find/load image: " + + name, + e); + + } + + return null; + + } + + public static ImageIcon getWindowIcon () + { + + return new ImageIcon (Environment.class.getResource (Constants.IMGS_DIR + Constants.WINDOW_ICON_PNG_NAME)); + + } + + public static BufferedImage getNoEditorAvatarImage () + { + + return Environment.getImage (Constants.EDITOR_NO_AVATAR_IMAGE); + + } + + public static BufferedImage getImage (String fileName) + { + + try + { + + return ImageIO.read (Environment.class.getResource (fileName)); + + } catch (Exception e) { + + Environment.logError ("Unable to read resource stream for image: " + + fileName, + e); + + } + + return null; + + //return new ImageIcon (Environment.class.getResource (fileName)).getImage (); + + } + + public static Image getTransparentImage () + { + + return new ImageIcon (Environment.class.getResource (Constants.IMGS_DIR + Constants.TRANSPARENT_PNG_NAME)).getImage (); + + } + + public static ImageIcon getLogo () + { + + return new ImageIcon (Environment.class.getResource (Constants.IMGS_DIR + Constants.LOGO_PNG_NAME)); + + } + + public static ImageIcon get3rdPartyLogo (String type) + { + + return new ImageIcon (Environment.class.getResource (Constants.IMGS_DIR + type + "-logo.png")); + + } + + public static String getWindowTitle (String title) + { + + return title + Environment.getWindowNameSuffix (); + + } + + public static String getWindowNameSuffix () + { + + return " - " + Constants.QUOLL_WRITER_NAME; + + } + + public static Color getBorderColor () + { + + return com.quollwriter.ui.UIUtils.getBorderColor (); + + } + + public static Color getInnerBorderColor () + { + + return com.quollwriter.ui.UIUtils.getColor ("#CCCCCC"); + + } +/* + public static InputStream getResourceStream (String name) + { + + return Environment.class.getResourceAsStream (name); + + } +*/ +/* + public static String getResourceFileAsString (String name) + throws GeneralException + { + + InputStream is = Environment.getResourceStream (name); + + if (is == null) + { + + return null; + + } + + StringBuilder b = new StringBuilder (); + + BufferedReader r = null; + + try + { + + r = new BufferedReader (new InputStreamReader (is, "utf-8")); + + String line = r.readLine (); + + while (line != null) + { + + b.append (line); + b.append ('\n'); + + line = r.readLine (); + + } + + } catch (Exception e) + { + + throw new GeneralException ("Unable to read from resource: " + + name, + e); + + } finally + { + + // Oh how I hate this... + try + { + + if (r != null) + { + + r.close (); + + } + + } catch (Exception e) + { + + // Ignore... What could we do otherwise? + + } + + } + + return b.toString (); + + } +*/ +/* + public static File getProjectInfoDBFile () + { + + File dir = null; + + String dv = UserProperties.get (Constants.PROJECT_INFO_DB_DIR_PROPERTY_NAME); + + if (dv != null) + { + + dir = new File (dv); + + } else { + + dir = Environment.getUserQuollWriterDir (); + + } + + return new File (dir, Constants.PROJECT_INFO_DB_FILE_NAME_PREFIX); + + } +*/ +/* + public static int getProjectInfoSchemaVersion () + { + + File f = new File (Environment.getProjectInfoDBFile ().getPath () + Constants.H2_DB_FILE_SUFFIX); + + // See if we already have a project info db. + if (f.exists ()) + { + + return Environment.projectInfoSchemaVersion; + + } + + // No file, so need to create the schema. + return 0; + + } +*/ +/* + public static int getSchemaVersion () + { + + return Environment.schemaVersion; + + } +*/ +/* + public static File writeStreamToTempFile (InputStream in) + throws IOException + { + + File f = File.createTempFile ("___" + Constants.QUOLL_WRITER_DIR_NAME + System.currentTimeMillis (), + null); + + BufferedOutputStream bout = new BufferedOutputStream (new FileOutputStream (f)); + + IOUtils.streamTo (new BufferedInputStream (in), + bout, + 4096); + + bout.flush (); + bout.close (); + + return f; + + } +*/ +/* + public static URL getUpgradeURL (Version version) + throws Exception + { + + String parms = "?version=" + version.getVersion (); + + return Environment.getSupportUrl (Constants.GET_UPGRADE_FILE_PAGE_PROPERTY_NAME, + parms); + + } +*/ +/* + private static URL getNewsAndVersionCheckURL () + throws Exception + { + + String parms = "?"; + + if (UserProperties.getAsBoolean (Constants.OPTIN_TO_BETA_VERSIONS_PROPERTY_NAME)) + { + + parms += "beta=true&"; + + } + + String lastVersionCheckTime = UserProperties.get (Constants.LAST_VERSION_CHECK_TIME_PROPERTY_NAME); + + if (lastVersionCheckTime != null) + { + + parms += "since=" + lastVersionCheckTime; + + } + + return Environment.getSupportUrl (Constants.GET_LATEST_VERSION_PAGE_PROPERTY_NAME, + parms); + + } +*/ +/* + public static void doNewsAndVersionCheck (final AbstractViewer viewer) + { + + if (Environment_old.doneVersionCheck) + { + + return; + + } + + String updaterClass = UserProperties.get (Constants.UPDATER_CLASS_PROPERTY_NAME, + null); + + Class updaterCl = null; + + try + { + + updaterCl = Class.forName (updaterClass); + + if (!QuollWriterUpdater.class.isAssignableFrom (updaterCl)) + { + + Environment.logError (String.format ("Expected class: %s, given by property: %s to be an instance of: %s", + updaterClass, + Constants.UPDATER_CLASS_PROPERTY_NAME, + QuollWriterUpdater.class.getName ())); + + updaterCl = null; + + } + + } catch (Exception e) { + + Environment.logError (String.format ("Unable to load class: %s given by property: %s", + updaterClass, + Constants.UPDATER_CLASS_PROPERTY_NAME), + e); + + } + + QuollWriterUpdater updater = null; + + if (updaterCl != null) + { + + try + { + + updater = (QuollWriterUpdater) updaterCl.newInstance (); + + } catch (Exception e) { + + Environment.logError (String.format ("Unable to create new instance of: %s, given by property: %s", + updaterClass, + Constants.UPDATER_CLASS_PROPERTY_NAME), + e); + + } + + } + + if ((UserProperties.getAsBoolean (Constants.DO_AUTO_UPDATE_CHECK_PROPERTY_NAME)) + && + (updater != null) + ) + { + + Environment_old.doneVersionCheck = true; + + final QuollWriterUpdater _updater = updater; + + Runner r = new Runner () + { + + public void run () + { + + try + { + + _updater.doUpdate (viewer); + + } catch (Exception e) + { + + Environment.logError ("Unable to perform update check", + e); + + } + + } + + }; + + Thread t = new Thread (r); + + t.setDaemon (true); + t.setPriority (Thread.MIN_PRIORITY); + + t.start (); + + } + + } +*/ +/* + public static String formatNumber (int i) + { + + return Environment_old.numFormat.format (i); + + } + + public static String formatNumber (long i) + { + + return Environment_old.numFormat.format (i); + + } + + public static String formatNumber (float f) + { + + return Environment_old.floatNumFormat.format (f); + + } + + public static String formatNumber (double f) + { + + return Environment_old.floatNumFormat.format (f); + + } +*/ +/* + public static String formatNumber (Number n) + { + + if (n == null) + { + + return "N/A"; + + } + + if (n instanceof Float) + { + + return Environment.floatNumFormat.format (n); + + } + + return Environment.numFormat.format (n); + + } +*/ +/* + public static Map> getAchievedAchievementIds (AbstractViewer viewer) + { + + return Environment.achievementsManager.getAchievedAchievementIds (viewer); + + } +*/ +/* + public static void removeAchievedAchievement (String achievementType, + String id, + AbstractViewer viewer) + throws Exception + { + + Environment.achievementsManager.removeAchievedAchievement (achievementType, + id, + viewer); + + } +*/ +/* + public static void showAchievement (AchievementRule ar) + { + + AbstractViewer v = Environment.getFocusedViewer (); + + if (v != null) + { + + v.showAchievement (ar); + + } + + } +*/ +/* + public static void eventOccurred (ProjectEvent ev) + { + + Environment.achievementsManager.eventOccurred (ev); + + } +*/ +/* + public static Set getPerProjectAchievementRules () + { + + return Environment.achievementsManager.getPerProjectRules (); + + } +*/ +/* + public static Set getUserAchievementRules () + { + + return Environment.achievementsManager.getUserRules (); + + } +*/ +/* + public static AchievementsManager getAchievementsManager () + { + + return Environment.achievementsManager; + + } +*/ + public static AbstractProjectViewer getFullScreenProjectViewer () + { + + for (AbstractProjectViewer v : Environment_old.openProjects.values ()) + { + + if (v.isInFullScreen ()) + { + + return v; + + } + + } + + return null; + + } + + public static boolean isInFullScreen () + { + + return Environment_old.getFullScreenProjectViewer () != null; + + } + + public static void doForOpenProjects (final String projectType, + final ProjectViewerAction act) + { + + UIUtils.doLater (new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + for (ProjectInfo p : Environment_old.openProjects.keySet ()) + { + + AbstractProjectViewer pv = Environment_old.openProjects.get (p); + + if ((projectType == null) + || + (p.getType ().equals (projectType)) + ) + { + + act.doAction (pv); + + } + + } + + } + + }); + + } + + public static void doForOpenProjectViewers (final Class projectViewerType, + final ProjectViewerAction act) + { + + UIUtils.doLater (new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + for (ProjectInfo p : Environment_old.openProjects.keySet ()) + { + + AbstractProjectViewer pv = Environment_old.openProjects.get (p); + + if ((projectViewerType == null) + || + (projectViewerType.isAssignableFrom (pv.getClass ())) + ) + { + + act.doAction (pv); + + } + + } + + } + + }); + + } +/* + public static String formatObjectToStringProperties (DataObject d) + { + + Map props = new LinkedHashMap (); + + d.fillToStringProperties (props); + + return Environment.formatObjectToStringProperties (props); + + } +*/ +/* + public static String formatObjectToStringProperties (Map props) + { + + try + { + + return JSONEncoder.encode (props, + true, + ""); + + } catch (Exception e) { + + Environment.logError ("Unable to encode properties: " + + props, + e); + + return props + ""; + + } + + } +*/ +/* + public static void relaunchLanding () + throws Exception + { + + if (Environment_old.landingViewer != null) + { + + Environment_old.landingViewer.removeProjectEventListener (Environment.achievementsManager); + + Environment_old.landingViewer.close (false, + null); + + Environment_old.landingViewer = null; + + } + + Environment_old.showLanding (); + + } +*/ +/* + public static Landing getLanding () + { + + return Environment_old.landingViewer; + + } +*/ +/* + public static void showLanding () + { + + if (Environment_old.landingViewer == null) + { + + try + { + + Environment_old.landingViewer = new Landing (); + + Environment_old.landingViewer.init (); + + Environment_old.landingViewer.addProjectEventListener (Environment.achievementsManager); + + Environment_old.userPropertyHandlers.get (Constants.PROJECT_STATUSES_PROPERTY_NAME).addPropertyChangedListener (new PropertyChangedListener () + { + + @Override + public void propertyChanged (PropertyChangedEvent ev) + { + + if (ev.getChangeType ().equals (UserPropertyHandler.VALUE_CHANGED)) + { + + List toSave = new ArrayList (); + + String oldValue = (String) ev.getOldValue (); + String newValue = (String) ev.getNewValue (); + + // Change the type for all notes with the old type. + Set pis = null; + + try + { + + pis = Environment.getAllProjectInfos (); + + } catch (Exception e) { + + Environment.logError ("Unable to save: " + + toSave + + " with new type: " + + ev.getNewValue (), + e); + + UIUtils.showErrorMessage (Environment.getFocusedViewer (), + Environment.getUIString (LanguageStrings.project, + LanguageStrings.actions, + LanguageStrings.changestatus, + LanguageStrings.actionerror)); + //"Unable to change status"); + + return; + + } + for (ProjectInfo pi : pis) + { + + if (oldValue.equals (pi.getStatus ())) + { + + pi.setStatus (newValue); + + toSave.add (pi); + + } + + } + + if (toSave.size () > 0) + { + + try + { + + Environment_old.updateProjectInfos (toSave); + + } catch (Exception e) + { + + Environment.logError ("Unable to save: " + + toSave + + " with new type: " + + ev.getNewValue (), + e); + + UIUtils.showErrorMessage (Environment.getFocusedViewer (), + Environment.getUIString (LanguageStrings.project, + LanguageStrings.actions, + LanguageStrings.changestatus, + LanguageStrings.actionerror)); + //"Unable to change status"); + + } + + } + + } + + } + + }); + + } catch (Exception e) { + + Environment.logError ("Unable to create landing viewer", + e); + + UIUtils.showErrorMessage (null, + Environment.getUIString (LanguageStrings.allprojects, + LanguageStrings.actionerror)); + //"Unable to show all {projects}, please contact Quoll Writer support for assistance."); + + return; + + } + + } + + Environment_old.landingViewer.setVisible (true); + + Environment_old.landingViewer.toFront (); + + } +*/ +/* + public static boolean isPlaySoundOnKeyStroke () + { + + return Environment_old.playSoundOnKeyStroke; + + } +*/ +/* + public static void playKeyStrokeSound () + { + + if (Environment_old.keyStrokeSound == null) + { + + return; + + } + + if (!Environment_old.playSoundOnKeyStroke) + { + + return; + + } + + try + { + + if (Environment_old.keyStrokeSound.isRunning ()) + { + + Environment_old.keyStrokeSound.stop (); + + } + + Environment_old.keyStrokeSound.setFramePosition (0); + + Environment_old.keyStrokeSound.start (); + + } catch (Exception e) + { + + Environment.logError ("Unable to play key stroke sound", + e); + + Environment_old.playSoundOnKeyStroke = false; + + } + + } +*/ +/* + + public static void setKeyStrokeSoundFile (File f) + { + + try + { + + InputStream is = null; + + if (f != null) + { + + try + { + + is = new BufferedInputStream (new FileInputStream (f)); + + } catch (Exception e) { + + // Ignore. + + } + + } + + if (is == null) + { + + // Play the default. + is = new BufferedInputStream (Environment.getResourceStream (Constants.DEFAULT_KEY_STROKE_SOUND_FILE)); + + } + + // Get the clip. + AudioInputStream ais = AudioSystem.getAudioInputStream (is); + + Environment_old.keyStrokeSound = AudioSystem.getClip (); + + Environment_old.keyStrokeSound.open (ais); + + } catch (Exception e) { + + Environment.logError ("Unable to set key stroke sound file", + e); + + UserProperties.remove (Constants.KEY_STROKE_SOUND_FILE_PROPERTY_NAME); + + return; + + } + + if (f != null) + { + + UserProperties.set (Constants.KEY_STROKE_SOUND_FILE_PROPERTY_NAME, + f.getPath ()); + + } + + } +*/ +/* + public static void setPlaySoundOnKeyStroke (boolean v) + { + + Environment.playSoundOnKeyStroke = v; + + UserProperties.set (Constants.PLAY_SOUND_ON_KEY_STROKE_PROPERTY_NAME, + v); + + Environment.fireUserProjectEvent (new Object (), + ProjectEvent.TYPE_WRITER_SOUND, + (v ? ProjectEvent.ON : ProjectEvent.OFF)); + + + } +*/ + + /** + * Un-schedule the scheduledfuture, this is returned from Environment.schedule. + * + * @param f The scheduledfuture to remove from the executor service. + * @returns Whether it was successfully removed. + */ + /* + public static void unschedule (ScheduledFuture f) + { + + if (f == null) + { + + return; + + } + + // Let it run to completion. + f.cancel (false); + + Environment_old.generalTimer.purge (); + + } +*/ + /** + * Schedule the runnable to run after delay and repeat (use -1 or 0 for no repeat). + * + * @param r The runnable to run. + * @param delay The delay, in millis. + * @param repeat The repeat time, in millis. + */ + /* + public static ScheduledFuture schedule (final Runnable r, + final long delay, + final long repeat) + { + + if (Environment_old.generalTimer == null) + { + + Environment.logError ("Unable to schedule timer is no longer valid."); + + return null; + + } + + if (r == null) + { + + Environment.logError ("Unable to schedule, runnable is null."); + + return null; + + } + + if (repeat < 1) + { + + return Environment_old.generalTimer.schedule (r, + delay, + TimeUnit.MILLISECONDS); + + } else { + + return Environment_old.generalTimer.scheduleAtFixedRate (r, + delay, + repeat, + TimeUnit.MILLISECONDS); + + } + + } +*/ +/* + public static void addDoOnShutdown (Runnable r) + { + + Environment.doOnShutdown.add (r); + + } +*/ +/* + public static File getUserObjectTypeIconFile (String objType) + { + + return new File (Environment.getUserQuollWriterDir () + "/" + Constants.USER_OBJECT_TYPE_ICON_FILES_DIR + "/" + objType); + + } +*/ +/* + public static String getDefaultTextAlignment () + { + + return getUIString (textalignments,left); + + } + + public static String getDefaultChapterName () + { + + return getUIString (general,defaultchaptername); + + } +*/ +} diff --git a/src/com/quollwriter/FilenameFilterAdapter.java b/src/main/java/com/quollwriter/FilenameFilterAdapter.java similarity index 100% rename from src/com/quollwriter/FilenameFilterAdapter.java rename to src/main/java/com/quollwriter/FilenameFilterAdapter.java diff --git a/src/com/quollwriter/GeneralException.java b/src/main/java/com/quollwriter/GeneralException.java similarity index 100% rename from src/com/quollwriter/GeneralException.java rename to src/main/java/com/quollwriter/GeneralException.java diff --git a/src/main/java/com/quollwriter/Getter.java b/src/main/java/com/quollwriter/Getter.java new file mode 100644 index 00000000..9e7935e3 --- /dev/null +++ b/src/main/java/com/quollwriter/Getter.java @@ -0,0 +1,455 @@ +/* + * Copyright 2006 - Gary Bentley + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.quollwriter; + +import java.lang.reflect.Array; +import java.lang.reflect.Method; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; + +import java.util.List; +import java.util.ArrayList; +import java.util.StringTokenizer; + +/** + * This class is used to perform access into a Java object using a + * String value with a specific notation. + *

    + * The Accessor uses a dot notation such as field1.method1.method2 to + * perform the access on an object. Each value in the notation refers to + * a field or method (a no argument method) of the type of the previous + * value. + * For instance if you have the following class structure: + *

    + *
    + * public class A
    + * {
    + *    public B = new B ();
    + * }
    + *
    + * public class B
    + * {
    + *    public C = new C ();
    + * }
    + *
    + * public class C
    + * {
    + *    String d = "";
    + * }
    + * 
    + *

    + * You would then use the notation: B.C.d to get access to + * field d in Class C. + *

    + * The Accessor also supports a [ ] notation for accessing + * into Lists/Maps and Arrays. If the value between the [ ] + * is an integer then we look for the associated type to be either + * an array or a List, we then index into it with the integer. If + * the value is NOT an integer then we use assume the + * type is a Map and use it as a key into the Map. + *

    + * For instance changing the example above: + *

    + *
    + * public class A
    + * {
    + *    public List vals = new ArrayList ();
    + * }
    + * 
    + *

    + * Now we could use: vals[X] where X is a positive integer. + * Or changing again: + *

    + *
    + * public class A
    + * {
    + *    public Map vals = new HashMap ();
    + * }
    + * 
    + *

    + * We could use: vals[VALUE] where VALUE would then be + * used as a Key into the vals HashMap. + *

    + * Note: The Accessor is NOT designed to be an all purpose + * method of gaining access to a class. It has specific uses and for + * most will be of no use at all. It should be used for general purpose + * applications where you want to access specific fields of an object + * without having to know the exact type. One such application is in + * the {@link GeneralComparator}, in that case arbitrary Objects can + * be sorted without having to write complex Comparators or implementing + * the Comparable interface AND it gives the flexibility that sorting + * can be changed ad-hoc. + *

    + * The Accessor looks for in the following order: + *

      + *
    • Public fields with the specified name.
    • + *
    • If no field is found then the name is converted to a "JavaBeans" + * get method, so a field name of value would be converted + * to getValue and that method is looked for. The method must take + * no arguments.
    • + *
    • If we don't find the get* method then we look for a method with + * the specified name. So a field name of value would mean that + * a method (that again takes no arguments) is looked for.
    • + *
    + *

    + * Note: we have had to add the 3rd type to allow for methods that don't follow + * JavaBeans conventions (there are loads in the standard Java APIs which makes + * accessing impossible otherwise). + */ +public class Getter +{ + + private List chain = new ArrayList (); + + private Class clazz = null; + private int cs = 0; + private String acc = null; + + /** + * Get the getter associated with the named reference. Return + * null if there isn't one, or if we can't access it. + * + * @param ref The reference for the getter. + * @param clazz The Class to get the field from. + */ + public Getter (String ref, + Class clazz) + throws IllegalArgumentException + { + + if (clazz == null) + { + + throw new IllegalArgumentException ("Class must be specified"); + + } + + this.acc = ref; + this.clazz = clazz; + + StringTokenizer t = new StringTokenizer (ref, + "."); + + Class c = clazz; + + while (t.hasMoreTokens ()) + { + + String tok = t.nextToken (); + + String index = ""; + + // Get the Fields. + Field[] fields = c.getFields (); + + Field f = null; + + // See if the token matches... + for (int i = 0; i < fields.length; i++) + { + + if (fields[i].getName ().equals (tok)) + { + + // Found it... + f = fields[i]; + + break; + + } + + } + + if (f != null) + { + + c = f.getType (); + + this.chain.add (f); + + } else { + + Method m = this.getNoParmJavaGetMethod (tok, + c); + + if (m == null) + { + + throw new IllegalArgumentException ("Cannot find method with name: " + + tok + + " in class: " + + c.getName ()); + + } + + // Need to set the method as being accessible here to workaround + // an annoying Java reflection bug that seems to have been around + // since the year dot. See bug: 4071957. + m.setAccessible (true); + + c = m.getReturnType (); + + if (Void.class.isAssignableFrom (c)) + { + + throw new IllegalArgumentException ("Method: " + + m.getName () + + " cannot be called on class: " + + c.getName () + + " since return type is void"); + + } + + this.chain.add (m); + + } + + } + + this.cs = this.chain.size (); + + } + + public Class getBaseClass () + { + + return this.clazz; + + } + + /** + * Get the class of the type of object we would return from the {@link #getValue(Object)} + * method. + * + * @return The class. + */ + public Class getType () + { + + Object o = this.chain.get (this.chain.size () - 1); + + // See what type the accessor is... + if (o instanceof Method) + { + + Method m = (Method) o; + + return m.getReturnType (); + + } + + if (o instanceof Field) + { + + // It's a field...so... + Field f = (Field) o; + + return f.getType (); + + } + + return null; + + } + + public Object getValue (Object obj) + throws IllegalAccessException, + InvocationTargetException + { + + // If the object is null then return null. + if (obj == null) + { + + return null; + + } + + // For our accessor chain, use the Field and Methods + // to get the actual value. + Object retdata = obj; + + for (int i = 0; i < this.cs; i++) + { + + Object o = this.chain.get (i); + + // See what type the accessor is... + if (o instanceof Method) + { + + Method m = (Method) o; + + Object[] parms = {}; + + // Invoke the method... + try + { + + retdata = m.invoke (retdata, + parms); + + } catch (Exception e) { + + this.throwException (obj, + e); + + } + + if (retdata == null) + { + + return null; + + } + + } + + if (o instanceof Field) + { + + // It's a field...so... + Field f = (Field) o; + + // Now get the value... + try + { + + retdata = f.get (retdata); + + } catch (Exception e) { + + this.throwException (obj, + e); + + } + + } + + } + + return retdata; + + } + + private void throwException (Object o, + Exception e) + { + + throw new RuntimeException ("Unable to get value from instance of: " + + o.getClass ().getName () + + ", using accessor: " + + this.acc + + " expected type to be: " + + this.clazz.getName (), + e); + + + } + + public static Method getNoParmJavaGetMethod (String method, + Class c) + { + + StringBuffer b = new StringBuffer (method); + + Method m = null; + + // First look for a "get" method. + try + { + + b.setCharAt (0, + Character.toUpperCase (method.charAt (0))); + + b.insert (0, + "get"); + + String getMN = b.toString (); + + m = c.getMethod (getMN); + + if (m != null) + { + + return m; + + } + + } catch (Exception e) { + + // Painful to have to do it this way... + + } + + try + { + + b = new StringBuffer (method); + + b.setCharAt (0, + Character.toUpperCase (method.charAt (0))); + + b.insert (0, + "is"); + + String isMN = b.toString (); + + m = c.getMethod (isMN); + + if (m != null) + { + + return m; + + } + + } catch (Exception e) { + + // Sigh... + + } + + try + { + + return c.getMethod (method); + + } catch (Exception e) { + + // Ignore... + + } + + return null; + + } + + public String getAccessor () + { + + return this.acc; + + } + + public String toString () + { + + return "Accessor: " + this.acc + " from class: " + this.clazz.getName (); + + } + +} diff --git a/src/com/quollwriter/JSONDecoder.java b/src/main/java/com/quollwriter/JSONDecoder.java similarity index 76% rename from src/com/quollwriter/JSONDecoder.java rename to src/main/java/com/quollwriter/JSONDecoder.java index 35656cf0..0b70448f 100644 --- a/src/com/quollwriter/JSONDecoder.java +++ b/src/main/java/com/quollwriter/JSONDecoder.java @@ -1,5 +1,6 @@ package com.quollwriter; +import java.lang.reflect.*; import java.math.*; import java.text.*; @@ -22,22 +23,22 @@ public class JSONDecoder static { - escapes.put (new Character ('"'), - new Character ('"')); - escapes.put (new Character ('\\'), - new Character ('\\')); - escapes.put (new Character ('/'), - new Character ('/')); - escapes.put (new Character ('b'), - new Character ('\b')); - escapes.put (new Character ('f'), - new Character ('\f')); - escapes.put (new Character ('n'), - new Character ('\n')); - escapes.put (new Character ('r'), - new Character ('\r')); - escapes.put (new Character ('t'), - new Character ('\t')); + escapes.put (Character.valueOf ('"'), + Character.valueOf ('"')); + escapes.put (Character.valueOf ('\\'), + Character.valueOf ('\\')); + escapes.put (Character.valueOf ('/'), + Character.valueOf ('/')); + escapes.put (Character.valueOf ('b'), + Character.valueOf ('\b')); + escapes.put (Character.valueOf ('f'), + Character.valueOf ('\f')); + escapes.put (Character.valueOf ('n'), + Character.valueOf ('\n')); + escapes.put (Character.valueOf ('r'), + Character.valueOf ('\r')); + escapes.put (Character.valueOf ('t'), + Character.valueOf ('\t')); } private CharacterIterator it; @@ -201,6 +202,12 @@ private Object read () break; + case 'N' : + next (); + next (); + token = Double.valueOf (Double.NaN); + break; + case 't': next (); next (); @@ -251,8 +258,10 @@ private Object object () if (token != OBJECT_END) { + Object val = read (); + ret.put (key, - read ()); + val); if (read () == COMMA) { @@ -348,7 +357,7 @@ private Object string () add (unicode ()); } else { - Object value = escapes.get (new Character (c)); + Object value = escapes.get (Character.valueOf (c)); if (value != null) { @@ -363,7 +372,51 @@ private Object string () next (); - return buf.toString (); + String s = buf.toString (); + + if (s.startsWith ("@[")) + { + + int ind = s.indexOf ("]", + 2); + + if (ind > 2) + { + + try + { + + String cn = s.substring (2, + ind); + + Class cl = Class.forName (cn); + + Constructor con = cl.getDeclaredConstructor (String.class); + + if (con == null) + { + + throw new IllegalArgumentException ("Expected class: " + cn + " to have a constructor with a single String arg."); + + } + + Object o = con.newInstance (s.substring (ind + 1)); + + return o; + + } catch (Exception e) { + + throw new IllegalArgumentException ("Unable to create object and init from: " + s, + e); + + } + + } + + } + + return s; + } private void add (char cc) diff --git a/src/com/quollwriter/JSONEncoder.java b/src/main/java/com/quollwriter/JSONEncoder.java similarity index 90% rename from src/com/quollwriter/JSONEncoder.java rename to src/main/java/com/quollwriter/JSONEncoder.java index 5ec3732b..0fe65d1c 100644 --- a/src/com/quollwriter/JSONEncoder.java +++ b/src/main/java/com/quollwriter/JSONEncoder.java @@ -7,6 +7,7 @@ import java.util.*; import com.quollwriter.data.*; +import com.quollwriter.ui.fx.State; public class JSONEncoder { @@ -46,66 +47,66 @@ public static String encode (String s) return JSONEncoder.encode (s, false, ""); - + } - + public static String encodeNull (boolean prettyPrint, String indent) { - + StringBuilder sb = new StringBuilder (); - + if (prettyPrint) { - + sb.append (indent); - + } sb.append ("null"); - + return sb.toString (); - + } - + public static String encodeBoolean (Boolean value, boolean prettyPrint, String indent) { - + StringBuilder sb = new StringBuilder (); - + if (prettyPrint) { - + sb.append (indent); - + } sb.append (value.toString ()); - + return sb.toString (); - + } public static String encodeNumber (Number value, boolean prettyPrint, String indent) { - + StringBuilder sb = new StringBuilder (); - + if (prettyPrint) { - + sb.append (indent); - + } sb.append (String.valueOf (value.doubleValue ())); - + return sb.toString (); - + } public static String encode (String s, @@ -118,14 +119,14 @@ public static String encode (String s, int l = chars.length; StringBuilder sb = new StringBuilder (); - + if (prettyPrint) { - + sb.append (indent); - + } - + sb.append ('"'); char b = 0; @@ -271,9 +272,9 @@ public static String encode (Object o) return JSONEncoder.encode (o, false, ""); - + } - + public static String encode (Object o, boolean prettyPrint, String indent) @@ -282,27 +283,40 @@ public static String encode (Object o, if (o == null) { - + return JSONEncoder.encodeNull (prettyPrint, indent); } + if (o instanceof State) + { + + String s = String.format ("@[%s]%s", + State.class.getName (), + ((State) o).asString ()); + + return JSONEncoder.encode (s, + prettyPrint, + indent); + + } + if (o instanceof DataObject) { - + Map props = new LinkedHashMap (); - + DataObject d = (DataObject) o; - + d.fillToStringProperties (props); - + return JSONEncoder.encode (props, prettyPrint, indent); - + } - + if (o instanceof Date) { @@ -342,27 +356,36 @@ public static String encode (Object o, } + if (o instanceof javafx.beans.property.StringProperty) + { + + return JSONEncoder.encode (((javafx.beans.property.StringProperty) o).getValue ().toString (), + prettyPrint, + indent); + + } + if (o instanceof StringWithMarkup) { StringWithMarkup s = (StringWithMarkup) o; - + Map props = new LinkedHashMap (); if (s.getMarkup () != null) { - + props.put ("markup", s.getMarkup ().toString ()); - + } - + if (s.getText () != null) { - + props.put ("text", s.getText ()); - + } return JSONEncoder.encode (props, @@ -390,35 +413,35 @@ public static String encode (Object o, } /* DataObjectFormatter f = Environment.getFormatter (o.getClass ()); - + if ((f != null) && (o instanceof DataObject) ) { - + try { - + return JSONEncoder.encodeMap (f.encode ((DataObject) o)); - + } catch (Exception e) { - + throw new GeneralException ("Unable to encode object of type: " + o.getClass ().getName () + " using formatter: " + f.getClass ().getName (), e); - + } - + } */ - + return JSONEncoder.encode (o.toString (), prettyPrint, indent); - + //throw new GeneralException ("Object: " + o.getClass ().getName () + " is not supported."); } @@ -511,13 +534,13 @@ public static String createMapWrapper (Map m) public static String encodeMap (Map m) throws GeneralException { - + return JSONEncoder.encodeMap (m, false, ""); - + } - + public static String encodeMap (Map m, boolean prettyPrint, String indent) @@ -525,35 +548,35 @@ public static String encodeMap (Map m, { StringBuilder b = new StringBuilder (); - + if (m.size () == 0) { - + b.append ("{}"); - + return b.toString (); - + } else { - + if (prettyPrint) { - + b.append ("\n"); b.append (indent); - + } - + b.append ("{"); - + if (prettyPrint) { - + b.append ("\n"); - + } - + } - + Iterator iter = m.keySet ().iterator (); while (iter.hasNext ()) @@ -567,24 +590,24 @@ public static String encodeMap (Map m, if (prettyPrint) { - + b.append (" : "); - + } else { - + b.append (':'); - + } String v = null; Object val = m.get (k); - + String nindent = indent; - + if (prettyPrint) { - + if ((val instanceof Map) || (val instanceof Collection) @@ -592,17 +615,17 @@ public static String encodeMap (Map m, (val instanceof DataObject) ) { - + nindent = indent + " "; - + } else { - + nindent = ""; - + } - + } - + v = JSONEncoder.encode (val, prettyPrint, nindent); @@ -613,12 +636,12 @@ public static String encodeMap (Map m, { b.append (","); - + if (prettyPrint) { - + b.append ("\n"); - + } } @@ -627,15 +650,15 @@ public static String encodeMap (Map m, if (prettyPrint) { - + b.append (indent); b.append ("\n"); b.append (indent); - + } b.append ("}"); - + return b.toString (); } @@ -643,13 +666,13 @@ public static String encodeMap (Map m, public static String encodeCollection (Collection o) throws GeneralException { - + return JSONEncoder.encodeCollection (o, false, ""); - + } - + public static String encodeCollection (Collection o, boolean prettyPrint, String indent) @@ -657,9 +680,9 @@ public static String encodeCollection (Collection o, { StringBuilder b = new StringBuilder (); - + b.append ("["); - /* + /* if (o instanceof List) { @@ -669,25 +692,25 @@ public static String encodeCollection (Collection o, if (s == 0) { - + b.append ("]"); - + return b.toString (); - + } - + if (prettyPrint) { - + b.append ("\n"); - - } - + + } + for (int i = 0; i < s; i++) { String v = null; - + v = JSONEncoder.encode (l.get (i), prettyPrint, indent + " "); @@ -700,12 +723,12 @@ public static String encodeCollection (Collection o, b.append (","); } - + if (prettyPrint) { - + b.append ("\n"); - + } } @@ -720,20 +743,20 @@ public static String encodeCollection (Collection o, if (o.size () == 0) { - + b.append ("]"); - + return b.toString (); - + } - + if (prettyPrint) { - + b.append ("\n"); - - } - + + } + Iterator iter = o.iterator (); while (iter.hasNext ()) @@ -742,22 +765,22 @@ public static String encodeCollection (Collection o, String v = null; Object val = iter.next (); - + if (prettyPrint) { - + if ((val instanceof Map) || (val instanceof Collection) ) { - + indent += " "; - + } - + } - + v = JSONEncoder.encode (val, prettyPrint, indent); @@ -773,11 +796,11 @@ public static String encodeCollection (Collection o, if (prettyPrint) { - + b.append ("\n"); - + } - + } //} @@ -786,20 +809,20 @@ public static String encodeCollection (Collection o, if (prettyPrint) { - + b.append (indent); - + } - + b.append ("]"); - + if (prettyPrint) { - + b.append ("\n"); - + } - + return b.toString (); } diff --git a/src/com/quollwriter/LanguageDictionaryProvider.java b/src/main/java/com/quollwriter/LanguageDictionaryProvider.java similarity index 96% rename from src/com/quollwriter/LanguageDictionaryProvider.java rename to src/main/java/com/quollwriter/LanguageDictionaryProvider.java index 43939764..1f9e0629 100644 --- a/src/com/quollwriter/LanguageDictionaryProvider.java +++ b/src/main/java/com/quollwriter/LanguageDictionaryProvider.java @@ -1,12 +1,13 @@ package com.quollwriter; import java.io.*; +import java.nio.file.*; import java.util.*; import com.quollwriter.ui.events.*; -import com.quollwriter.ui.components.*; +import com.quollwriter.ui.fx.*; import com.quollwriter.text.*; import com.softcorporation.suggester.util.Constants; @@ -52,7 +53,8 @@ private LanguageDictionaryProvider (String lang) this.language = lang; - File dictFile = Environment.getDictionaryFile (lang); + // TODO CHange to a path. + File dictFile = DictionaryProvider.getDictionaryFilePath (lang).toFile (); if (!dictFile.exists ()) { @@ -224,19 +226,9 @@ public String getLanguage () public static boolean isLanguageInstalled (String lang) { - File f = Environment.getDictionaryFile (lang); + Path f = DictionaryProvider.getDictionaryFilePath (lang); - if ((f != null) - && - (f.exists ()) - ) - { - - return true; - - } - - return false; + return f != null && Files.exists (f); } diff --git a/src/main/java/com/quollwriter/LanguageStrings.java b/src/main/java/com/quollwriter/LanguageStrings.java new file mode 100644 index 00000000..a599b420 --- /dev/null +++ b/src/main/java/com/quollwriter/LanguageStrings.java @@ -0,0 +1,1010 @@ +package com.quollwriter; + +public class LanguageStrings +{ + + public static final String newtype = "newtype"; + public static final String editnotetypes = "editnotetypes"; + public static final String keypress = "keypress"; + public static final String editposition = "editposition"; + public static final String projectswindow = "projectswindow"; + public static final String language = "language"; + public static final String projectdir = "projectdir"; + public static final String subtitles = "subtitles"; + public static final String isfirstuse = "isfirstuse"; + public static final String first = "first"; + public static final String permanentnightmode = "permanentnightmode"; + public static final String nightmode = "nightmode"; + public static final String configure = "configure"; + public static final String autonightmode = "autonightmode"; + public static final String range = "range"; + public static final String between = "between"; + public static final String and = "and"; + public static final String select = "select"; + public static final String selectall = "selectall"; + public static final String sections = "sections"; + public static final String nosections = "nosections"; + public static final String license = "license"; + public static final String wordcounttimer = "wordcounttimer"; + public static final String top = "top"; + public static final String bottom = "bottom"; + public static final String up = "up"; + public static final String down = "down"; + public static final String play = "play"; + public static final String pause = "pause"; + public static final String stylesheet = "stylesheet"; + public static final String errortooltip = "errortooltip"; + public static final String links = "links"; + public static final String prunebackups = "prunebackups"; + public static final String drop = "drop"; + public static final String removecolumn = "removecolumn"; + public static final String editcolumntitle = "editcolumntitle"; + public static final String editall = "editall"; + public static final String column = "column"; + public static final String newfield = "newfield"; + public static final String addcolumn = "addcolumn"; + public static final String editfield = "editfield"; + public static final String init = "init"; + public static final String renameasset = "renameasset"; + public static final String project = "project"; + public static final String settingsmenu = "settingsmenu"; + public static final String items = "items"; + public static final String _this = "this"; + public static final String addfieldbelow = "addfieldbelow"; + public static final String wordseparator = "wordseparator"; + public static final String current = "current"; + public static final String basefontsize = "basefontsize"; + public static final String basefontsizeless = "basefontsizeless"; + public static final String basefontsizemore = "basefontsizemore"; + public static final String basefont = "basefont"; + public static final String languagenames = "languagenames"; + public static final String createdbyyou = "createdbyyou"; + public static final String renameproject = "renameproject"; + public static final String statistics = "statistics"; + public static final String targets = "targets"; + public static final String createbackup = "createbackup"; + public static final String openproject = "openproject"; + public static final String newproject = "newproject"; + public static final String deleteproject = "deleteproject"; + public static final String closeproject = "closeproject"; + public static final String exportproject = "exportproject"; + public static final String ideaboard = "ideaboard"; + public static final String dowarmup = "dowarmup"; + + public static final String actionerror = "actionerror"; + public static final String label = "label"; + public static final String filetype = "filetype"; + public static final String stages = "stages"; + public static final String wheretosave = "wheretosave"; + public static final String finder = "finder"; + public static final String tooltip = "tooltip"; + public static final String button = "button"; + public static final String title = "title"; + public static final String text = "text"; + public static final String help = "help"; + public static final String nexterror = "nexterror"; + public static final String previouserror = "previouserror"; + public static final String exportcompletepopup = "exportcompletepopup"; + public static final String sectiontitles = "sectiontitles"; + public static final String plan = "plan"; + public static final String goals = "goals"; + public static final String assets = "assets"; + public static final String notes = "notes"; + public static final String scenesoutlineitems = "scenesoutlineitems"; + public static final String chapterinfo = "chapterinfo"; + public static final String howtosave = "howtosave"; + public static final String otheritems = "otheritems"; + public static final String onefileperitemtype = "onefileperitemtype"; + public static final String types = "types"; + public static final String singlefile = "singlefile"; + public static final String onefileperchapter = "onefileperchapter"; + public static final String selectitems = "selectitems"; + public static final String importproject = "importproject"; + public static final String projectslist = "projectslist"; + public static final String selectproject = "selectproject"; + public static final String getallprojectserror = "getallprojectserror"; + public static final String moretextindicator = "moretextindicator"; + public static final String choose = "choose"; + public static final String importfromfile = "importfromfile"; + public static final String importfile = "importfile"; + public static final String options = "options"; + public static final String importfromproject = "importfromproject"; + public static final String selectfile = "selectfile"; + public static final String decide = "decide"; + public static final String textextra = "textextra"; + public static final String addtoproject = "addtoproject"; + public static final String importcompletepopup = "importcompletepopup"; + public static final String unabletosave = "unabletosave"; + public static final String supportedfiletypesdescription = "supportedfiletypesdescription"; + public static final String unabletocreateproject = "unabletocreateproject"; + public static final String nofileselected = "nofileselected"; + public static final String filenotexist = "filenotexist"; + public static final String dirselected = "dirselected"; + public static final String openfile = "openfile"; + public static final String cantopenproject = "cantopenproject"; + public static final String popup = "popup"; + public static final String wizard = "wizard"; + public static final String buttons = "buttons"; + public static final String confirm = "confirm"; + public static final String problemfinder = "problemfinder"; + public static final String config = "config"; + public static final String removerule = "removerule"; + public static final String thisproject = "thisproject"; + public static final String allprojects = "allprojects"; + public static final String rulebox = "rulebox"; + public static final String find = "find"; + public static final String info = "info"; + public static final String delete = "delete"; + public static final String edit = "edit"; + public static final String sentence = "sentence"; + public static final String paragraph = "paragraph"; + public static final String words = "words"; + public static final String addrule = "addrule"; + public static final String editrule = "editrule"; + public static final String add = "add"; + public static final String saveruleerror = "saveruleerror"; + public static final String tabtitles = "tabtitles"; + public static final String form = "form"; + public static final String labels = "labels"; + public static final String summary = "summary"; + public static final String description = "description"; + public static final String errors = "errors"; + public static final String entervalue = "entervalue"; + public static final String wordfinder = "wordfinder"; + public static final String passivesentence = "passivesentence"; + public static final String adverb = "adverb"; + public static final String wordphrase = "wordphrase"; + public static final String anywhere = "anywhere"; + public static final String where = "where"; + public static final String startofsentence = "startofsentence"; + public static final String endofsentence = "endofsentence"; + public static final String onlyindialogue = "onlyindialogue"; + public static final String ignoreindialogue = "ignoreindialogue"; + public static final String nowordserror = "nowordserror"; + public static final String rules = "rules"; + public static final String issues = "issues"; + public static final String suffixes = "suffixes"; + public static final String notindialogue = "notindialogue"; + public static final String indialogue = "indialogue"; + public static final String edittitle = "edittitle"; + public static final String insentence = "insentence"; + public static final String speechverbs = "speechverbs"; + public static final String newspeechverbs = "newspeechverbs"; + public static final String removespeechverbs = "removespeechverbs"; + public static final String separate = "separate"; + public static final String punctuationtext = "punctuationtext"; + public static final String wordtext = "wordtext"; + public static final String addtitle = "addtitle"; + public static final String doubleword = "doubleword"; + public static final String paragraphlength = "paragraphlength"; + public static final String sentencetext = "sentencetext"; + public static final String sentences = "sentences"; + public static final String paragraphreadability = "paragraphreadability"; + public static final String fr = "fr"; + public static final String fk = "fk"; + public static final String gf = "gf"; + public static final String sentencelength = "sentencelength"; + public static final String sentencecomplexity = "sentencecomplexity"; + public static final String ratio = "ratio"; + public static final String toomanyclauses = "toomanyclauses"; + public static final String clauses = "clauses"; + public static final String startup = "startup"; + public static final String cantopenlastprojecterror = "cantopenlastprojecterror"; + public static final String alreadyrunningerror = "alreadyrunningerror"; + public static final String unabletostarterror = "unabletostarterror"; + public static final String invalidemail = "invalidemail"; + public static final String functionunavailable = "functionunavailable"; + public static final String actions = "actions"; + public static final String fontunavailable = "fontunavailable"; + public static final String chaptersoverwcmaximum = "chaptersoverwcmaximum"; + public static final String multipleoverlimit = "multipleoverlimit"; + public static final String singleoverlimit = "singleoverlimit"; + public static final String multiple = "multiple"; + public static final String single = "single"; + public static final String chaptersoverreadabilitymaximum = "chaptersoverreadabilitymaximum"; + public static final String showdetail = "showdetail"; + public static final String autobackupnotification = "autobackupnotification"; + public static final String backups = "backups"; + public static final String spellchecker = "spellchecker"; + public static final String unabletosetlanguage = "unabletosetlanguage"; + public static final String achievementspanel = "achievementspanel"; + public static final String savechanges = "savechanges"; + public static final String discardchanges = "discardchanges"; + public static final String confirmpopup = "confirmpopup"; + public static final String fullscreen = "fullscreen"; + public static final String showpanelactionerror = "showpanelactionerror"; + public static final String closepanel = "closepanel"; + public static final String discard = "discard"; + public static final String save = "save"; + public static final String editors = "editors"; + public static final String vieweditorerror = "vieweditorerror"; + public static final String vieweditorserror = "vieweditorserror"; + public static final String showregistererror = "showregistererror"; + public static final String deletechapter = "deletechapter"; + public static final String toolbar = "toolbar"; + public static final String viewaddasset = "viewaddasset"; + public static final String viewchapterinformation = "viewchapterinformation"; + public static final String editchapter = "editchapter"; + public static final String viewproblemfindersidebar = "viewproblemfindersidebar"; + public static final String removetag = "removetag"; + public static final String close = "close"; + public static final String send = "send"; + public static final String email = "email"; + public static final String message = "message"; + public static final String errorlabel = "errorlabel"; + public static final String about = "about"; + public static final String keyboardshortcuts = "keyboardshortcuts"; + public static final String contactsupport = "contactsupport"; + public static final String viewuserguide = "viewuserguide"; + public static final String reportbug = "reportbug"; + public static final String whatsnew = "whatsnew"; + public static final String achievements = "achievements"; + public static final String projectmenu = "projectmenu"; + public static final String type = "type"; + public static final String vieweditors = "vieweditors"; + public static final String editorsserviceregister = "editorsserviceregister"; + public static final String showcontacts = "showcontacts"; + public static final String betabug = "betabug"; + public static final String bug = "bug"; + public static final String warmup = "warmup"; + public static final String reportproblem = "reportproblem"; + public static final String sendlogfiles = "sendlogfiles"; + public static final String sendscreenshot = "sendscreenshot"; + public static final String cancel = "cancel"; + public static final String debugmode = "debugmode"; + public static final String enabled = "enabled"; + public static final String disabled = "disabled"; + public static final String dowarmuponstart = "dowarmuponstart"; + public static final String times = "times"; + public static final String unlimited = "unlimited"; + public static final String words100 = "words100"; + public static final String words250 = "words250"; + public static final String words500 = "words500"; + public static final String words1000 = "words1000"; + public static final String hour1 = "hour1"; + public static final String mins5 = "mins5"; + public static final String mins10 = "mins10"; + public static final String mins20 = "mins20"; + public static final String mins30 = "mins30"; + public static final String week1 = "week1"; + public static final String days2 = "days2"; + public static final String days5 = "days5"; + public static final String hours12 = "hours12"; + public static final String hours24 = "hours24"; + public static final String addwarmuperror = "addwarmuperror"; + public static final String getwarmupsprojecterror = "getwarmupsprojecterror"; + public static final String starterror = "starterror"; + public static final String createwarmupsproject = "createwarmupsproject"; + public static final String openwarmupsprojecterror = "openwarmupsprojecterror"; + public static final String startwriting = "startwriting"; + public static final String saveerror = "saveerror"; + public static final String whicheverfirst = "whicheverfirst"; + public static final String andor = "andor"; + public static final String dofor = "dofor"; + public static final String ownprompt = "ownprompt"; + public static final String nextprompt = "nextprompt"; + public static final String previousprompt = "previousprompt"; + public static final String allpromptsexcluded = "allpromptsexcluded"; + public static final String visitlink = "visitlink"; + public static final String weblinks = "weblinks"; + public static final String noshowpromptagain = "noshowpromptagain"; + public static final String chooseprompt = "chooseprompt"; + public static final String acknowledgments = "acknowledgments"; + public static final String makeadonation = "makeadonation"; + public static final String releasenotes = "releasenotes"; + public static final String sourcecode = "sourcecode"; + public static final String website = "website"; + public static final String copyright = "copyright"; + public static final String qwversion = "qwversion"; + public static final String stop = "stop"; + public static final String tipspanel = "tipspanel"; + public static final String next = "next"; + public static final String previous = "previous"; + public static final String name = "name"; + public static final String tips = "tips"; + public static final String sidebar = "sidebar"; + public static final String section = "section"; + public static final String appearsinchapters = "appearsinchapters"; + public static final String showinsidebar = "showinsidebar"; + public static final String activetitle = "activetitle"; + public static final String headerpopupmenu = "headerpopupmenu"; + public static final String treepopupmenu = "treepopupmenu"; + public static final String tree = "tree"; + public static final String view = "view"; + public static final String sort = "sort"; + public static final String _new = "new"; + public static final String aboutpanel = "aboutpanel"; + public static final String linkedto = "linkedto"; + public static final String editobjecttypeinfo = "editobjecttypeinfo"; + public static final String addfileordocument = "addfileordocument"; + public static final String popupmenu = "popupmenu"; + public static final String user = "user"; + public static final String playsound = "playsound"; + public static final String playsoundinfullscreen = "playsoundinfullscreen"; + public static final String enable = "enable"; + public static final String enablenightmode = "enablenightmode"; + public static final String disablenightmode = "disablenightmode"; + public static final String legacyfields = "legacyfields"; + public static final String aliases = "aliases"; + public static final String webpage = "webpage"; + public static final String textalignments = "textalignments"; + public static final String left = "left"; + public static final String right = "right"; + public static final String justified = "justified"; + public static final String sidebars = "sidebars"; + public static final String othersidebarselect = "othersidebarselect"; + public static final String cantfindeditor = "cantfindeditor"; + public static final String invalidprojectdir = "invalidprojectdir"; + public static final String projectdirisfile = "projectdirisfile"; + public static final String projectdirnotexist = "projectdirnotexist"; + public static final String projectnotexist = "projectnotexist"; + public static final String openerrors = "openerrors"; + public static final String general = "general"; + public static final String writingtargetreachedpopup = "writingtargetreachedpopup"; + public static final String monthly = "monthly"; + public static final String weekly = "weekly"; + public static final String daily = "daily"; + public static final String session = "session"; + public static final String enterpasswordpopup = "enterpasswordpopup"; + public static final String novalue = "novalue"; + public static final String invalidvalue = "invalidvalue"; + public static final String projectalreadyopen = "projectalreadyopen"; + public static final String invalidpassword = "invalidpassword"; + public static final String invalidstate = "invalidstate"; + public static final String open = "open"; + public static final String changestatus = "changestatus"; + public static final String restore = "restore"; + public static final String showerror = "showerror"; + public static final String viewbackupsdir = "viewbackupsdir"; + public static final String nobackups = "nobackups"; + public static final String show = "show"; + public static final String deleteitem = "deleteitem"; + public static final String confirmword = "confirmword"; + public static final String startat = "startat"; + public static final String endat = "endat"; + public static final String splitchapter = "splitchapter"; + public static final String newchaptername = "newchaptername"; + public static final String cantreopenproject = "cantreopenproject"; + //public static final String projectexists = "projectexists"; + public static final String renamechapter = "renamechapter"; + //public static final String chapterexists = "chapterexists"; + public static final String newchapter = "newchapter"; + public static final String deletetype = "deletetype"; + public static final String warning = "warning"; + public static final String valueexists = "valueexists"; + public static final String warmups = "warmups"; + public static final String deletewarmup = "deletewarmup"; + public static final String notifications = "notifications"; + public static final String remove = "remove"; + public static final String filefinder = "filefinder"; + public static final String errormessage = "errormessage"; + public static final String generalmessage = "generalmessage"; + public static final String iconcolumn = "iconcolumn"; + public static final String distractionfreemode = "distractionfreemode"; + public static final String viewitem = "viewitem"; + public static final String edititem = "edititem"; + public static final String moveitem = "moveitem"; + public static final String linkitem = "linkitem"; + public static final String manage = "manage"; + public static final String rename = "rename"; + public static final String colorchooser = "colorchooser"; + public static final String hex = "hex"; + public static final String red = "red"; + public static final String blue = "blue"; + public static final String green = "green"; + public static final String color = "color"; + public static final String swatch = "swatch"; + public static final String reset = "reset"; + public static final String objectfinder = "objectfinder"; + public static final String renamewarmup = "renamewarmup"; + public static final String editorproject = "editorproject"; + public static final String normal = "normal"; + public static final String editor = "editor"; + public static final String plural = "plural"; + public static final String headercontrols = "headercontrols"; + public static final String loading = "loading"; + public static final String notfound = "notfound"; + public static final String results = "results"; + public static final String findall = "findall"; + public static final String ignored = "ignored"; + public static final String unignore = "unignore"; + public static final String ignore = "ignore"; + public static final String checkbox = "checkbox"; + public static final String overlay = "overlay"; + public static final String deleteall = "deleteall"; + public static final String addsection = "addsection"; + public static final String newobject = "newobject"; + public static final String hidesection = "hidesection"; + public static final String addtag = "addtag"; + public static final String below = "below"; + public static final String tags = "tags"; + public static final String newtag = "newtag"; + public static final String table = "table"; + public static final String finish = "finish"; + public static final String loadallerror = "loadallerror"; + public static final String converttoproject = "converttoproject"; + public static final String entersummaryerror = "entersummaryerror"; + public static final String maxchars = "maxchars"; + public static final String dictionary = "dictionary"; + public static final String synonyms = "synonyms"; + public static final String formatting = "formatting"; + public static final String format = "format"; + public static final String bold = "bold"; + public static final String italic = "italic"; + public static final String underline = "underline"; + public static final String spellcheck = "spellcheck"; + public static final String nosuggestions = "nosuggestions"; + public static final String nosynonyms = "nosynonyms"; + public static final String more = "more"; + public static final String redo = "redo"; + public static final String undo = "undo"; + public static final String cut = "cut"; + public static final String paste = "paste"; + public static final String copy = "copy"; + public static final String textarea = "textarea"; + public static final String charsremaining = "charsremaining"; + public static final String charsover = "charsover"; + public static final String deletetag = "deletetag"; + public static final String prompt = "prompt"; + public static final String create = "create"; + public static final String newprojectpanel = "newprojectpanel"; + public static final String encrypt = "encrypt"; + public static final String password = "password"; + public static final String confirmpassword = "confirmpassword"; + public static final String nopassword = "nopassword"; + public static final String nomatch = "nomatch"; + public static final String savein = "savein"; + public static final String newwords = "newwords"; + public static final String nodirselected = "nodirselected"; + public static final String createexporter = "createexporter"; + public static final String objectnames = "objectnames"; + public static final String singular = "singular"; + public static final String convertwarmup = "convertwarmup"; + public static final String editwarmup = "editwarmup"; + public static final String enter = "enter"; + public static final String exit = "exit"; + public static final String firsttimepopup = "firsttimepopup"; + public static final String editproperties = "editproperties"; + public static final String sessionwordcount = "sessionwordcount"; + public static final String chapterwordcount = "chapterwordcount"; + public static final String word = "word"; + public static final String distractionfreemodeenter = "distractionfreemodeenter"; + public static final String distractionfreemodeexit = "distractionfreemodeexit"; + public static final String showproperties = "showproperties"; + public static final String achievementreached = "achievementreached"; + public static final String fullscreenexit = "fullscreenexit"; + public static final String changer = "changer"; + public static final String resetchange = "resetchange"; + public static final String confirmchange = "confirmchange"; + public static final String panel = "panel"; + public static final String nolinksedit = "nolinksedit"; + public static final String file = "file"; + public static final String othernames = "othernames"; + public static final String allowmulti = "allowmulti"; + public static final String multi = "multi"; + public static final String valueseparator = "valueseparator"; + public static final String addedit = "addedit"; + public static final String bulletpoints = "bulletpoints"; + public static final String max = "max"; + public static final String min = "min"; + public static final String greaterthanmin = "greaterthanmin"; + public static final String _default = "default"; + public static final String lessthanmax = "lessthanmax"; + public static final String smallicon = "smallicon"; + public static final String bigicon = "bigicon"; + public static final String warnings = "warnings"; + public static final String basic = "basic"; + public static final String userobjects = "userobjects"; + public static final String fields = "fields"; + public static final String move = "move"; + public static final String layout = "layout"; + public static final String layouts = "layouts"; + public static final String layout0 = "0"; + public static final String layout1 = "1"; + public static final String layout2 = "2"; + public static final String layout3 = "3"; + public static final String layout4 = "4"; + public static final String layout5 = "5"; + public static final String layout6 = "6"; + public static final String layout7 = "7"; + public static final String layout8 = "8"; + public static final String spellcheckon = "spellcheckon"; + public static final String spellcheckoff = "spellcheckoff"; + public static final String tools = "tools"; + public static final String wordcount = "wordcount"; + public static final String editorpanel = "editorpanel"; + public static final String textproperties = "textproperties"; + public static final String print = "print"; + public static final String convert = "convert"; + public static final String notetypes = "notetypes"; + public static final String gotoeditposition = "gotoeditposition"; + public static final String removeeditposition = "removeeditposition"; + public static final String seteditcomplete = "seteditcomplete"; + public static final String showchapterinfo = "showchapterinfo"; + public static final String seteditposition = "seteditposition"; + public static final String compresstext = "compresstext"; + public static final String shortcutprefix = "shortcutprefix"; + public static final String doubleclickmenu = "doubleclickmenu"; + public static final String ideatypes = "ideatypes"; + public static final String ideas = "ideas"; + public static final String on = "on"; + public static final String off = "off"; + public static final String objectpreview = "objectpreview"; + public static final String newbelow = "newbelow"; + public static final String edittextproperties = "edittextproperties"; + public static final String chapters = "chapters"; + public static final String scenes = "scenes"; + public static final String outlineitems = "outlineitems"; + public static final String seteditneeded = "seteditneeded"; + public static final String ignoreall = "ignoreall"; + public static final String manageitems = "manageitems"; + public static final String newitems = "newitems"; + public static final String separators = "separators"; + public static final String status = "status"; + public static final String clicktoclose = "clicktoclose"; + public static final String clicktoview = "clicktoview"; + public static final String clicktohide = "clicktohide"; + public static final String doubleclicktoview = "doubleclicktoview"; + public static final String readability = "readability"; + public static final String projectwords = "projectwords"; + public static final String totalwords = "totalwords"; + public static final String selected = "selected"; + public static final String edited = "edited"; + public static final String allchapters = "allchapters"; + public static final String viewdetaillink = "viewdetaillink"; + public static final String helplink = "helplink"; + public static final String sparkline = "sparkline"; + public static final String valuepercent = "valuepercent"; + public static final String a4pages = "a4pages"; + public static final String documents = "documents"; + public static final String showfolder = "showfolder"; + public static final String noobjectselectedpanel = "noobjectselectedpanel"; + public static final String upgrade = "upgrade"; + public static final String download = "download"; + public static final String start = "start"; + public static final String cantcreatetemporaryfile = "cantcreatetemporaryfile"; + public static final String newversionavailable = "newversionavailable"; + public static final String exitnow = "exitnow"; + public static final String exitlater = "exitlater"; + public static final String unabletodownload = "unabletodownload"; + public static final String later = "later"; + public static final String restart = "restart"; + public static final String complete = "complete"; + public static final String digestinvalid = "digestinvalid"; + public static final String inprogress = "inprogress"; + public static final String checkingfile = "checkingfile"; + public static final String changedisplay = "changedisplay"; + public static final String managestatuses = "managestatuses"; + public static final String sortwordcount = "sortwordcount"; + public static final String sortstatus = "sortstatus"; + public static final String sortname = "sortname"; + public static final String sortlastedited = "sortlastedited"; + public static final String sortprojects = "sortprojects"; + public static final String findprojects = "findprojects"; + public static final String importfileorproject = "importfileorproject"; + public static final String noprojects = "noprojects"; + public static final String example = "example"; + public static final String selectbackground = "selectbackground"; + public static final String removeproject = "removeproject"; + public static final String projectopen = "projectopen"; + public static final String unspecified = "unspecified"; + public static final String error = "error"; + public static final String encrypted = "encrypted"; + public static final String tooltips = "tooltips"; + public static final String managebackups = "managebackups"; + public static final String newstatus = "newstatus"; + public static final String setstatus = "setstatus"; + public static final String editcomplete = "editcomplete"; + public static final String notedited = "notedited"; + public static final String lastedited = "lastedited"; + public static final String details = "details"; + public static final String nomoreproblems = "nomoreproblems"; + public static final String limit = "limit"; + public static final String unignoreall = "unignoreall"; + public static final String noproblemsfound = "noproblemsfound"; + public static final String end = "end"; + public static final String unignoreissues = "unignoreissues"; + public static final String wordtypes = "wordtypes"; + public static final String adverbs = "adverbs"; + public static final String other = "other"; + public static final String tabs = "tabs"; + public static final String verbs = "verbs"; + public static final String adjectives = "adjectives"; + public static final String nouns = "nouns"; + public static final String notfirst = "notfirst"; + public static final String firstusewizard = "firstusewizard"; + public static final String selectprojectdb = "selectprojectdb"; + public static final String existing = "existing"; + public static final String manual = "manual"; + public static final String imageselector = "imageselector"; + public static final String viewonlypanel = "viewonlypanel"; + public static final String testboolbarbuttonmessage = "testboolbarbuttonmessage"; + public static final String test = "test"; + public static final String bulletedtext = "bulletedtext"; + public static final String charts = "charts"; + public static final String allwordcounts = "allwordcounts"; + public static final String _for = "for"; + public static final String xaxis = "xaxis"; + public static final String yaxis = "yaxis"; + public static final String lastmonth = "lastmonth"; + public static final String thismonth = "thismonth"; + public static final String alltime = "alltime"; + public static final String lastweek = "lastweek"; + public static final String thisweek = "thisweek"; + public static final String perchapter = "perchapter"; + public static final String history = "history"; + public static final String showaverage = "showaverage"; + public static final String showtarget = "showtarget"; + public static final String markers = "markers"; + public static final String average = "average"; + public static final String target = "target"; + public static final String chaptersovertarget = "chaptersovertarget"; + public static final String averagesuffix = "averagesuffix"; + public static final String now = "now"; + public static final String forchapters = "forchapters"; + public static final String notarget = "notarget"; + public static final String detail = "detail"; + public static final String timeseries = "timeseries"; + public static final String added = "added"; + public static final String removed = "removed"; + public static final String showgf = "showgf"; + public static final String showfk = "showfk"; + public static final String showtargets = "showtargets"; + public static final String averagegf = "averagegf"; + public static final String averagegfsuffix = "averagegfsuffix"; + public static final String averagefk = "averagefk"; + public static final String averagefksuffix = "averagefksuffix"; + public static final String targetfk = "targetfk"; + public static final String targetgf = "targetgf"; + public static final String overtargetfk = "overtargetfk"; + public static final String overtargetgf = "overtargetgf"; + public static final String excluded = "excluded"; + public static final String notargets = "notargets"; + public static final String sessionlength = "sessionlength"; + public static final String sessions = "sessions"; + public static final String sessionsover1hr = "sessionsover1hr"; + public static final String sessionsovertarget = "sessionsovertarget"; + public static final String sessionmostwords = "sessionmostwords"; + public static final String numsessions = "numsessions"; + public static final String totalsessiontime = "totalsessiontime"; + public static final String numzerowordsessions = "numzerowordsessions"; + public static final String longestsession = "longestsession"; + public static final String averagesessionlength = "averagesessionlength"; + public static final String showzero = "showzero"; + public static final String averagesession = "averagesession"; + public static final String hide = "hide"; + public static final String rating = "rating"; + public static final String shorttext = "shorttext"; + public static final String sortrating = "sortrating"; + public static final String sortdate = "sortdate"; + public static final String sortalpha = "sortalpha"; + public static final String newidea = "newidea"; + public static final String noideas = "noideas"; + public static final String header = "header"; + public static final String defaulttypes = "defaulttypes"; + public static final String dialogue = "dialogue"; + public static final String none = "none"; + public static final String clear = "clear"; + public static final String image = "image"; + public static final String newtypes = "newtypes"; + public static final String newnotetype = "newnotetype"; + public static final String selectitem = "selectitem"; + public static final String unavailable = "unavailable"; + public static final String affirmativevalue = "affirmativevalue"; + public static final String notification = "notification"; + public static final String preview = "preview"; + public static final String nodescription = "nodescription"; + public static final String problemcount = "problemcount"; + public static final String spellingcount = "spellingcount"; + public static final String emptychapter = "emptychapter"; + public static final String notapplicable = "notapplicable"; + public static final String apply = "apply"; + public static final String defaults = "defaults"; + public static final String names = "names"; + public static final String unabletoopenfile = "unabletoopenfile"; + public static final String unabletoopenwebpage = "unabletoopenwebpage"; + public static final String appendix = "appendix"; + public static final String bookdetails = "bookdetails"; + public static final String authorname = "authorname"; + public static final String id = "id"; + public static final String addor = "andor"; + public static final String time = "time"; + public static final String timer = "timer"; + public static final String remaining = "remaining"; + public static final String less1min = "less1min"; + public static final String over1min = "over1min"; + public static final String noname = "noname"; + public static final String adddesctochapter = "adddesctochapter"; + public static final String chapteritems = "chapteritems"; + public static final String mywriting = "mywriting"; + public static final String showmessagewhentargetreached = "showmessagewhentargetreached"; + public static final String showwarningwhenchapterexceedsmax = "showwarningwhenchapterexceedsmax"; + public static final String chaptersovermaxtarget = "chaptersovermaxtarget"; + public static final String chaptersoverreadabilitytarget = "chaptersoverreadabilitytarget"; + public static final String overlimit = "overlimit"; + public static final String maximum = "maximum"; + public static final String unabletoperformaction = "unabletoperformaction"; + public static final String fullscreentitle = "fullscreentitle"; + public static final String deletesceneoutlineitems = "deletesceneoutlineitems"; + public static final String fontsize = "fontsize"; + public static final String alignment = "alignment"; + public static final String linespacing = "linespacing"; + public static final String paragraphspacing = "paragraphspacing"; + public static final String textborder = "textborder"; + public static final String indentfirstline = "indentfirstline"; + public static final String highlightwritingline = "highlightwritingline"; + public static final String highlightlinecolor = "highlightlinecolor"; + public static final String textcolor = "textcolor"; + public static final String bgcolor = "bgcolor"; + public static final String bgopacity = "bgopacity"; + public static final String bgimagewebsites = "bgimagewebsites"; + public static final String fullscreenproperties = "fullscreenproperties"; + public static final String areasize = "areasize"; + public static final String showtimewordcount = "showtimewordcount"; + public static final String versions = "versions"; + public static final String qwstart = "qwstart"; + public static final String showtips = "showtips"; + public static final String showlastedited = "showlastedited"; + public static final String showprojectswindow = "showprojectswindow"; + public static final String betas = "betas"; + public static final String optin = "optin"; + public static final String itemsandrules = "itemsandrules"; + public static final String autologin = "autologin"; + public static final String defaultstatus = "defaultstatus"; + public static final String statuses = "statuses"; + public static final String online = "online"; + public static final String offline = "offline"; + public static final String busy = "busy"; + public static final String away = "away"; + public static final String snooze = "snooze"; + public static final String fullscreenbusystatus = "fullscreenbusystatus"; + public static final String logmessages = "logmessages"; + public static final String problemfinderrules = "problemfinderrules"; + public static final String editingchapters = "editingchapters"; + public static final String haseditposition = "haseditposition"; + public static final String showicon = "showicon"; + public static final String autosave = "autosave"; + public static final String autosavewhen = "autosavewhen"; + public static final String viewexample = "viewexample"; + public static final String showeditposition = "showeditposition"; + public static final String seteditpositioncolor = "seteditpositioncolor"; + public static final String seteditcompleteatchapterend = "seteditcompleteatchapterend"; + public static final String compressrightclickmenu = "compressrightclickmenu"; + public static final String setspellcheckerlanguage = "setspellcheckerlanguage"; + public static final String downloadlanguagefiles = "downloadlanguagefiles"; + public static final String setasdefaultlanguage = "setasdefaultlanguage"; + public static final String nonenglishwarning = "nonenglishwarning"; + public static final String downloaddictionaryfiles = "downloaddictionaryfiles"; + public static final String managedictionary = "managedictionary"; + public static final String naming = "naming"; + public static final String changenames = "changenames"; + public static final String keepprojectswindowsopen = "keepprojectswindowsopen"; + public static final String showprojectswindownoopenproject = "showprojectswindownoopenproject"; + public static final String showpreview = "showpreview"; + public static final String shownotes = "shownotes"; + public static final String lookandsound = "lookandsound"; + public static final String interfacelayout = "interfacelayout"; + public static final String interfacelayouts = "interfacelayouts"; + public static final String showtoolbar = "showtoolbar"; + public static final String belowsidebar = "belowsidebar"; + public static final String abovesidebar = "abovesidebar"; + public static final String showtabs = "showtabs"; + public static final String showtabstop = "showtabstop"; + public static final String showtabsbottom = "showtabsbottom"; + public static final String whenfind = "whenfind"; + public static final String expandall = "expandall"; + public static final String justchapter = "justchapter"; + public static final String playtypewritersound = "playtypewritersound"; + public static final String usesound = "usesound"; + public static final String selectownwavfile = "selectownwavfile"; + public static final String highlightdividers = "highlightdividers"; + public static final String filter = "filter"; + public static final String newasset = "newasset"; + public static final String alwayspopup = "alwayspopup"; + public static final String popupifpossible = "popupifpossible"; + public static final String owntab = "owntab"; + public static final String editassetconfig = "editassetconfig"; + public static final String addtype = "addtype"; + public static final String projectandbackup = "projectandbackup"; + public static final String selectprojectdir = "selectprojectdir"; + public static final String all = "all"; + public static final String autobackup = "autobackup"; + public static final String createbackupafter = "createbackupafter"; + public static final String nobackupstokeep = "nobackupstokeep"; + public static final String selectbackupdir = "selectbackupdir"; + public static final String link = "link"; + public static final String savepropertyerror = "savepropertyerror"; + public static final String changeprojectdir = "changeprojectdir"; + public static final String backupdirchangewarning = "backupdirchangewarning"; + public static final String reopenproject = "reopenproject"; + public static final String dirnotempty = "dirnotempty"; + public static final String backupdirnotempty = "backupdirnotempty"; + public static final String changebackupdir = "changebackupdir"; + public static final String usedefault = "usedefault"; + public static final String examplechapter = "examplechapter"; + public static final String uilanguage = "uilanguage"; + //public static final String select = "select"; + public static final String downloading = "downloading"; + public static final String restartwarning = "restartwarning"; + public static final String set = "set"; + public static final String createtranslation = "createtranslation"; + public static final String edittranslation = "edittranslation"; + public static final String feedback = "feedback"; + public static final String switchtoversion = "switchtoversion"; + public static final String comment = "comment"; + public static final String unsentcommentspopup = "unsentcommentspopup"; + public static final String unsentcomments = "unsentcomments"; + public static final String editcomment = "editcomment"; + public static final String viewertitle = "viewertitle"; + public static final String viewertitleversionwrapper = "viewertitleversionwrapper"; + public static final String previouscontact = "previouscontact"; + public static final String viewcomment = "viewcomment"; + public static final String auto = "auto"; + public static final String login = "login"; + public static final String messages = "messages"; + public static final String undealtwith = "undealtwith"; + public static final String reasons = "reasons"; + public static final String updateinfotoall = "updateinfotoall"; + public static final String updateinfotocontact = "updateinfotocontact"; + public static final String sendmessagetocontact = "sendmessagetocontact"; + public static final String invitesent = "invitesent"; + public static final String sendprojectoninvite = "sendprojectoninvite"; + public static final String sendinvite = "sendinvite"; + public static final String editoroffline = "editoroffline"; + public static final String deleteaccount = "deleteaccount"; + public static final String deletealleditorprojects = "deletealleditorprojects"; + public static final String deleteprojectsforeditor = "deleteprojectsforeditor"; + public static final String avatar = "avatar"; + public static final String accept = "accept"; + public static final String reject = "reject"; + public static final String updated = "updated"; + public static final String sendproject = "sendproject"; + public static final String updateproject = "updateproject"; + public static final String firstupdatewithversion = "firstupdatewithversion"; + public static final String firstupdate = "firstupdate"; + public static final String lastupdatewithversion = "lastupdatewithversion"; + public static final String lastupdate = "lastupdate"; + public static final String sendorupdateproject = "sendorupdateproject"; + public static final String nochapters = "nochapters"; + public static final String unsavedchanges = "unsavedchanges"; + public static final String dueby = "dueby"; + public static final String updatesuffix = "updatesuffix"; + public static final String version = "version"; + public static final String editorstatus = "editorstatus"; + public static final String sendunsentcomments = "sendunsentcomments"; + public static final String comments = "comments"; + public static final String reportmessage = "reportmessage"; + public static final String from = "from"; + public static final String reason = "reason"; + public static final String changepassword = "changepassword"; + public static final String newpassword = "newpassword"; + public static final String register = "register"; + public static final String exists = "exists"; + public static final String savepasswordwarningpopup = "savepasswordwarningpopup"; + public static final String prefix = "prefix"; + public static final String invalidcredentials = "invalidcredentials"; + public static final String alreadyregistered = "alreadyregistered"; + public static final String agreetandc = "agreetandc"; + public static final String viewtandc = "viewtandc"; + public static final String youremail = "youremail"; + public static final String alreadyinvited = "alreadyinvited"; + public static final String previousrejected = "previousrejected"; + public static final String inviteeditor = "inviteeditor"; + public static final String invite = "invite"; + public static final String noemail = "noemail"; + public static final String self = "self"; + public static final String showprojectscontactisediting = "showprojectscontactisediting"; + public static final String showprojectseditingforcontact = "showprojectseditingforcontact"; + public static final String commentssent = "commentssent"; + public static final String commentsreceived = "commentsreceived"; + public static final String important = "important"; + public static final String suffix = "suffix"; + public static final String projectupdated = "projectupdated"; + public static final String inactiveaccount = "inactiveaccount"; + public static final String maxloginattempts = "maxloginattempts"; + public static final String deleteinvite = "deleteinvite"; + public static final String updateinvite = "updateinvite"; + public static final String sendchat = "sendchat"; + public static final String contactistyping = "contactistyping"; + public static final String sending = "sending"; + public static final String box = "box"; + public static final String received = "received"; + public static final String response = "response"; + public static final String update = "update"; + public static final String sent = "sent"; + public static final String report = "report"; + public static final String attention = "attention"; + public static final String resendinvite = "resendinvite"; + public static final String allmessages = "allmessages"; + public static final String removecontact = "removecontact"; + public static final String updatecontactinfo = "updatecontactinfo"; + public static final String projectscontactediting = "projectscontactediting"; + public static final String sendupdateproject = "sendupdateproject"; + public static final String viewcommentserror = "viewcommentserror"; + public static final String lastcommentssent = "lastcommentssent"; + public static final String lastcommentsreceived = "lastcommentsreceived"; + public static final String projectsuserediting = "projectsuserediting"; + public static final String projectupdates = "projectupdates"; + public static final String importantmessages = "importantmessages"; + public static final String sendmessage = "sendmessage"; + public static final String unreadchatmessages = "unreadchatmessages"; + public static final String noprojectcomments = "noprojectcomments"; + public static final String projectcomments = "projectcomments"; + public static final String undealtwithmessagecount = "undealtwithmessagecount"; + public static final String projecteditor = "projecteditor"; + public static final String onlinestatus = "onlinestatus"; + public static final String previouseditor = "previouseditor"; + public static final String pendingeditor = "pendingeditor"; + public static final String invitereceived = "invitereceived"; + public static final String currenteditor = "currenteditor"; + public static final String contactinfo = "contactinfo"; + public static final String inviteresponse = "inviteresponse"; + public static final String dealtwith = "dealtwith"; + public static final String rejected = "rejected"; + public static final String accepted = "accepted"; + public static final String contactremoved = "contactremoved"; + public static final String chatmessages = "chatmessages"; + public static final String today = "today"; + public static final String yesterday = "yesterday"; + public static final String sentbyme = "sentbyme"; + public static final String redownload = "redownload"; + public static final String editneededtitle = "editneededtitle"; + public static final String editneedednote = "editneedednote"; + public static final String font = "font"; + public static final String shortcut = "shortcut"; + public static final String projecteditstop = "projecteditstop"; + public static final String newprojectresponse = "newprojectresponse"; + public static final String extra = "extra"; + public static final String clicktoviewproject = "clicktoviewproject"; + public static final String clicktoviewcomments = "clicktoviewcomments"; + public static final String othercomments = "othercomments"; + public static final String item = "item"; + public static final String displaypassword = "displaypassword"; + public static final String resetpassword = "resetpassword"; + public static final String resendaccountconfirmationemail = "resendaccountconfirmationemail"; + public static final String updatenameavatar = "updatenameavatar"; + public static final String previouscontacts = "previouscontacts"; + public static final String preferences = "preferences"; + public static final String logout = "logout"; + public static final String invitesfromothers = "invitesfromothers"; + public static final String allcontacts = "allcontacts"; + public static final String pendinginvites = "pendinginvites"; + public static final String nocontacts = "nocontacts"; + public static final String firstlogin = "firstlogin"; + public static final String savepassword = "savepassword"; + public static final String otherversions = "otherversions"; + public static final String noversion = "noversion"; + public static final String unsent = "unsent"; + public static final String projectsent = "projectsent"; + public static final String viewchapter = "viewchapter"; + public static final String commentspanel = "commentspanel"; + public static final String logindetails = "logindetails"; + public static final String minlength = "minlength"; + public static final String reminderpopup = "reminderpopup"; + public static final String check = "check"; + public static final String selectfolder = "selectfolder"; + public static final String saving = "saving"; + public static final String newcomment = "newcomment"; + public static final String due = "due"; + public static final String latest = "latest"; + public static final String newupdateproject = "newupdateproject"; + public static final String notspecified = "notspecified"; + public static final String projectdeleted = "projectdeleted"; + public static final String previouseditors = "previouseditors"; + public static final String hidepreviouseditors = "hidepreviouseditors"; + public static final String unknownproject = "unknownproject"; + public static final String notinlist = "notinlist"; + public static final String fkfull = "fkfull"; + public static final String frfull = "frfull"; + public static final String gffull = "gffull"; + public static final String defaultchaptername = "defaultchaptername"; + public static final String defaultstatuses = "defaultstatuses"; + public static final String editneededtype = "editneededtype"; + public static final String websiteuilanguage = "websiteuilanguage"; + public static final String startingfolder = "startingfolder"; + public static final String filechooser = "filechooser"; + public static final String extensionfilter = "extensionfilter"; + public static final String supportqw = "supportqw"; + public static final String hideachieved = "hideachieved"; + +} diff --git a/src/com/quollwriter/ui/components/Markup.java b/src/main/java/com/quollwriter/Markup.java similarity index 81% rename from src/com/quollwriter/ui/components/Markup.java rename to src/main/java/com/quollwriter/Markup.java index 3bccf3f6..12c6695a 100644 --- a/src/com/quollwriter/ui/components/Markup.java +++ b/src/main/java/com/quollwriter/Markup.java @@ -1,16 +1,20 @@ -package com.quollwriter.ui.components; +package com.quollwriter; import java.util.*; import javax.swing.*; import javax.swing.text.*; -import com.gentlyweb.utils.*; +import javafx.scene.control.IndexRange; + +import org.fxmisc.richtext.model.*; + +import com.quollwriter.ui.fx.components.TextEditor; public class Markup { - public static String DEFAULT_SEPARATOR = ""; + public static String DEFAULT_SEPARATOR = " "; public static final String B = "b"; public static final String U = "u"; public static final String I = "i"; @@ -103,7 +107,7 @@ public MarkupItem next () false, false, false); - + } else { @@ -185,26 +189,26 @@ public MarkupItem(int start, public void shiftBy (int i) { - + this.start += i; this.end += i; - + if (this.start < 0) { - + this.start = 0; - + } - + if (this.end < 0) { - + this.end = 0; - + } - + } - + public String toString () { @@ -228,7 +232,12 @@ public boolean isStyled () } - public List items = new ArrayList (); + public List items = new ArrayList<> (); + + public Markup () + { + + } public Markup (Markup fromMarkup, int from, @@ -237,21 +246,21 @@ public Markup (Markup fromMarkup, if (fromMarkup == null) { - + return; - + } - + for (MarkupItem mi : fromMarkup.getItems (from, to)) { - + this.items.add (this.createItem (mi)); - + } - + } - + public Markup(String m) { @@ -263,7 +272,7 @@ public Markup(String m) } int lastInd = 0; - + StringTokenizer tt = new StringTokenizer (m, ","); @@ -278,7 +287,7 @@ public Markup(String m) MarkupItem it = new MarkupItem (nt.nextToken (), nt.nextToken ()); - + if (it.start > lastInd) { /* @@ -288,13 +297,13 @@ public Markup(String m) false, false, false); - + this.items.add (dit); */ } - + lastInd = it.end; - + this.items.add (it); } catch (Exception e) @@ -321,47 +330,96 @@ public Markup(Document doc) } } - + + public Markup (TextEditor ed) + { + + StyleSpans ss = ed.getStyleSpans (0, ed.getText ().length ()); + + int from = 0; + + for (StyleSpan s : ss) + { + + TextEditor.TextStyle t = s.getStyle (); + + if ((t.isBold ()) + || + (t.isUnderline ()) + || + (t.isItalic ()) + ) + { + + this.items.add (new MarkupItem (from, + from + s.getLength (), + t.isBold (), + t.isItalic (), + t.isUnderline ())); + + } + + from += s.getLength (); + + } + + } + + public void addItem (int start, + int end, + boolean isBold, + boolean isItalic, + boolean isUnderline) + { + + this.items.add (new MarkupItem (start, + end, + isBold, + isItalic, + isUnderline)); + + } + public void shiftBy (int i) { - + for (MarkupItem it : items) { - + it.shiftBy (i); - + } - + } - + public String markupAsHTML (String text) { - + return this.markupAsHTML (text, DEFAULT_SEPARATOR); - + } - + public String markupAsHTML (String text, String sep) { if (text == null) { - + return ""; - + } - + if (this.items.size () == 0) { - + return text; - + } - + StringBuilder ct = new StringBuilder (); - + Markup.MarkupItem last = null; for (MarkupItem item : this.items) @@ -372,32 +430,32 @@ public String markupAsHTML (String text, (item.start > 0) ) { - + // Got some unstyled text at the start. ct.append (text.substring (0, item.start)); - + } - + if ((last != null) && (item.start > last.end) ) { - + // Got some unstyled text in the middle of two items. ct.append (text.substring (last.end, item.start)); - + } - + int end = Math.min (item.end, text.length ()); - + String st = text.substring (item.start, end); boolean styled = item.isStyled (); - + if (styled) { @@ -405,7 +463,7 @@ public String markupAsHTML (String text, ct.append (item.getStyles (sep)); ct.append ("\">"); - ct.append (StringUtils.replaceString (st, + ct.append (Utils.replaceString (st, String.valueOf ('\n'), "
    ")); @@ -414,28 +472,28 @@ public String markupAsHTML (String text, } else { ct.append (st); - + } - + last = item; - + } - + if ((last != null) && (last.end < text.length ()) ) { - + // Got some unstyled text at the end. ct.append (text.substring (last.end)); - + } return ct.toString (); - + } - + private void applyStyle (DefaultStyledDocument doc, Object style, int start, @@ -445,17 +503,52 @@ private void applyStyle (DefaultStyledDocument doc, MutableAttributeSet attrs = new SimpleAttributeSet (); attrs.addAttribute (style, true); - + doc.setCharacterAttributes (start, end - start, attrs, false); - + + } + + public void apply (TextEditor ed) + { + + for (MarkupItem i : this.items) + { + + // TODO Put all 3 calls together? + if (i.bold) + { + + ed.setBold (new IndexRange (i.start, + i.end)); + + } + + if (i.italic) + { + + ed.setItalic (new IndexRange (i.start, + i.end)); + + } + + if (i.underline) + { + + ed.setUnderline (new IndexRange (i.start, + i.end)); + + } + + } + } - + public void apply (DefaultStyledDocument doc) { - + for (MarkupItem i : items) { @@ -497,11 +590,56 @@ public void apply (DefaultStyledDocument doc) } - } - + } + + } + + public void apply (com.quollwriter.ui.components.QTextEditor ed) + { + + for (MarkupItem i : items) + { + + try + { + + if (i.bold) + { + + ed.applyStyle (StyleConstants.Bold, + i.start, + i.end); + + } + + if (i.italic) + { + + ed.applyStyle (StyleConstants.Italic, + i.start, + i.end); + + } + + if (i.underline) + { + + ed.applyStyle (StyleConstants.Underline, + i.start, + i.end); + + } + + } catch (Exception e) + { + + } + + } + } - - public void apply (QTextEditor ed) + + public void apply (com.quollwriter.ui.fx.swing.QTextEditor ed) { for (MarkupItem i : items) @@ -552,7 +690,7 @@ public Iterator iterator () return new MarkupIterator (this.items); } - */ + */ private void traverseElement (Element el) { @@ -589,10 +727,10 @@ private void traverseElement (Element el) public List getMarkupBetween (int from, int to) { - + return this.getItems (from, to); - + } public List getItems (int from, @@ -610,39 +748,39 @@ public List getItems (int from, (it.start <= to) ) { - + its.add (it); - + continue; - + } - + // anything that covers the whole range. if ((it.start <= from) && (it.end >= from) ) { - + its.add (it); - + continue; - + } - + // end between from and to. if ((it.end >= from) && (it.end <= to) ) { - + its.add (it); - + continue; - + } - + } return its; @@ -651,30 +789,30 @@ public List getItems (int from, public MarkupItem createItem (MarkupItem it) { - + return this.createItem (it.start, it.end, it.bold, it.italic, it.underline); - + } - + public MarkupItem createItem (int start, int end, boolean bold, boolean italic, boolean underline) { - + return new MarkupItem (start, end, bold, italic, underline); - + } - + private String formatItems () { @@ -693,11 +831,11 @@ private String formatItems () if (m.types.equals ("")) { - + continue; - + } - + if (b.length () > 0) { diff --git a/src/com/quollwriter/NullOutputStream.java b/src/main/java/com/quollwriter/NullOutputStream.java similarity index 100% rename from src/com/quollwriter/NullOutputStream.java rename to src/main/java/com/quollwriter/NullOutputStream.java diff --git a/src/com/quollwriter/ObjectRefURLStreamHandlerFactory.java b/src/main/java/com/quollwriter/ObjectRefURLStreamHandlerFactory.java similarity index 100% rename from src/com/quollwriter/ObjectRefURLStreamHandlerFactory.java rename to src/main/java/com/quollwriter/ObjectRefURLStreamHandlerFactory.java diff --git a/src/com/quollwriter/ProjectDictionaryProvider.java b/src/main/java/com/quollwriter/ProjectDictionaryProvider.java similarity index 99% rename from src/com/quollwriter/ProjectDictionaryProvider.java rename to src/main/java/com/quollwriter/ProjectDictionaryProvider.java index 8e5d3460..82dbcbd5 100644 --- a/src/com/quollwriter/ProjectDictionaryProvider.java +++ b/src/main/java/com/quollwriter/ProjectDictionaryProvider.java @@ -6,7 +6,7 @@ import com.quollwriter.ui.events.*; -import com.quollwriter.ui.components.*; +import com.quollwriter.ui.fx.*; import com.quollwriter.text.*; import com.softcorporation.suggester.util.Constants; diff --git a/src/com/quollwriter/QWSpellDictionaryHashMap.java b/src/main/java/com/quollwriter/QWSpellDictionaryHashMap.java similarity index 78% rename from src/com/quollwriter/QWSpellDictionaryHashMap.java rename to src/main/java/com/quollwriter/QWSpellDictionaryHashMap.java index e8274439..944a76df 100644 --- a/src/com/quollwriter/QWSpellDictionaryHashMap.java +++ b/src/main/java/com/quollwriter/QWSpellDictionaryHashMap.java @@ -35,9 +35,9 @@ public void removeWord (String word) if (list == null) { - + return; - + } list.removeElement (word); @@ -51,6 +51,33 @@ public void removeWord (String word) } + public Set getWords () + { + + Set ret = new TreeSet<> (); + + Collection vs = mainDictionary.values (); + + Iterator iter = vs.iterator (); + + while (iter.hasNext ()) + { + + Vector v = (Vector) iter.next (); + + for (int i = 0; i < v.size (); i++) + { + + ret.add (v.get (i).toString ()); + + } + + } + + return ret; + + } + public void saveDictionaryToFile (File f) throws Exception { diff --git a/src/main/java/com/quollwriter/QuollWriterUpdater.java b/src/main/java/com/quollwriter/QuollWriterUpdater.java new file mode 100644 index 00000000..0c59cce0 --- /dev/null +++ b/src/main/java/com/quollwriter/QuollWriterUpdater.java @@ -0,0 +1,10 @@ +package com.quollwriter; + +import com.quollwriter.ui.fx.viewers.*; + +public interface QuollWriterUpdater +{ + + public void doUpdate (AbstractViewer viewer); + +} diff --git a/src/main/java/com/quollwriter/Startup.java b/src/main/java/com/quollwriter/Startup.java new file mode 100644 index 00000000..b1d9815e --- /dev/null +++ b/src/main/java/com/quollwriter/Startup.java @@ -0,0 +1,246 @@ +package com.quollwriter; + +import java.io.*; +import java.nio.channels.*; + +import java.util.*; + +//import com.quollwriter.data.*; + +import com.quollwriter.ui.fx.*; +import com.quollwriter.ui.fx.components.*; +import com.quollwriter.ui.fx.popups.*; +import javafx.stage.*; +import javafx.application.*; +import javafx.beans.property.*; + +import javafx.scene.*; +import javafx.scene.control.*; + +//import de.codecentric.centerdevice.javafxsvg.*; +//import de.codecentric.centerdevice.javafxsvg.dimension.*; + +import static com.quollwriter.uistrings.UILanguageStringsManager.getUILanguageStringProperty; +import static com.quollwriter.LanguageStrings.*; + +public class Startup extends Application +{ + + private Splashscreen ss = null; + + @Override + public void init () + { + + } + + public void updateProgress (double v) + { + + UIUtils.runLater (() -> + { + + if (ss != null) + { + + //ss.updateProgress (v); + + } + + }); + + } + + public void finish () + { + + UIUtils.runLater (() -> + { + + if (ss != null) + { + + ss.finish (); + + } + + }); + + } + + @Override + public void start (Stage s) + { + + //Platform.setImplicitExit (false); + + try + { + + this.ss = Splashscreen.builder ().build (); + + this.ss.show (); + + javafx.geometry.Rectangle2D rb = Screen.getPrimary ().getBounds (); + + this.ss.setX (((rb.getWidth () - this.ss.getWidth ()) / 2)); + this.ss.setY (((rb.getHeight () - this.ss.getHeight ()) / 2)); + + this.updateProgress (0.2d); + + } catch (Exception e) { + + //e.printStackTrace (); + + } + + Thread t = new Thread (() -> + { + + try + { + + Environment.init (this.ss.progressProperty (), + () -> + { + + try + { + + Environment.setHostServices (this.getHostServices ()); + + Environment.incrStartupProgress (); + + if (Environment.isFirstUse ()) + { + + new FirstUseWizard ().show (); + + this.finish (); + + return; + + } + + if (Environment.getAllProjectInfos ().size () == 0) + { + + this.finish (); + + Environment.showAllProjectsViewer (); + + return; + + } + + boolean showError = false; + + if (UserProperties.getAsBoolean (Constants.SHOW_LANDING_ON_START_PROPERY_NAME)) + { + + Environment.showAllProjectsViewer (); + + } + + // See if the user property is to open the last edited project. + if (UserProperties.getAsBoolean (Constants.OPEN_LAST_EDITED_PROJECT_PROPERTY_NAME)) + { + + try + { + + if (!Environment.openLastEditedProject ()) + { + + showError = true; + + } + + } catch (Exception e) + { + + showError = true; + + } + + } + + // Need to do this here since, if there is no visible frame (somewhere) then showErrorMessage will throw an error that crashes the jvm... nice... + if (showError) + { + + Environment.showAllProjectsViewer (); + + ComponentUtils.showErrorMessage (getUILanguageStringProperty (startup,cantopenlastprojecterror,text)); + + } + + } catch (Exception e) { + + Environment.logError ("Unable to start up: " + + e); + + ComponentUtils.showErrorMessage (getUILanguageStringProperty (startup,unabletostarterror)); + + } + + }); + + } catch (Exception eee) + { + + if (eee instanceof OverlappingFileLockException) + { + + // We need to show english here since we don't have the ui strings set up yet. + ComponentUtils.showErrorMessage (getUILanguageStringProperty (startup,alreadyrunningerror)); + + } else { + + Environment.logError ("Unable to open Quoll Writer", + eee); + + ComponentUtils.showErrorMessage (getUILanguageStringProperty (startup,unabletostarterror)); + + } + + } catch (Error err) { + + err.printStackTrace (); + + } finally + { + + this.finish (); + + Environment.startupComplete (); + + } + + }); + + t.start (); + + } + + public static void main (String[] argv) + { + + if ((argv != null) && + (argv.length > 0)) + { + + if (argv[0].equals ("_debugMode")) + { + + Environment.setDebugModeEnabled (true); + + } + + } + + Startup.launch (argv); + + } + +} diff --git a/src/main/java/com/quollwriter/Startup_old.java b/src/main/java/com/quollwriter/Startup_old.java new file mode 100644 index 00000000..5e553b9e --- /dev/null +++ b/src/main/java/com/quollwriter/Startup_old.java @@ -0,0 +1,161 @@ +package com.quollwriter; + +import java.io.*; +import java.nio.channels.*; + +import java.util.*; + +import javax.swing.*; + +import com.quollwriter.data.*; + +import com.quollwriter.ui.fx.components.*; + +import static com.quollwriter.LanguageStrings.*; +import static com.quollwriter.uistrings.UILanguageStringsManager.getUILanguageStringProperty; + +public class Startup_old +{ + + public static void main (String[] argv) + { + + if ((argv != null) && + (argv.length > 0)) + { + + if (argv[0].equals ("_debugMode")) + { + + Environment.setDebugModeEnabled (true); + + } + + } + + Splashscreen ss = null; + + try + { + + ss = Splashscreen.builder () + .build (); + + ss.updateProgress (5); + + Environment.init (null, null); + + final Splashscreen _ss = ss; +/* + Environment.startupProgressProperty ().addListener ((p, oldv, newv) -> + { + + _ss.updateProgress (5); + + }); +*/ + if (Environment.isFirstUse ()) + { + + // TODO new FirstUseWizard ().init (); + + return; + + } + + if (Environment.getAllProjects ().size () == 0) + { + + ss.finish (); + + Environment.showAllProjectsViewer (); + + return; + + } + + boolean showError = false; + + if (UserProperties.getAsBoolean (Constants.SHOW_LANDING_ON_START_PROPERY_NAME)) + { + + Environment.showAllProjectsViewer (); + + } + + // See if the user property is to open the last edited project. + if (UserProperties.getAsBoolean (Constants.OPEN_LAST_EDITED_PROJECT_PROPERTY_NAME)) + { + + try + { + + if (!Environment.openLastEditedProject ()) + { + + showError = true; + + } + + } catch (Exception e) + { + + showError = true; + + } + + } + + // Need to do this here since, if there is no visible frame (somewhere) then showErrorMessage will throw an error that crashes the jvm... nice... + if (showError) + { + + Environment.showAllProjectsViewer (); + + QuollPopup.messageBuilder () + .withViewer (Environment.getFocusedViewer ()) + .title (startup,cantopenlastprojecterror,title) + .message (startup,cantopenlastprojecterror,text) + .build (); + + } + + } catch (Exception eee) + { + + if (eee instanceof OverlappingFileLockException) + { + + ComponentUtils.showErrorMessage (Environment.getFocusedViewer (), + getUILanguageStringProperty (startup,alreadyrunningerror)); + //"It appears that Quoll Writer is already running. Please close the other instance before starting Quoll Writer again."); + + + } else { + + Environment.logError ("Unable to open Quoll Writer", + eee); + + ComponentUtils.showErrorMessage (Environment.getFocusedViewer (), + getUILanguageStringProperty (startup,unabletostarterror)); + //"Unable to start Quoll Writer"); + + } + + } finally + { + + if (ss != null) + { + + ss.finish (); + + } + + Environment.startupComplete (); + + } + + } + +} diff --git a/src/main/java/com/quollwriter/StringWithMarkup.java b/src/main/java/com/quollwriter/StringWithMarkup.java new file mode 100644 index 00000000..3330e1ca --- /dev/null +++ b/src/main/java/com/quollwriter/StringWithMarkup.java @@ -0,0 +1,147 @@ +package com.quollwriter; + +import javafx.beans.property.*; + +public class StringWithMarkup +{ + + private String text = null; + private Markup markup = null; + private StringProperty textProp = new SimpleStringProperty (); + private ObjectProperty markupProp = new SimpleObjectProperty<> (); + + public StringWithMarkup (String text, + Markup markup) + { + + this.text = text; + this.markup = markup; + + this.markupProp.setValue (this.markup); + this.textProp.setValue (this.text); + + } + + public StringWithMarkup (String text, + String markup) + { + + this.text = text; + + if (markup != null) + { + + this.markup = new Markup (markup); + + } + + this.markupProp.setValue (this.markup); + this.textProp.setValue (this.text); + + } + + public StringWithMarkup (String text) + { + + this.text = text; + + this.textProp.setValue (this.text); + + } + + public StringProperty textProperty () + { + + return this.textProp; + + } + + public ObjectProperty markupProperty () + { + + return this.markupProp; + + } + + public boolean hasText () + { + + if (this.text == null) + { + + return false; + + } + + return this.text.trim ().length () > 0; + + } + + public void update (StringWithMarkup t) + { + + if (t.getText () != null) + { + + this.text = new String (t.getText ()); + this.textProp.setValue (this.text); + + } + + if (t.getMarkup () != null) + { + + this.markup = new Markup (t.getMarkup ().toString ()); + this.markupProp.setValue (this.markup); + + } + + } + + public void update (String text, + Markup markup) + { + + this.text = text; + this.markup = markup; + this.textProp.setValue (text); + this.markupProp.setValue (markup); + + } + + public String getMarkedUpText () + { + + if (this.text == null) + { + + return null; + + } + + if (this.markup == null) + { + + return this.text; + + } + + return this.markup.markupAsHTML (this.text); + + } + + public String getText () + { + + return this.text; + + } + + public Markup getMarkup () + { + + return this.markup; + + } + +} diff --git a/src/main/java/com/quollwriter/UrlDownloader.java b/src/main/java/com/quollwriter/UrlDownloader.java new file mode 100644 index 00000000..b2ec2afc --- /dev/null +++ b/src/main/java/com/quollwriter/UrlDownloader.java @@ -0,0 +1,324 @@ +package com.quollwriter; + +import java.net.*; +import java.io.*; +import java.nio.file.*; +import java.util.*; +import java.util.function.*; + +public class UrlDownloader +{ + + private URL url = null; + private DownloadListener list = null; + private File toFile = null; + private boolean stop = false; + private boolean inProgress = false; + + private Consumer onError = null; + private BiConsumer onProgress = null; + private Runnable onStop = null; + private Consumer onComplete = null; + + private UrlDownloader (Builder b) + { + + if (b.url == null) + { + + throw new IllegalArgumentException ("Url must be provided."); + + } + + this.url = b.url; + this.onError = b.onError; + this.onProgress = b.onProgress; + this.onComplete = b.onComplete; + this.onStop = b.onStop; + + if (b.saveTo != null) + { + + this.toFile = b.saveTo.toFile (); + + } else { + + try + { + + this.toFile = File.createTempFile (UUID.randomUUID ().toString (), + null); + + } catch (Exception e) { + + Environment.logError ("Unable to download language files, cant create temp file", + e); + + if (this.onError != null) + { + + this.onError.accept (e); + + } + + return; + + } + + this.toFile.deleteOnExit (); + + } + + } + + public UrlDownloader (URL url, + File toFile, + DownloadListener l) + { + + this.url = url; + this.toFile = toFile; + this.list = l; + + } + + public boolean isInProgress () + { + + return this.inProgress; + + } + + public void start () + { + + this.stop = false; + + if (this.inProgress) + { + + return; + + } + + this.inProgress = true; + + final UrlDownloader _this = this; + + new Thread (() -> + { + + InputStream in = null; + OutputStream out = null; + + try + { + + URLConnection conn = _this.url.openConnection (); + + int length = conn.getContentLength (); + + in = new BufferedInputStream (conn.getInputStream ()); + out = new BufferedOutputStream (new FileOutputStream (this.toFile)); + + byte[] buf = new byte[8192]; + + int bRead = -1; + + int total = 0; + + while ((bRead = in.read (buf)) != -1) + { + + if (this.stop) + { + + in.close (); + out.flush (); + out.close (); + + if (this.onStop != null) + { + + this.onStop.run (); + + } + + return; + + } + + total += bRead; + + out.write (buf, + 0, + bRead); + + if (this.onProgress != null) + { + + this.onProgress.accept (total, length); + + } + + if (this.list != null) + { + + this.list.progress (total, + length); + + } + + } + + in.close (); + out.flush (); + out.close (); + + if (this.onComplete != null) + { + + this.onComplete.accept (this.toFile.toPath ()); + + } + + if (this.list != null) + { + + this.list.finished (length); + + } + + } catch (Exception e) { + + if (this.onError != null) + { + + this.onError.accept (e); + + } + + if (this.list != null) + { + + this.list.handleError (e); + + } + + } finally { + + this.inProgress = false; + + try + { + + if (in != null) + { + + in.close (); + + } + + if (out != null) + { + + out.flush (); + out.close (); + + } + + } catch (Exception e) {} + + } + + }).start (); + + } + + public void stop () + { + + this.stop = true; + + } + + public static UrlDownloader.Builder builder () + { + + return new Builder (); + + } + + public static class Builder + { + + private BiConsumer onProgress = null; + private Consumer onError = null; + private Runnable onStop = null; + private Consumer onComplete = null; + private URL url = null; + private Path saveTo = null; + + private Builder () + { + + } + + public UrlDownloader build () + { + + return new UrlDownloader (this); + + } + + public Builder onProgress (BiConsumer on) + { + + this.onProgress =on; + return this; + + } + + public Builder onError (Consumer on) + { + + this.onError = on; + return this; + + } + + public Builder onStop (Runnable r) + { + + this.onStop = r; + return this; + + } + + public Builder onComplete (Consumer on) + { + + this.onComplete = on; + return this; + + } + + public Builder url (URL u) + { + + this.url = u; + return this; + + } + + public Builder saveTo (Path f) + { + + this.saveTo = f; + return this; + + } + + } + +} diff --git a/src/com/quollwriter/UserDictionaryProvider.java b/src/main/java/com/quollwriter/UserDictionaryProvider.java similarity index 78% rename from src/com/quollwriter/UserDictionaryProvider.java rename to src/main/java/com/quollwriter/UserDictionaryProvider.java index e33cc35b..45d152ff 100644 --- a/src/com/quollwriter/UserDictionaryProvider.java +++ b/src/main/java/com/quollwriter/UserDictionaryProvider.java @@ -1,15 +1,18 @@ package com.quollwriter; import java.io.*; +import java.nio.file.*; +import java.nio.charset.*; import java.util.*; +import java.util.stream.*; import com.quollwriter.ui.events.*; -import com.quollwriter.ui.components.*; +import com.quollwriter.ui.fx.*; import com.quollwriter.text.*; -import com.softcorporation.suggester.util.Constants; +//import com.softcorporation.suggester.util.Constants; import com.softcorporation.suggester.util.SpellCheckConfiguration; import com.softcorporation.suggester.Suggestion; import com.softcorporation.suggester.dictionary.BasicDictionary; @@ -20,6 +23,7 @@ public class UserDictionaryProvider implements DictionaryProvider2 private static List listeners = new ArrayList (); + // TODO Use a path private static File file = null; private static QWSpellDictionaryHashMap dict = null; private static SpellChecker checker = null; @@ -40,28 +44,40 @@ public UserDictionaryProvider () final UserDictionaryProvider _this = this; - if (UserDictionaryProvider.file == null) - { + Path userDictFile = DictionaryProvider.getUserDictionaryFilePath (); - File userDictFile = Environment.getUserDictionaryFile (); + String lines = null; - if (!userDictFile.exists ()) - { + // Pre v3 handling. + if (Files.exists (userDictFile)) + { - userDictFile.createNewFile (); + lines = new String (Files.readAllBytes (userDictFile), + StandardCharsets.UTF_8); - } + UserProperties.set (Constants.USER_DICTIONARY_WORDS_PROPERTY_NAME, + lines); + + Files.delete (userDictFile); - UserDictionaryProvider.dict = new QWSpellDictionaryHashMap (userDictFile); + } - UserDictionaryProvider.file = userDictFile; + // Post v3 handling, get from user properties. + lines = UserProperties.get (Constants.USER_DICTIONARY_WORDS_PROPERTY_NAME); - UserDictionaryProvider.spellChecker = new com.swabunga.spell.event.SpellChecker (); + if (lines == null) + { - UserDictionaryProvider.spellChecker.setUserDictionary (this.dict); + lines = ""; } + UserDictionaryProvider.dict = new QWSpellDictionaryHashMap (new StringReader (lines)); + + UserDictionaryProvider.spellChecker = new com.swabunga.spell.event.SpellChecker (); + + UserDictionaryProvider.spellChecker.setUserDictionary (this.dict); + this.checker = new SpellChecker () { @@ -228,6 +244,10 @@ public synchronized void removeWord (String word) UserDictionaryProvider.dict.removeWord (word); + this.saveDictionary (); + +/* +TODO Remove try { @@ -240,13 +260,29 @@ public synchronized void removeWord (String word) e); } - +*/ this.fireDictionaryEvent (new DictionaryChangedEvent (this, DictionaryChangedEvent.WORD_REMOVED, word)); } + public Set getWords () + { + + return UserDictionaryProvider.dict.getWords (); + + } + + private void saveDictionary () + { + + UserProperties.set (Constants.USER_DICTIONARY_WORDS_PROPERTY_NAME, + UserDictionaryProvider.dict.getWords ().stream () + .collect (Collectors.joining ("\n"))); + + } + @Override public synchronized void addWord (String word) { @@ -256,6 +292,9 @@ public synchronized void addWord (String word) UserDictionaryProvider.dict.addWord (word); + this.saveDictionary (); +/* +TODO REmove try { @@ -268,7 +307,7 @@ public synchronized void addWord (String word) e); } - +*/ this.fireDictionaryEvent (new DictionaryChangedEvent (this, DictionaryChangedEvent.WORD_ADDED, word)); diff --git a/src/main/java/com/quollwriter/UserProperties.java b/src/main/java/com/quollwriter/UserProperties.java new file mode 100644 index 00000000..98c53f57 --- /dev/null +++ b/src/main/java/com/quollwriter/UserProperties.java @@ -0,0 +1,2639 @@ +package com.quollwriter; + +import java.io.*; +import java.net.*; +import java.nio.file.*; +import java.time.*; +import java.time.format.*; + +import java.util.stream.*; +import java.util.StringTokenizer; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.HashSet; +import java.util.HashMap; +import java.util.WeakHashMap; +import java.util.LinkedHashSet; +import java.util.Collections; +import java.util.Collection; +import java.util.Set; +import java.util.TreeSet; + +import java.awt.event.*; + +import javafx.collections.*; +import javafx.scene.paint.*; +import javafx.scene.text.*; +import javafx.scene.media.*; +import javafx.scene.control.*; +import javafx.beans.property.SimpleStringProperty; +import javafx.beans.property.SimpleSetProperty; +import javafx.beans.property.SimpleListProperty; +import javafx.beans.property.SimpleIntegerProperty; +import javafx.beans.property.SimpleFloatProperty; +import javafx.beans.property.SimpleBooleanProperty; +import javafx.beans.property.SimpleObjectProperty; +import javafx.beans.property.SimpleDoubleProperty; +import javafx.beans.property.SetProperty; +import javafx.beans.property.ListProperty; + +import org.dom4j.*; +import org.dom4j.tree.*; + +import com.gentlyweb.properties.*; + +import com.quollwriter.data.*; +import com.quollwriter.ui.fx.*; +import com.quollwriter.ui.fx.components.*; +import com.quollwriter.events.*; + +import static com.quollwriter.uistrings.UILanguageStringsManager.getUILanguageStringProperty; +import static com.quollwriter.LanguageStrings.*; + +public class UserProperties +{ + + public static final double DEFAULT_FULL_SCREEN_X_BORDER_WIDTH = 0.3d; //(7f / 100f); + public static final double DEFAULT_FULL_SCREEN_Y_BORDER_WIDTH = 0.3d; //(7f / 100f); + public static final double DEFAULT_FULL_SCREEN_OPACITY = 1d; + + public static final double FULL_SCREEN_X_BORDER_WIDTH_ADJUST_INCR = 0.001d; + public static final double FULL_SCREEN_Y_BORDER_WIDTH_ADJUST_INCR = 0.002d; + public static final double FULL_SCREEN_MIN_X_BORDER_WIDTH = 0.05d; + public static final double FULL_SCREEN_MAX_X_BORDER_WIDTH = 0.4d; + public static final double FULL_SCREEN_MIN_Y_BORDER_WIDTH = 0.05d; + public static final double FULL_SCREEN_MAX_Y_BORDER_WIDTH = 0.4d; + + public static final String DEFAULT_SEPARATOR = "|"; + + private static com.gentlyweb.properties.Properties props = new com.gentlyweb.properties.Properties (); + private static Map listeners = null; + private static Path qwDir = null; + + private static Map mappedBooleanProperties = new HashMap<> (); + private static Map mappedProperties = new HashMap<> (); + private static SimpleStringProperty tabsLocationProp = null; + private static SimpleStringProperty toolbarLocationProp = null; + private static SimpleStringProperty projectInfoFormatProp = null; + private static SimpleObjectProperty editMarkerColorProp = null; + private static SimpleStringProperty sortProjectsByProp = null; + private static ObservableSet userBGImagePaths = null; + //private static SimpleSetProperty userBGImagePathsProp = null; + private static ObservableSet userColors = null; + private static ObservableSet projectStatuses = null; + private static SetProperty projectStatusesProp = null; + private static SimpleStringProperty noProjectStatusProp = null; + private static SimpleStringProperty uiLayoutProp = null; + private static SimpleIntegerProperty chapterAutoSaveTimeProp = null; + private static SimpleBooleanProperty chapterAutoSaveEnabledProp = null; + private static SimpleFloatProperty uiBaseFontSizeProp = null; + private static SimpleObjectProperty uiBaseFontProp = null; + private static SimpleBooleanProperty showEditPositionIconInChapterListProp = null; + private static SimpleBooleanProperty showEditCompleteIconInChapterListProp = null; + private static SimpleBooleanProperty showEditMarkerInChapterProp = null; + private static SimpleBooleanProperty showNotesInChapterListProp = null; + private static SimpleIntegerProperty autoBackupsTimeProp = null; + private static SimpleIntegerProperty backupsToKeepCountProp = null; + private static SimpleBooleanProperty autoBackupsEnabledProp = null; + private static SimpleBooleanProperty keepProjectsWindowWhenProjectOpenedProp = null; + private static ObservableSet fullScreenHeaderControlButtonIds = null; + private static ObservableSet projectViewerHeaderControlButtonIds = null; + private static ObservableSet allProjectsViewerHeaderControlButtonIds = null; + private static ObservableSet warmupViewerHeaderControlButtonIds = null; + private static ObservableSet languageStringsEditorHeaderControlButtonIds = null; + + // Just used in the map above as a placeholder for the listeners. + private static final Object listenerFillObj = new Object (); + + private static SetChangeListener projectStatusesListener = null; + private static SetChangeListener userColorsListener = null; + + private static ObservableSet noteTypes = null; + + private static SimpleObjectProperty editNeededNoteChapterHighlightColorProp = null; + private static SimpleObjectProperty problemFinderBlockHighlightColorProp = null; + private static SimpleObjectProperty problemFinderIssueHighlightColorProp = null; + private static SimpleObjectProperty synonymHighlightColorProp = null; + private static SimpleObjectProperty findHighlightColorProp = null; + private static SimpleObjectProperty editorCommentChapterHighlightColorProp = null; + + private static SimpleDoubleProperty fullScreenXBorderWidthProp = null; + private static SimpleDoubleProperty fullScreenYBorderWidthProp = null; + private static SimpleDoubleProperty fullScreenOpacityProp = null; + private static SimpleObjectProperty fullScreenBackgroundProp = null; + + private static SimpleObjectProperty userStyleSheetProp = null; + + private static SimpleBooleanProperty playSoundOnKeyStrokeProp = null; + private static SimpleObjectProperty keyStrokeSoundPathProp = null; + //private static AudioClip keyStrokeSound = null; + private static javax.sound.sampled.Clip keyStrokeSound = null; + private static byte[] keyStrokeSoundBytes = null; + private static UserDictionaryProvider uiTextDictionaryProv = null; + private static SimpleBooleanProperty autoNightModeProp = null; + private static SimpleObjectProperty autoNightModeToProp = null; + private static SimpleObjectProperty autoNightModeFromProp = null; + private static SimpleBooleanProperty permanentNightModeEnabledProp = null; + + static + { + + UserProperties.listeners = Collections.synchronizedMap (new WeakHashMap<> ()); + + } + + private UserProperties () + { + + } + + public static void init (com.gentlyweb.properties.Properties props) + throws Exception + { + + if (props == null) + { + + throw new NullPointerException ("Properties must be specified"); + + } + + UserProperties.props = props; + + UserProperties.projectInfoFormatProp = UserProperties.createMappedProperty (Constants.PROJECT_INFO_FORMAT, + Constants.DEFAULT_PROJECT_INFO_FORMAT); + UserProperties.tabsLocationProp = UserProperties.createMappedProperty (Constants.TABS_LOCATION_PROPERTY_NAME); + UserProperties.toolbarLocationProp = UserProperties.createMappedProperty (Constants.TOOLBAR_LOCATION_PROPERTY_NAME); + + UserProperties.playSoundOnKeyStrokeProp = new SimpleBooleanProperty (UserProperties.getAsBoolean (Constants.PLAY_SOUND_ON_KEY_STROKE_PROPERTY_NAME)); + + UserProperties.playSoundOnKeyStrokeProp.addListener ((p, oldv, newv) -> + { + + UserProperties.set (Constants.PLAY_SOUND_ON_KEY_STROKE_PROPERTY_NAME, + newv); + + Environment.fireUserProjectEvent (ProjectEvent.Type.typewritersound, + (newv ? ProjectEvent.Action.on : ProjectEvent.Action.off)); + + }); + + UserProperties.keyStrokeSoundPathProp = new SimpleObjectProperty (); + + String sf = UserProperties.get (Constants.KEY_STROKE_SOUND_FILE_PROPERTY_NAME); + + try + { + + UserProperties.setKeyStrokeSoundFilePath ((sf != null ? Paths.get (sf) : null)); + //Utils.getResourceUrl (sf).toURI ()) : null)); + + } catch (Exception e) { + + Environment.logError ("Unable to load key stroke sound from: " + sf, + e); + + } + + UserProperties.keyStrokeSoundPathProp.addListener ((p, oldv, newv) -> + { + + if (newv == null) + { + + UserProperties.remove (Constants.KEY_STROKE_SOUND_FILE_PROPERTY_NAME); + + return; + + } + + UserProperties.set (Constants.KEY_STROKE_SOUND_FILE_PROPERTY_NAME, + newv.toString ()); + + // TODO Add an event? + + }); + + UserProperties.userStyleSheetProp = new SimpleObjectProperty<> (); + + String us = UserProperties.get (Constants.USER_STYLE_SHEET_FILE_NAME_PROPERTY_NAME); + + if (us != null) + { + + Path p = Paths.get (us); + + UserProperties.userStyleSheetProp.setValue (p); + + } + + UserProperties.editMarkerColorProp = new SimpleObjectProperty<> (); + UserProperties.problemFinderBlockHighlightColorProp = new SimpleObjectProperty<> (); + UserProperties.problemFinderIssueHighlightColorProp = new SimpleObjectProperty<> (); + UserProperties.synonymHighlightColorProp = new SimpleObjectProperty<> (); + UserProperties.findHighlightColorProp = new SimpleObjectProperty<> (); + + String col = UserProperties.get (Constants.EDIT_MARKER_COLOR_PROPERTY_NAME); + + UserProperties.editMarkerColorProp.setValue (UIUtils.hexToColor (col)); + + UserProperties.editMarkerColorProp.addListener ((pr, oldv, newv) -> + { + + UserProperties.set (Constants.EDIT_MARKER_COLOR_PROPERTY_NAME, + UIUtils.colorToHex (newv)); + + }); + + UserProperties.editNeededNoteChapterHighlightColorProp = new SimpleObjectProperty<> (); + + col = UserProperties.get (Constants.EDIT_NEEDED_NOTE_CHAPTER_HIGHLIGHT_COLOR_PROPERTY_NAME); + + UserProperties.editNeededNoteChapterHighlightColorProp.setValue (UIUtils.hexToColor (col)); + + UserProperties.editNeededNoteChapterHighlightColorProp.addListener ((pr, oldv, newv) -> + { + + UserProperties.set (Constants.EDIT_NEEDED_NOTE_CHAPTER_HIGHLIGHT_COLOR_PROPERTY_NAME, + UIUtils.colorToHex (newv)); + + }); + + UserProperties.editorCommentChapterHighlightColorProp = new SimpleObjectProperty<> (); + + col = UserProperties.get (Constants.EDITOR_COMMENT_CHAPTER_HIGHLIGHT_COLOR_PROPERTY_NAME); + + UserProperties.editorCommentChapterHighlightColorProp.setValue (UIUtils.hexToColor (col)); + + UserProperties.editorCommentChapterHighlightColorProp.addListener ((pr, oldv, newv) -> + { + + UserProperties.set (Constants.EDITOR_COMMENT_CHAPTER_HIGHLIGHT_COLOR_PROPERTY_NAME, + UIUtils.colorToHex (newv)); + + }); + + UserProperties.permanentNightModeEnabledProp = UserProperties.createMappedBooleanProperty (Constants.NIGHT_MODE_ENABLE_PERMENANTLY_PROPERTY_NAME); + + UserProperties.autoNightModeProp = UserProperties.createMappedBooleanProperty (Constants.AUTO_NIGHT_MODE_ENABLED_PROPERTY_NAME); + + UserProperties.autoNightModeToProp = new SimpleObjectProperty<> (); + UserProperties.autoNightModeFromProp = new SimpleObjectProperty<> (); + + DateTimeFormatter dFormat = DateTimeFormatter.ofPattern ("kk:mm"); + + String v = UserProperties.get (Constants.AUTO_NIGHT_MODE_TO_PROPERTY_NAME); + + if (v != null) + { + + UserProperties.autoNightModeToProp.setValue (LocalTime.parse (v, + dFormat)); + + } + + UserProperties.autoNightModeToProp.addListener ((pr, oldv, newv) -> + { + + String _v = null; + + if (newv != null) + { + + _v = newv.format (dFormat); + + } + + UserProperties.set (Constants.AUTO_NIGHT_MODE_TO_PROPERTY_NAME, + _v); + + }); + + v = UserProperties.get (Constants.AUTO_NIGHT_MODE_FROM_PROPERTY_NAME); + + if (v != null) + { + + UserProperties.autoNightModeFromProp.setValue (LocalTime.parse (v, + dFormat)); + + } + + UserProperties.autoNightModeFromProp.addListener ((pr, oldv, newv) -> + { + + String _v = null; + + if (newv != null) + { + + _v = newv.format (dFormat); + + } + + UserProperties.set (Constants.AUTO_NIGHT_MODE_FROM_PROPERTY_NAME, + _v); + + }); + + col = UserProperties.get (Constants.PROBLEM_FINDER_BLOCK_HIGHLIGHT_COLOR_PROPERTY_NAME); + + UserProperties.problemFinderBlockHighlightColorProp.setValue (UIUtils.hexToColor (col)); + + UserProperties.problemFinderBlockHighlightColorProp.addListener ((pr, oldv, newv) -> + { + + UserProperties.set (Constants.PROBLEM_FINDER_BLOCK_HIGHLIGHT_COLOR_PROPERTY_NAME, + UIUtils.colorToHex (newv)); + + }); + + col = UserProperties.get (Constants.PROBLEM_FINDER_ISSUE_HIGHLIGHT_COLOR_PROPERTY_NAME); + + UserProperties.problemFinderIssueHighlightColorProp.setValue (UIUtils.hexToColor (col)); + + UserProperties.problemFinderIssueHighlightColorProp.addListener ((pr, oldv, newv) -> + { + + UserProperties.set (Constants.PROBLEM_FINDER_ISSUE_HIGHLIGHT_COLOR_PROPERTY_NAME, + UIUtils.colorToHex (newv)); + + }); + + col = UserProperties.get (Constants.SYNONYM_HIGHLIGHT_COLOR_PROPERTY_NAME); + + UserProperties.synonymHighlightColorProp.setValue (UIUtils.hexToColor (col)); + + UserProperties.synonymHighlightColorProp.addListener ((pr, oldv, newv) -> + { + + UserProperties.set (Constants.SYNONYM_HIGHLIGHT_COLOR_PROPERTY_NAME, + UIUtils.colorToHex (newv)); + + }); + + col = UserProperties.get (Constants.FIND_HIGHLIGHT_COLOR_PROPERTY_NAME); + + UserProperties.findHighlightColorProp.setValue (UIUtils.hexToColor (col)); + + UserProperties.findHighlightColorProp.addListener ((pr, oldv, newv) -> + { + + UserProperties.set (Constants.FIND_HIGHLIGHT_COLOR_PROPERTY_NAME, + UIUtils.colorToHex (newv)); + + }); + + UserProperties.uiLayoutProp = UserProperties.createMappedProperty (Constants.UI_LAYOUT_PROPERTY_NAME); + + UserProperties.showEditPositionIconInChapterListProp = UserProperties.createMappedBooleanProperty (Constants.SHOW_EDIT_POSITION_ICON_IN_CHAPTER_LIST_PROPERTY_NAME); + + UserProperties.showEditCompleteIconInChapterListProp = UserProperties.createMappedBooleanProperty (Constants.SHOW_EDIT_COMPLETE_ICON_IN_CHAPTER_LIST_PROPERTY_NAME); + + UserProperties.showEditMarkerInChapterProp = UserProperties.createMappedBooleanProperty (Constants.SHOW_EDIT_MARKER_IN_CHAPTER_PROPERTY_NAME); + + UserProperties.showNotesInChapterListProp = UserProperties.createMappedBooleanProperty (Constants.SHOW_NOTES_IN_CHAPTER_LIST_PROPERTY_NAME); + + UserProperties.autoBackupsEnabledProp = UserProperties.createMappedBooleanProperty (Constants.AUTO_SNAPSHOTS_ENABLED_PROPERTY_NAME); + + UserProperties.keepProjectsWindowWhenProjectOpenedProp = UserProperties.createMappedBooleanProperty (Constants.KEEP_PROJECTS_WINDOW_WHEN_PROJECT_OPENED_PROPERTY_NAME); + + UserProperties.userBGImagePaths = FXCollections.observableSet (new LinkedHashSet<> ()); + + try + { + + UserProperties.initUserBGImagePaths (); + + } catch (Exception e) { + + throw new IOException ("Unable to init user background image paths", + e); + + } + + //UserProperties.userBGImagePathsProp = new SimpleSetProperty<> (UserProperties.userBGImagePaths); + + UserProperties.userBGImagePaths.addListener ((SetChangeListener) (ev) -> + { + + // TODO Is this the best palce for this? The exception gets sort of lost. + try + { + + // Encode as json... + String data = JSONEncoder.encode (UserProperties.userBGImagePaths); + + /* + + Element root = new DefaultElement ("files"); + + for (Path p : UserProperties.userBGImagePaths) + { + + Element el = new DefaultElement ("f"); + el.add (new DefaultCDATA (p.toString ())); + + root.add (el); + + } + + // Get as a string. + String data = DOM4JUtils.elementAsString (root); +*/ + UserProperties.set (Constants.BG_IMAGE_FILES_PROPERTY_NAME, + data); + + } catch (Exception e) { + + Environment.logError ("Unable to update background image files", + e); + + } + + }); + + try + { + + UserProperties.initUserColors (); + + } catch (Exception e) { + + throw new IOException ("Unable to init user colors", + e); + + } + + // Have to do this after startup since it may rely on the user ui language strings. + Environment.startupCompleteProperty ().addListener ((pr, oldv, newv) -> + { + + try + { + + UserProperties.initNoteTypes (); + + } catch (Exception e) { + + Environment.logError ("Unable to init note types", + e); + + } + + }); + + UserProperties.initProjectStatuses (); + + UserProperties.chapterAutoSaveTimeProp = new SimpleIntegerProperty (); + + String val = UserProperties.get (Constants.CHAPTER_AUTO_SAVE_INTERVAL_PROPERTY_NAME); + + if (val != null) + { + + try + { + + UserProperties.chapterAutoSaveTimeProp.setValue (Integer.parseInt (val)); + + } catch (Exception e) { + + UserProperties.chapterAutoSaveTimeProp.setValue (Constants.DEFAULT_CHAPTER_AUTO_SAVE_TIME); + + } + + } + + UserProperties.chapterAutoSaveTimeProp.addListener ((pr, oldv, newv) -> + { + + UserProperties.set (Constants.CHAPTER_AUTO_SAVE_INTERVAL_PROPERTY_NAME, + String.valueOf (newv)); + + }); + + UserProperties.chapterAutoSaveEnabledProp = new SimpleBooleanProperty (); + UserProperties.chapterAutoSaveEnabledProp.setValue (UserProperties.getAsBoolean (Constants.CHAPTER_AUTO_SAVE_ENABLED_PROPERTY_NAME)); + + UserProperties.chapterAutoSaveEnabledProp.addListener ((pr, oldv, newv) -> + { + + UserProperties.set (Constants.CHAPTER_AUTO_SAVE_ENABLED_PROPERTY_NAME, + newv); + + }); + + UserProperties.uiBaseFontSizeProp = new SimpleFloatProperty (); + + AbstractProperty a = UserProperties.props.getPropertyObj (Constants.UI_BASE_FONT_SIZE_PROPERTY_NAME); + + if (a != null) + { + + UserProperties.uiBaseFontSizeProp.setValue (UserProperties.getAsFloat (Constants.UI_BASE_FONT_SIZE_PROPERTY_NAME)); + + } + + UserProperties.uiBaseFontSizeProp.addListener ((pr, oldv, newv) -> + { + + UserProperties.set (Constants.UI_BASE_FONT_SIZE_PROPERTY_NAME, + newv.floatValue ()); + + }); + + UserProperties.uiBaseFontProp = new SimpleObjectProperty<> (); + + String f = UserProperties.get (Constants.UI_BASE_FONT_PROPERTY_NAME); + + //Font font = Font.getDefault (); + + if (f != null) + { + + //font = Font.font (f); + UserProperties.uiBaseFontProp.setValue (Font.font (f)); + + } +/* + if (font == null) + { + + font = Font.getDefault (); + + } +*/ + UserProperties.uiBaseFontProp.addListener ((pr, oldv, newv) -> + { + + UserProperties.set (Constants.UI_BASE_FONT_PROPERTY_NAME, + newv.getName ()); + + }); + + UserProperties.autoBackupsTimeProp = new SimpleIntegerProperty (); + + Integer ival = UserProperties.getAsInt (Constants.AUTO_SNAPSHOTS_TIME_PROPERTY_NAME); + + if (ival != null) + { + + UserProperties.autoBackupsTimeProp.setValue (ival); + + } else { + + UserProperties.autoBackupsTimeProp.setValue (Constants.DEFAULT_CHAPTER_AUTO_SAVE_TIME); + + } + + UserProperties.autoBackupsTimeProp.addListener ((pr, oldv, newv) -> + { + + UserProperties.set (Constants.AUTO_SNAPSHOTS_TIME_PROPERTY_NAME, + newv.intValue ()); + + }); + + UserProperties.backupsToKeepCountProp = new SimpleIntegerProperty (); + + ival = UserProperties.getAsInt (Constants.BACKUPS_TO_KEEP_COUNT_PROPERTY_NAME); + + if (ival != null) + { + + UserProperties.backupsToKeepCountProp.setValue (ival); + + } else { + + UserProperties.backupsToKeepCountProp.setValue (Constants.DEFAULT_BACKUPS_TO_KEEP); + + } + + UserProperties.backupsToKeepCountProp.addListener ((pr, oldv, newv) -> + { + + UserProperties.set (Constants.BACKUPS_TO_KEEP_COUNT_PROPERTY_NAME, + newv.intValue ()); + + }); + + UserProperties.fullScreenXBorderWidthProp = new SimpleDoubleProperty (UserProperties.constrainFullScreenXBorderWidth (UserProperties.getAsFloat (Constants.FULL_SCREEN_BORDER_X_WIDTH_PROPERTY_NAME))); + UserProperties.fullScreenXBorderWidthProp.addListener ((pr, oldv, newv) -> + { + + UserProperties.set (Constants.FULL_SCREEN_BORDER_X_WIDTH_PROPERTY_NAME, + newv.floatValue ()); + + }); + + UserProperties.fullScreenYBorderWidthProp = new SimpleDoubleProperty (UserProperties.constrainFullScreenYBorderWidth (UserProperties.getAsFloat (Constants.FULL_SCREEN_BORDER_Y_WIDTH_PROPERTY_NAME))); + UserProperties.fullScreenYBorderWidthProp.addListener ((pr, oldv, newv) -> + { + + UserProperties.set (Constants.FULL_SCREEN_BORDER_Y_WIDTH_PROPERTY_NAME, + newv.floatValue ()); + + }); + + UserProperties.fullScreenOpacityProp = new SimpleDoubleProperty (0); + Float d = UserProperties.getAsFloat (Constants.FULL_SCREEN_BORDER_OPACITY_PROPERTY_NAME); + + UserProperties.fullScreenOpacityProp.setValue (d != null ? d : DEFAULT_FULL_SCREEN_OPACITY); + UserProperties.fullScreenOpacityProp.addListener ((pr, oldv, newv) -> + { + + UserProperties.set (Constants.FULL_SCREEN_BORDER_OPACITY_PROPERTY_NAME, + newv.floatValue ()); + + }); + + UserProperties.fullScreenBackgroundProp = new SimpleObjectProperty<> (); + + v = UserProperties.get (Constants.FULL_SCREEN_BG_PROPERTY_NAME); + + if (v == null) + { + + v = Constants.DEFAULT_FULL_SCREEN_BG_IMAGE_FILE_NAME; + + } + + try + { + + UserProperties.fullScreenBackgroundProp.setValue (BackgroundObject.createBackgroundObjectForId (v)); + + } catch (Exception e) { + + Environment.logError ("Unable to set background object to: " + + v); + + } + + UserProperties.fullScreenBackgroundProp.addListener ((pr, oldv, newv) -> + { + + String id = null; + + if (newv != null) + { + + BackgroundObject b = new BackgroundObject (); + + try + { + + b.update (newv); + + id = b.getAsString (); + + } catch (Exception e) { + + Environment.logError ("Unable to update full screen background to: " + + newv, + e); + + } + + } + + UserProperties.set (Constants.FULL_SCREEN_BG_PROPERTY_NAME, + id); + + }); + + UserProperties.fullScreenHeaderControlButtonIds = FXCollections.observableSet (new LinkedHashSet<> ()); + + String nt = UserProperties.get (Constants.FULL_SCREEN_HEADER_CONTROL_BUTTON_IDS_PROPERTY_NAME); + + if (nt != null) + { + + StringTokenizer t = new StringTokenizer (nt, + DEFAULT_SEPARATOR); + + while (t.hasMoreTokens ()) + { + + String tok = t.nextToken ().trim (); + + UserProperties.fullScreenHeaderControlButtonIds.add (tok); + + } + + } + + UserProperties.projectViewerHeaderControlButtonIds = FXCollections.observableSet (new LinkedHashSet<> ()); + + nt = UserProperties.get (Constants.PROJECT_VIEWER_HEADER_CONTROL_BUTTON_IDS_PROPERTY_NAME); + + if (nt != null) + { + + StringTokenizer t = new StringTokenizer (nt, + DEFAULT_SEPARATOR); + + while (t.hasMoreTokens ()) + { + + String tok = t.nextToken ().trim (); + + UserProperties.projectViewerHeaderControlButtonIds.add (tok); + + } + + } + + UserProperties.warmupViewerHeaderControlButtonIds = FXCollections.observableSet (new LinkedHashSet<> ()); + + nt = UserProperties.get (Constants.WARMUP_VIEWER_HEADER_CONTROL_BUTTON_IDS_PROPERTY_NAME); + + if (nt != null) + { + + StringTokenizer t = new StringTokenizer (nt, + DEFAULT_SEPARATOR); + + while (t.hasMoreTokens ()) + { + + String tok = t.nextToken ().trim (); + + UserProperties.warmupViewerHeaderControlButtonIds.add (tok); + + } + + } + + UserProperties.languageStringsEditorHeaderControlButtonIds = FXCollections.observableSet (new LinkedHashSet<> ()); + + nt = UserProperties.get (Constants.LANGUAGE_STRINGS_EDITOR_HEADER_CONTROL_BUTTON_IDS_PROPERTY_NAME); + + if (nt != null) + { + + StringTokenizer t = new StringTokenizer (nt, + DEFAULT_SEPARATOR); + + while (t.hasMoreTokens ()) + { + + String tok = t.nextToken ().trim (); + + UserProperties.languageStringsEditorHeaderControlButtonIds.add (tok); + + } + + } + + UserProperties.allProjectsViewerHeaderControlButtonIds = FXCollections.observableSet (new LinkedHashSet<> ()); + + nt = UserProperties.get (Constants.ALL_PROJECTS_VIEWER_HEADER_CONTROL_BUTTONS_IDS_PROPERTY_NAME); + + if (nt != null) + { + + StringTokenizer t = new StringTokenizer (nt, + DEFAULT_SEPARATOR); + + while (t.hasMoreTokens ()) + { + + String tok = t.nextToken ().trim (); + + UserProperties.allProjectsViewerHeaderControlButtonIds.add (tok); + + } + + } + + // TODO Make this configurable + //UserProperties.uiTextDictionaryProv = new UserDictionaryProvider (Constants.ENGLISH); + + } +/* + public static UserDictionaryProvider getUITextDictionaryProvider () + { + + return UserProperties.uiTextDictionaryProv; + + } +*/ + + public static SimpleBooleanProperty keepProjectsWindowWhenProjectOpenedProperty () + { + + return UserProperties.keepProjectsWindowWhenProjectOpenedProp; + + } + + public static SimpleObjectProperty autoNightModeFromProperty () + { + + return UserProperties.autoNightModeFromProp; + + } + + public static SimpleObjectProperty autoNightModeToProperty () + { + + return UserProperties.autoNightModeToProp; + + } + + public static LocalTime getAutoNightModeFromTime () + { + + return UserProperties.autoNightModeFromProp.getValue (); + + } + + public static LocalTime getAutoNightModeToTime () + { + + return UserProperties.autoNightModeToProp.getValue (); + + } + + public static void setAutoNightModeFromTime (LocalTime t) + { + + UserProperties.autoNightModeFromProp.setValue (t); + + } + + public static void setAutoNightModeToTime (LocalTime t) + { + + UserProperties.autoNightModeToProp.setValue (t); + + } + + public static SimpleBooleanProperty permanentNightModeEnabledProperty () + { + + return UserProperties.permanentNightModeEnabledProp; + + } + + public static SimpleBooleanProperty autoNightModeEnabledProperty () + { + + return UserProperties.autoNightModeProp; + + } + + public static void setPermanentlyEnableNightMode (boolean v) + { + + UserProperties.set (Constants.NIGHT_MODE_ENABLE_PERMENANTLY_PROPERTY_NAME, + v); + + } + + public static void setAutoNightModeEnabled (boolean v) + { + + UserProperties.set (Constants.AUTO_NIGHT_MODE_ENABLED_PROPERTY_NAME, + v); + + } + + public static ObservableSet projectViewerHeaderControlButtonIds () + { + + return UserProperties.projectViewerHeaderControlButtonIds; + + } + + public static ObservableSet allProjectsViewerHeaderControlButtonIds () + { + + return UserProperties.allProjectsViewerHeaderControlButtonIds; + + } + + public static ObservableSet warmupViewerHeaderControlButtonIds () + { + + return UserProperties.warmupViewerHeaderControlButtonIds; + + } + + public static ObservableSet fullScreenHeaderControlButtonIds () + { + + return UserProperties.fullScreenHeaderControlButtonIds; + + } + + public static ObservableSet languageStringsEditorHeaderControlButtonIds () + { + + return UserProperties.languageStringsEditorHeaderControlButtonIds; + + } + + public static void setLanguageStringsEditorHeaderControlButtonIds (Set ids) + { + + UserProperties.languageStringsEditorHeaderControlButtonIds.clear (); + UserProperties.languageStringsEditorHeaderControlButtonIds.addAll (ids); + + UserProperties.set (Constants.LANGUAGE_STRINGS_EDITOR_HEADER_CONTROL_BUTTON_IDS_PROPERTY_NAME, + UserProperties.languageStringsEditorHeaderControlButtonIds.stream () + .collect (Collectors.joining (DEFAULT_SEPARATOR))); + + } + + public static void setProjectViewerHeaderControlButtonIds (Set ids) + { + + UserProperties.projectViewerHeaderControlButtonIds.clear (); + UserProperties.projectViewerHeaderControlButtonIds.addAll (ids); + + UserProperties.set (Constants.PROJECT_VIEWER_HEADER_CONTROL_BUTTON_IDS_PROPERTY_NAME, + UserProperties.projectViewerHeaderControlButtonIds.stream () + .collect (Collectors.joining (DEFAULT_SEPARATOR))); + + } + + public static void setAllProjectsViewerHeaderControlButtonIds (Set ids) + { + + UserProperties.allProjectsViewerHeaderControlButtonIds.clear (); + UserProperties.allProjectsViewerHeaderControlButtonIds.addAll (ids); + + UserProperties.set (Constants.ALL_PROJECTS_VIEWER_HEADER_CONTROL_BUTTONS_IDS_PROPERTY_NAME, + UserProperties.allProjectsViewerHeaderControlButtonIds.stream () + .collect (Collectors.joining (DEFAULT_SEPARATOR))); + + } + + public static void setWarmupViewerHeaderControlButtonIds (Set ids) + { + + UserProperties.warmupViewerHeaderControlButtonIds.clear (); + UserProperties.warmupViewerHeaderControlButtonIds.addAll (ids); + + UserProperties.set (Constants.WARMUP_VIEWER_HEADER_CONTROL_BUTTON_IDS_PROPERTY_NAME, + UserProperties.warmupViewerHeaderControlButtonIds.stream () + .collect (Collectors.joining (DEFAULT_SEPARATOR))); + + } + + public static void setFullScreenHeaderControlButtonIds (Set ids) + { + + UserProperties.fullScreenHeaderControlButtonIds.clear (); + UserProperties.fullScreenHeaderControlButtonIds.addAll (ids); + + UserProperties.set (Constants.FULL_SCREEN_HEADER_CONTROL_BUTTON_IDS_PROPERTY_NAME, + UserProperties.fullScreenHeaderControlButtonIds.stream () + .collect (Collectors.joining (DEFAULT_SEPARATOR))); + + } + + public static void setPlaySoundOnKeyStroke (boolean v) + { + + UserProperties.playSoundOnKeyStrokeProp.setValue (v); + + } + + public static void setKeyStrokeSoundFilePath (Path up) + { + + Path p = null; + + if (up == null) + { + + try + { + + p = Utils.getAsPath (Utils.getResourceUrl (Constants.DEFAULT_KEY_STROKE_SOUND_FILE).toURI ()); + + } catch (Exception e) { + + throw new IllegalArgumentException ("Unable to get path for: " + Constants.DEFAULT_KEY_STROKE_SOUND_FILE, + e); + + } + + } else { + + if (Files.exists (up)) + { + + p = up; + + } + + } + + try + { + + UserProperties.keyStrokeSoundBytes = Files.readAllBytes (p); + UserProperties.keyStrokeSoundPathProp.setValue (up); + + } catch (Exception e) { + + Environment.logError ("Unable to set key stroke sound file: " + + p, + e); + + UserProperties.keyStrokeSoundPathProp.setValue (null); + + } + + } + + public static SimpleObjectProperty keyStrokeSoundPathProperty () + { + + return UserProperties.keyStrokeSoundPathProp; + + } + + public static SimpleBooleanProperty playSoundOnKeyStrokeProperty () + { + + return UserProperties.playSoundOnKeyStrokeProp; + + } + + public static boolean isPlaySoundOnKeyStroke () + { + + return UserProperties.playSoundOnKeyStrokeProp.getValue (); + + } + + public static void playKeyStrokeSound () + { + + if (UserProperties.keyStrokeSoundBytes != null) + { + + Environment.schedule (() -> + { + + try + { + + javax.sound.sampled.AudioInputStream audioInputStream = javax.sound.sampled.AudioSystem.getAudioInputStream (new BufferedInputStream (new ByteArrayInputStream (UserProperties.keyStrokeSoundBytes))); + javax.sound.sampled.Clip clip = javax.sound.sampled.AudioSystem.getClip (); + clip.open (audioInputStream); + clip.start (); + audioInputStream.close (); + + } catch (Exception e) { + + e.printStackTrace (); + + } + + }, + -1, + -1); + + } + + } + + + private static double constrainFullScreenXBorderWidth (Float v) + { + + if (v == null) + { + + return DEFAULT_FULL_SCREEN_X_BORDER_WIDTH; + + } + + double d = v.doubleValue (); + + if (d > FULL_SCREEN_MAX_X_BORDER_WIDTH) + { + + d = FULL_SCREEN_MAX_X_BORDER_WIDTH; + + } + + if (d < FULL_SCREEN_MIN_X_BORDER_WIDTH) + { + + d = FULL_SCREEN_MIN_X_BORDER_WIDTH; + + } + + return d; + + } + + private static double constrainFullScreenYBorderWidth (Float v) + { + + if (v == null) + { + + return DEFAULT_FULL_SCREEN_Y_BORDER_WIDTH; + + } + + double d = v.doubleValue (); + + if (d > FULL_SCREEN_MAX_Y_BORDER_WIDTH) + { + + d = FULL_SCREEN_MAX_Y_BORDER_WIDTH; + + } + + if (d < FULL_SCREEN_MIN_Y_BORDER_WIDTH) + { + + d = FULL_SCREEN_MIN_Y_BORDER_WIDTH; + + } + + return d; + + } + + public static Object getFullScreenBackground () + { + + return UserProperties.fullScreenBackgroundProp.getValue (); + + } + + public static void setFullScreenBackground (Object b) + { + + UserProperties.fullScreenBackgroundProp.setValue (b); + + } + + public static SimpleObjectProperty fullScreenBackgroundProperty () + { + + return UserProperties.fullScreenBackgroundProp; + + } + + public static double getFullScreenXBorderWidth () + { + + return UserProperties.fullScreenXBorderWidthProp.getValue (); + + } + + public static SimpleDoubleProperty fullScreenXBorderWidthProperty () + { + + return UserProperties.fullScreenXBorderWidthProp; + + } + + public static double getFullScreenYBorderWidth () + { + + return UserProperties.fullScreenYBorderWidthProp.getValue (); + + } + + public static SimpleDoubleProperty fullScreenYBorderWidthProperty () + { + + return UserProperties.fullScreenYBorderWidthProp; + + } + + public static double getFullScreenOpacity () + { + + return UserProperties.fullScreenOpacityProp.getValue (); + + } + + public static SimpleDoubleProperty fullScreenOpacityProperty () + { + + return UserProperties.fullScreenOpacityProp; + + } + + public static void incrementFullScreenXBorderWidth () + { + + UserProperties.adjustFullScreenXBorderWidth (FULL_SCREEN_X_BORDER_WIDTH_ADJUST_INCR); + + } + + public static void decrementFullScreenXBorderWidth () + { + + UserProperties.adjustFullScreenXBorderWidth (-1 * FULL_SCREEN_X_BORDER_WIDTH_ADJUST_INCR); + + } + + private static void adjustFullScreenXBorderWidth (double incr) + { + + double v = UserProperties.fullScreenXBorderWidthProp.getValue () + incr; + + if ((v <= FULL_SCREEN_MIN_X_BORDER_WIDTH) + || + (v >= FULL_SCREEN_MAX_X_BORDER_WIDTH) + ) + { + + return; + + } + + UserProperties.fullScreenXBorderWidthProp.setValue (v); + + } + + public static void incrementFullScreenYBorderWidth () + { + + UserProperties.adjustFullScreenYBorderWidth (FULL_SCREEN_Y_BORDER_WIDTH_ADJUST_INCR); + + } + + public static void decrementFullScreenYBorderWidth () + { + + UserProperties.adjustFullScreenYBorderWidth (-1 * FULL_SCREEN_Y_BORDER_WIDTH_ADJUST_INCR); + + } + + private static void adjustFullScreenYBorderWidth (double incr) + { + + double v = UserProperties.fullScreenYBorderWidthProp.getValue () + incr; + + if ((v <= FULL_SCREEN_MIN_Y_BORDER_WIDTH) + || + (v >= FULL_SCREEN_MAX_Y_BORDER_WIDTH) + ) + { + + return; + + } + + UserProperties.fullScreenYBorderWidthProp.setValue (v); + + } + + public static void setFullScreenOpacity (double v) + { + + if (v < 0) + { + + v = 0; + + } + + if (v > 1) + { + + v = 1; + + } + + UserProperties.fullScreenOpacityProp.setValue (v); + + } + + public static boolean isAutoBackupsEnabled () + { + + return UserProperties.autoBackupsEnabledProp.getValue (); + + } + + public static void setAutoBackupsEnabled (boolean v) + { + + UserProperties.autoBackupsEnabledProp.setValue (v); + + } + + public static int getAutoBackupsTime () + { + + return UserProperties.autoBackupsTimeProp.getValue (); + + } + + public static void setAutoBackupsTime (long c) + { + + UserProperties.autoBackupsTimeProp.setValue ((int) c); + + } + + public static SimpleIntegerProperty autoBackupsTimeProperty () + { + + return UserProperties.autoBackupsTimeProp; + + } + + public static int getBackupsToKeepCount () + { + + return UserProperties.backupsToKeepCountProp.getValue (); + + } + + public static void setBackupsToKeepCount (int v) + { + + UserProperties.backupsToKeepCountProp.setValue (v); + + } + + public static SimpleIntegerProperty backupsToKeepCountProperty () + { + + return UserProperties.backupsToKeepCountProp; + + } + + public static SimpleFloatProperty uiBaseFontSizeProperty () + { + + return UserProperties.uiBaseFontSizeProp; + + } + + public static void setUIBaseFontSize (double v) + { + + UserProperties.uiBaseFontSizeProp.setValue (v); + + } + + public static float getUIBaseFontSize () + { + + float v = UserProperties.uiBaseFontSizeProp.getValue (); + + if (v == 0) + { + + Label l = new Label (); + // This is an assumption that may not hold. + v = (float) l.getFont ().getSize () * (float) (72f/96f); + + } + + return v; + + } + + public static SimpleObjectProperty uiBaseFontProperty () + { + + return UserProperties.uiBaseFontProp; + + } + + public static void setUIBaseFont (Font f) + { + + UserProperties.uiBaseFontProp.setValue (f); + + } + + public static Font getUIBaseFont () + { + + Font f = UserProperties.uiBaseFontProp.getValue (); + + if (f == null) + { + + f = Font.getDefault (); + + } + + return f; + + } + + public static void setDefaultUILanguageStringsSpellCheckLanguage (String lang) + { + + UserProperties.set (Constants.UI_LANGUAGE_STRINGS_SPELL_CHECK_LANGUAGE_PROPERTY_NAME, + lang); + + } + + public static String getDefaultUILanguageStringsSpellCheckLanguage () + { + + return UserProperties.get (Constants.UI_LANGUAGE_STRINGS_SPELL_CHECK_LANGUAGE_PROPERTY_NAME); + + } + + public static void setDefaultSpellCheckLanguage (String lang) + { + + UserProperties.set (Constants.SPELL_CHECK_LANGUAGE_PROPERTY_NAME, + lang); + + } + + public static String getDefaultSpellCheckLanguage () + { + + String v = UserProperties.get (Constants.SPELL_CHECK_LANGUAGE_PROPERTY_NAME); + + if (("UK English".equals (v)) + || + ("UK English".equals (v)) + ) + { + + v = Constants.ENGLISH; + + } + + return v; + + } + + public static void setChapterAutoSaveEnabled (boolean v) + { + + UserProperties.chapterAutoSaveEnabledProp.setValue (v); + + } + + public static void setChapterAutoSaveTime (int millis) + { + + UserProperties.chapterAutoSaveTimeProp.setValue (millis); + + } + + public static SimpleIntegerProperty chapterAutoSaveTimeProperty () + { + + return UserProperties.chapterAutoSaveTimeProp; + + } + + public static SimpleBooleanProperty chapterAutoSaveEnabledProperty () + { + + return UserProperties.chapterAutoSaveEnabledProp; + + } + + public static void saveDefaultProjectProperty (String name, + String value) + { + + try + { + + Environment.saveDefaultProperty (Project.OBJECT_TYPE, + name, + value); + + } catch (Exception e) + { + + Environment.logError ("Unable to save default " + Project.OBJECT_TYPE + " properties", + e); + + ComponentUtils.showErrorMessage (Environment.getFocusedViewer (), + getUILanguageStringProperty (options,savepropertyerror)); + //"Unable to save default project properties"); + + } + + + } + + public static void saveDefaultProjectProperty (String name, + Boolean value) + { + + try + { + + Environment.saveDefaultProperty (Project.OBJECT_TYPE, + name, + value); + + } catch (Exception e) + { + + Environment.logError ("Unable to save default " + Project.OBJECT_TYPE + " properties", + e); + + ComponentUtils.showErrorMessage (Environment.getFocusedViewer (), + getUILanguageStringProperty (options,savepropertyerror)); + //"Unable to save default project properties"); + + } + + + } + + public static void addNoteType (String t) + { + + UserProperties.noteTypes.add (new SimpleStringProperty (t)); + + } + + public static void removeNoteType (String t) + { + + javafx.beans.property.StringProperty s = null; + + for (javafx.beans.property.StringProperty p : UserProperties.noteTypes) + { + + if (p.getValue ().equals (t)) + { + + s = p; + break; + + } + + } + + UserProperties.noteTypes.remove (s); + + } + + public static javafx.beans.property.StringProperty getNoteTypeProperty (String v) + { + + for (javafx.beans.property.StringProperty p : UserProperties.noteTypes) + { + + if (p.getValue ().equals (v)) + { + + return p; + + } + + } + + return null; + + } + + public static ObservableSet getNoteTypes () + { + + return UserProperties.noteTypes; + + } + + public static ObservableSet getUserColors () + { + + return UserProperties.userColors; + + } + + public static SetProperty projectStatusesProperty () + { + + return UserProperties.projectStatusesProp; + + } + + public static void removeProjectStatus (String val) + { + + if (val == null) + { + + return; + + } + + javafx.beans.property.StringProperty p = UserProperties.getProjectStatus (val); + + if (p != null) + { + + UserProperties.projectStatuses.remove (p); + + p.setValue (null); + + } + + } + + public static javafx.beans.property.StringProperty addProjectStatus (String val) + { + + if (val == null) + { + + return null; + + } + + javafx.beans.property.StringProperty sp = UserProperties.getProjectStatus (val); + + if ((sp != null) + && + (sp != UserProperties.noProjectStatusProp) + ) + { + + return sp; + + } + + sp = new javafx.beans.property.SimpleStringProperty (val); + + sp.addListener ((p, oldv, newv) -> + { + + UserProperties.saveProjectStatuses (); + + }); + + UserProperties.projectStatuses.add (sp); + + return sp; + + } + + public static javafx.beans.property.StringProperty getProjectStatus (String val) + { + + if (val == null) + { + + return UserProperties.noProjectStatusProp; + + } + + return UserProperties.projectStatuses.stream () + .filter (p -> val.equals (p.getValue ())) + .findFirst () + .orElse (UserProperties.noProjectStatusProp); + + } + + public static javafx.beans.property.StringProperty noProjectStatusProperty () + { + + return UserProperties.noProjectStatusProp; + + } + + public static ObservableSet getProjectStatuses () + { + + return UserProperties.projectStatuses; + + } + + private static void initProjectStatuses () + { + + UserProperties.noProjectStatusProp = new SimpleStringProperty (null); + + Set set = new TreeSet<> ((o1, o2) -> o1.get ().toLowerCase ().compareTo (o2.get ().toLowerCase ())); + + UserProperties.projectStatuses = FXCollections.observableSet (set); + + String nt = UserProperties.get (Constants.PROJECT_STATUSES_PROPERTY_NAME); + + if (nt != null) + { + + StringTokenizer t = new StringTokenizer (nt, + DEFAULT_SEPARATOR); + + while (t.hasMoreTokens ()) + { + + String tok = t.nextToken ().trim (); + + UserProperties.addProjectStatus (tok); + + } + + } + + UserProperties.projectStatusesProp = new SimpleSetProperty<> (UserProperties.projectStatuses); + + UserProperties.projectStatusesListener = ev -> + { + + UserProperties.saveProjectStatuses (); + + }; + + // Have to cast here to help out the compiler. + UserProperties.projectStatusesProp.addListener (UserProperties.projectStatusesListener); + + } + + private static void saveProjectStatuses () + { + + UserProperties.set (Constants.PROJECT_STATUSES_PROPERTY_NAME, + UserProperties.projectStatuses.stream () + .map (p -> p.getValue ()) + .collect (Collectors.joining (DEFAULT_SEPARATOR))); + + } + + private static void initUserColors () + throws Exception + { + + UserProperties.userColors = FXCollections.observableSet (new LinkedHashSet<> ()); + + // TODO Use a stream? + String colors = UserProperties.get (Constants.COLOR_SWATCHES_PROPERTY_NAME); + + StringTokenizer t = new StringTokenizer (colors, + ","); + + while (t.hasMoreTokens ()) + { + + String col = t.nextToken ().trim (); + + Color c = null; + + try + { + + c = UIUtils.hexToColor (col); + + } catch (Exception e) { + + Environment.logError ("Invalid color: " + c, + e); + + continue; + + } + + if (c != null) + { + + UserProperties.userColors.add (c); + + } + + } + + UserProperties.userColorsListener = ev -> + { + + UserProperties.set (Constants.COLOR_SWATCHES_PROPERTY_NAME, + UserProperties.userColors.stream () + .map (c -> UIUtils.colorToHex (c)) + .collect (Collectors.joining (","))); + + }; + + UserProperties.userColors.addListener (UserProperties.userColorsListener); + + } + + private static void initNoteTypes () + throws Exception + { + + UserProperties.noteTypes = FXCollections.observableSet (new TreeSet<> ((o1, o2) -> + { + + return o1.getValue ().compareTo (o2.getValue ()); + + })); + + String types = UserProperties.get (Constants.NOTE_TYPES_PROPERTY_NAME); + + if (types == null) + { + + types = getUILanguageStringProperty (notetypes,defaulttypes).getValue (); + + } + + StringTokenizer t = new StringTokenizer (types, + "|"); + + while (t.hasMoreTokens ()) + { + + String ty = t.nextToken ().trim (); + + UserProperties.noteTypes.add (new SimpleStringProperty (ty)); + + } + + UserProperties.noteTypes.addListener ((SetChangeListener) ev -> + { + + UserProperties.set (Constants.NOTE_TYPES_PROPERTY_NAME, + UserProperties.noteTypes.stream () + .map (v -> v.getValue ()) + .collect (Collectors.joining ("|"))); + + }); + + } + + public static void removeUserBGImagePath (Path p) + { + + UserProperties.userBGImagePaths.remove (p); + + } + + public static void addUserBGImagePath (Path p) + { + + UserProperties.userBGImagePaths.add (p); + + } + + private static void initUserBGImagePaths () + throws Exception + { + + String bgFiles = UserProperties.get (Constants.BG_IMAGE_FILES_PROPERTY_NAME); + + if (bgFiles == null) + { + + return; + + } + + // Will be xml. + // Legacy, if starts with Paths.get (el.getTextTrim ())) + .filter (p -> + { + + return ((Files.exists (p)) + && + (!Files.isDirectory (p))); + + }) + .collect (Collectors.toList ())); + + } else { + + // Post v3, JSON. + Object o = JSONDecoder.decode (bgFiles); + + if (o instanceof Collection) + { + + Collection c = (Collection) o; + + UserProperties.userBGImagePaths.addAll (c.stream () + .map (i -> Paths.get (i.toString ())) + .filter (i -> + { + + return ((Files.exists (i)) + && + (!Files.isDirectory (i))); + + }) + .collect (Collectors.toList ())); + + } + + } + + } + + public static void addUserColor (Color c) + { + + UserProperties.userColors.add (c); + + } + + public static void removeUserColor (Color c) + { + + UserProperties.userColors.remove (c); + + } + + public static ObservableSet userColorsProperty () + { + + return UserProperties.userColors; + + } + + public static ObservableSet userBGImagePathsProperty () + { + + return UserProperties.userBGImagePaths; + + } + + public static SimpleStringProperty getMappedStringProperty (String name) + { + + SimpleStringProperty s = UserProperties.mappedProperties.get (name); + + if (s == null) + { + + s = UserProperties.createMappedProperty (name); + + } + + return s; + + } + + public static void setUILayout (String v) + { + + UserProperties.uiLayoutProp.setValue (v); + + } + + public static SimpleStringProperty uiLayoutProperty () + { + + return UserProperties.uiLayoutProp; + + } + + public static URL getDefaultStyleSheetURL () + { + + return UserProperties.class.getResource (Constants.DEFAULT_STYLE_SHEET_FILE_NAME); + + } + + public static SimpleObjectProperty userStyleSheetProperty () + { + + return UserProperties.userStyleSheetProp; + + } + + public static void setUserStyleSheet (Path p) + { + + if (p == null) + { + + UserProperties.remove (Constants.USER_STYLE_SHEET_FILE_NAME_PROPERTY_NAME); + + } else { + + UserProperties.set (Constants.USER_STYLE_SHEET_FILE_NAME_PROPERTY_NAME, + p.toString ()); + + } + + UserProperties.userStyleSheetProp.setValue (p); + + } + + public static Path getUserStyleSheet () + { + + return UserProperties.userStyleSheetProp.getValue (); + + } + + private static SimpleStringProperty createMappedProperty (String name) + { + + return UserProperties.createMappedProperty (name, + null); + + } + + private static SimpleStringProperty createMappedProperty (String name, + String defaultNameOnNull) + { + + String v = UserProperties.get (name); + + if (v == null) + { + + v = UserProperties.get (defaultNameOnNull); + + } + + SimpleStringProperty s = new SimpleStringProperty (v); + UserProperties.mappedProperties.put (name, + s); + + s.addListener ((pr, oldv, newv) -> + { + + UserProperties.set (name, + newv); + + }); + + return s; + + } + + private static SimpleBooleanProperty createMappedBooleanProperty (String name) + { + + boolean v = UserProperties.getAsBoolean (name); + + SimpleBooleanProperty s = new SimpleBooleanProperty (v); + UserProperties.mappedBooleanProperties.put (name, + s); + + return s; + + } + + public static Color getFindHighlightColor () + { + + return UserProperties.findHighlightColorProp.getValue (); + + } + + public static Color getSynonymHighlightColor () + { + + return UserProperties.synonymHighlightColorProp.getValue (); + + } + + public static Color getProblemFinderBlockHighlightColor () + { + + return UserProperties.problemFinderBlockHighlightColorProp.getValue (); + + } + + public static Color getProblemFinderIssueHighlightColor () + { + + return UserProperties.problemFinderIssueHighlightColorProp.getValue (); + + } + + public static Color getEditNeededNoteChapterHighlightColor () + { + + return UserProperties.editNeededNoteChapterHighlightColorProp.getValue (); + + } + + public static Color getEditorCommentChapterHighlightColor () + { + + return UserProperties.editorCommentChapterHighlightColorProp.getValue (); + + } + + public static Color getEditMarkerColor () + { + + return UserProperties.editMarkerColorProp.getValue (); + + } + + public static void setEditMarkerColor (Color col) + { + + UserProperties.editMarkerColorProp.setValue (col); + + } + + public static SimpleObjectProperty editMarkerColorProperty () + { + + return UserProperties.editMarkerColorProp; + + } + + public static SimpleStringProperty projectInfoFormatProperty () + { + + return UserProperties.projectInfoFormatProp; + + } + + public static String getProjectInfoFormat () + { + + return UserProperties.projectInfoFormatProp.getValue (); + + } + + public static void setProjectInfoFormat (String v) + { + + UserProperties.projectInfoFormatProp.setValue (v); + + } + + public static SimpleStringProperty tabsLocationProperty () + { + + return UserProperties.tabsLocationProp; + + } + + // TODO Make an enum. + public static SimpleStringProperty toolbarLocationProperty () + { + + return UserProperties.toolbarLocationProp; + + } + + public static void setToolbarLocation (String loc) + { + + UserProperties.toolbarLocationProp.setValue (loc); + + } + + // TODO Make an enum. + public static void setTabsLocation (String loc) + { + + UserProperties.tabsLocationProp.setValue (loc); + + } + + public static boolean isShowEditPositionIconInChapterList () + { + + return UserProperties.showEditPositionIconInChapterListProp.getValue (); + + } + + public static void setShowEditPositionIconInChapterList (boolean v) + { + + UserProperties.set (Constants.SHOW_EDIT_POSITION_ICON_IN_CHAPTER_LIST_PROPERTY_NAME, + v); + + } + + public static SimpleBooleanProperty showEditPositionIconInChapterListProperty () + { + + return UserProperties.showEditPositionIconInChapterListProp; + + } + + public static boolean isShowNotesInChapterList () + { + + return UserProperties.showNotesInChapterListProp.getValue (); + + } + + public static SimpleBooleanProperty showNotesInChapterListProperty () + { + + return UserProperties.showNotesInChapterListProp; + + } + + public static SimpleBooleanProperty showEditMarkerInChapterProperty () + { + + return UserProperties.showEditMarkerInChapterProp; + + } + + public static boolean isShowEditMarkerInChapter () + { + + return UserProperties.showEditMarkerInChapterProp.getValue (); + + } + + public static void setShowEditMarkerInChapter (boolean v) + { + + UserProperties.set (Constants.SHOW_EDIT_MARKER_IN_CHAPTER_PROPERTY_NAME, + v); + + } + + public static boolean isShowEditCompleteIconInChapterList () + { + + return UserProperties.showEditCompleteIconInChapterListProp.getValue (); + + } + + public static void setShowEditCompleteIconInChapterList (boolean v) + { + + UserProperties.set (Constants.SHOW_EDIT_COMPLETE_ICON_IN_CHAPTER_LIST_PROPERTY_NAME, + v); + + } + + public static SimpleBooleanProperty showEditCompleteIconInChapterListProperty () + { + + return UserProperties.showEditCompleteIconInChapterListProp; + + } + + public static void removeListener (UserPropertyListener l) + { + + UserProperties.listeners.remove (l); + + } + + /** + * Adds a listener for property events. Warning! This will be a soft reference that can + * disappear so make sure you have a strong reference to your listener. + * + * @param l The listener. + */ + public static void addListener (UserPropertyListener l) + { + + UserProperties.listeners.put (l, + UserProperties.listenerFillObj); + + } + + public static void fireUserPropertyEvent (Object source, + String name, + AbstractProperty prop, + UserPropertyEvent.Type action) + { + + UserProperties.fireUserPropertyEvent (new UserPropertyEvent (source, + name, + prop, + action)); + + } + + public static void fireUserPropertyEvent (final UserPropertyEvent ev) + { + + com.quollwriter.ui.UIUtils.doActionLater (new ActionListener () + { + + public void actionPerformed (ActionEvent aev) + { + + Set ls = null; + + // Get a copy of the current valid listeners. + synchronized (UserProperties.listeners) + { + + ls = new LinkedHashSet<> (UserProperties.listeners.keySet ()); + + } + + for (UserPropertyListener l : ls) + { + + l.propertyChanged (ev); + + } + + } + + }); + + } + + public static void remove (String name) + { + + UserProperties.props.removeProperty (name); + + UserProperties.fireUserPropertyEvent (UserProperties.listenerFillObj, + name, + null, + UserPropertyEvent.Type.removed); + + UserProperties.save (); + + } + + public static void set (String name, + AbstractProperty prop) + { + + UserProperties.props.setProperty (name, + prop); + + UserProperties.fireUserPropertyEvent (UserProperties.listenerFillObj, + name, + prop, + UserPropertyEvent.Type.changed); + + UserProperties.save (); + + } + + public static void set (String name, + String value) + { + + UserProperties.set (name, + new StringProperty (name, + value)); + + SimpleStringProperty p = UserProperties.mappedProperties.get (name); + + if (p == null) + { + + p = UserProperties.createMappedProperty (name); + + } + + if (p != null) + { + + p.setValue (value); + + } + + UserProperties.save (); + + } + + public static void set (String name, + boolean value) + { + + UserProperties.set (name, + new BooleanProperty (name, + value)); + + SimpleBooleanProperty p = UserProperties.mappedBooleanProperties.get (name); + + if (p == null) + { + + p = UserProperties.createMappedBooleanProperty (name); + + } + + if (p != null) + { + + p.setValue (value); + + } + + UserProperties.save (); + + } + + public static void set (String name, + float value) + { + + UserProperties.set (name, + new FloatProperty (name, + value)); + + UserProperties.save (); + + } + + public static void set (String name, + int value) + { + + UserProperties.set (name, + new IntegerProperty (name, + value)); + + UserProperties.save (); + + } + + public static Boolean getAsBoolean (String name, + String defOnNull) + { + + AbstractProperty a = UserProperties.props.getPropertyObj (name); + + if (a == null) + { + + return UserProperties.getAsBoolean (defOnNull); + + } + + return UserProperties.props.getPropertyAsBoolean (name); + + } + + public static Boolean getAsBoolean (String name) + { + + return UserProperties.props.getPropertyAsBoolean (name); + + } + + public static Integer getAsInt (String name, + String defOnNull) + { + + AbstractProperty a = UserProperties.props.getPropertyObj (name); + + if (a == null) + { + + return UserProperties.getAsInt (defOnNull); + + } + + return UserProperties.props.getPropertyAsInt (name); + + } + + public static Integer getAsInt (String name) + { + + return UserProperties.props.getPropertyAsInt (name); + + } + + public static Path getAsFile (String name) + { + + File f = UserProperties.props.getPropertyAsFile (name); + + if (f == null) + { + + return null; + + } + + return f.toPath (); + + } + + public static float getAsFloat (String name, + String defOnNull) + { + + AbstractProperty a = UserProperties.props.getPropertyObj (name); + + if (a == null) + { + + return UserProperties.getAsFloat (defOnNull); + + } + + return UserProperties.props.getPropertyAsFloat (name); + + } + + public static float getAsFloat (String name) + { + + return UserProperties.props.getPropertyAsFloat (name); + + } + + public static String get (String name, + String defOnNull) + { + + AbstractProperty a = UserProperties.props.getPropertyObj (name); + + if (a == null) + { + + return UserProperties.get (defOnNull); + + } + + return UserProperties.props.getProperty (name); + + } + + public static String get (String name) + { + + return UserProperties.props.getProperty (name); + + } + + public static AbstractProperty getProperty (String name) + { + + return UserProperties.props.getPropertyObj (name); + + } + + public static Properties getProperties () + { + + return UserProperties.props; + + } + + private static void save () + { + + try + { + + Environment.saveUserProperties (); + + } catch (Exception e) { + + Environment.logError ("Unable to set user properties", + e); + + } + + } + + public static Path getUserEditorsPropertiesPath () + { + + return Environment.getUserPath (Constants.EDITORS_PROPERTIES_FILE_NAME); + + } + + public static Path getUserDefaultProjectPropertiesPath () + { + + return Environment.getUserPath (Constants.DEFAULT_PROJECT_PROPERTIES_FILE_NAME); + + } + + /** + * No longer used, since properties now stored in projects db. + * This is only used for legacy versions that need to port the properties over + * to the new storage method. + */ + public static Path getUserPropertiesPath () + { + + return Environment.getUserPath (Constants.PROPERTIES_FILE_NAME); + + } + + public static Path getUserObjectTypeNamesPath () + { + + return Environment.getUserPath (Constants.OBJECT_TYPE_NAMES_FILE_NAME); + + } + +} diff --git a/src/main/java/com/quollwriter/Utils.java b/src/main/java/com/quollwriter/Utils.java new file mode 100644 index 00000000..bd689c42 --- /dev/null +++ b/src/main/java/com/quollwriter/Utils.java @@ -0,0 +1,3003 @@ +package com.quollwriter; + +import java.io.*; +import java.awt.event.*; +import java.time.*; +import java.time.temporal.*; +import java.nio.file.*; +import java.text.*; +import java.net.*; +import java.util.jar.*; +import java.util.*; +import java.util.function.*; +import java.util.zip.*; +import java.util.stream.*; +import java.nio.file.*; +import java.nio.charset.*; + +import javax.swing.*; + +import javafx.beans.property.*; + +import org.dom4j.*; +import org.dom4j.tree.*; + +import com.quollwriter.ui.*; + +import com.quollwriter.data.*; +import com.quollwriter.events.*; + +import static com.quollwriter.uistrings.UILanguageStringsManager.getUILanguageStringProperty; +import static com.quollwriter.LanguageStrings.*; + +public class Utils +{ + + public static List newList (Collection l, + T... els) + { + + List ret = new ArrayList<> (); + + if (l != null) + { + + ret.addAll (l); + + } + + if (els != null) + { + + ret.addAll (Arrays.asList (els)); + + } + + return ret; + + } + + public static String getStreamAsString (InputStream in, + Charset ch) + throws Exception + { + + BufferedInputStream _in = new BufferedInputStream (in); + + ByteArrayOutputStream out = new ByteArrayOutputStream (); + + int r = -1; + + byte[] bytes = new byte[65536]; + + while ((r = _in.read (bytes, 0, 65536)) > 0) + { + + out.write (bytes, + 0, + r); + + } + + out.flush (); + out.close (); + _in.close (); + + return (ch != null ? new String (out.toByteArray (), ch) : new String (out.toByteArray ())); + + } + + public static String getFileAsString (File f, + Charset ch) + throws Exception + { + + return Utils.getStreamAsString (new FileInputStream (f), + ch); + + } + + public static String keyStrokeToString (KeyStroke k) + { + + if (k == null) + { + + return null; + + } + + StringBuilder b = new StringBuilder (); + + String m = KeyEvent.getModifiersExText (k.getModifiers ()); + + if (m.length () > 0) + { + + b.append (Utils.replaceString (m.toLowerCase (), + "+", + " ")); + b.append (" "); + + } + + b.append (KeyEvent.getKeyText (k.getKeyCode ()).toUpperCase ()); + + return b.toString (); + + } + + public static List splitString (String str, + String separator) + { + + List ret = new ArrayList<> (); + + if (str == null) + { + + return ret; + + } + + StringTokenizer t = new StringTokenizer (str, + separator); + + while (t.hasMoreTokens ()) + { + + ret.add (t.nextToken ()); + + } + + return ret; + + } + + public static String joinStrings (Collection items, + String separator) + { + + if ((items == null) + || + (items.size () == 0) + ) + { + + return null; + + } + + StringBuilder b = new StringBuilder (); + + Iterator iter = items.iterator (); + + while (iter.hasNext ()) + { + + b.append (iter.next ()); + + if (iter.hasNext ()) + { + + b.append (separator != null ? separator : ", "); + + } + + } + + return b.toString (); + + } + + public static boolean isSubDir (File parent, + File sub) + { + + File p = sub.getParentFile (); + + if (p == null) + { + + return false; + + } + + if (p.equals (parent)) + { + + return true; + + } + + return Utils.isSubDir (parent, + p); + + } + + // TODO Remove. + public static String checkEmail2 (String em) + { + + StringProperty p = Utils.checkEmail (em); + + if (p != null) + { + + return p.getValue (); + + } + + return null; + + } + + public static StringProperty checkEmail (String em) + { + + StringProperty err = getUILanguageStringProperty (LanguageStrings.form, + LanguageStrings.errors, + LanguageStrings.invalidemail); + //"Email does not appear to be valid."; + + if ((em == null) + || + (em.trim ().equals ("")) + ) + { + + return null; + + } + + int ind = em.indexOf ("@"); + + if (ind < 1) + { + + return err; + + } + + int ind2 = em.indexOf (".", + ind + 1); + + if (ind2 < 1) + { + + return err; + + } else { + + if (em.length () - 1 == ind2) + { + + return err; + + } + + } + + return null; + + } + + public static String getStatisticsAsXML (Map stats) + { + + if (stats == null) + { + + return null; + + } + + if (stats.size () == 0) + { + + return null; + + } + + Element root = new DefaultElement (Environment.XMLConstants.stats); + + Iterator iter = stats.keySet ().iterator (); + + while (iter.hasNext ()) + { + + ProjectInfo.Statistic s = iter.next (); + + Object v = stats.get (s); + + if ((s != null) + && + (v != null) + ) + { + + Element stat = new DefaultElement (Environment.XMLConstants.stat); + + root.add (stat); + + stat.addAttribute (Environment.XMLConstants.id, + s.getType ()); + stat.add (new DefaultCDATA (v.toString ())); + + if (v instanceof String) + { + + stat.addAttribute (Environment.XMLConstants.type, + "string"); + + } + + if (v instanceof Number) + { + + stat.addAttribute (Environment.XMLConstants.type, + "number"); + + } + + } + + } + + try + { + + return Utils.getAsXML (root); + + } catch (Exception e) { + + Environment.logError ("Unable to convert element to string for statistics: " + + stats, + e); + + return null; + + } + + } + + public static String getAsXML (Element el) + { + + Document doc = DocumentHelper.createDocument (); + doc.setRootElement (el); + return doc.asXML (); + + } + + public static Map getStatisticsFromXML (String t) + { + + Map ret = new HashMap<> (); + + if (t == null) + { + + return ret; + + } + + Element root = null; + + try + { + + root = DOM4JUtils.stringAsElement (t); + + } catch (Exception e) { + + Environment.logError ("Unable to convert string: " + + t + + " to an element", + e); + + return ret; + + } + + root.elements (Environment.XMLConstants.stat).stream () + .forEach (el -> + { + + try + { + + String val = el.getTextTrim (); + + String id = DOM4JUtils.attributeValue (el, + Environment.XMLConstants.id, + true); + + String type = DOM4JUtils.attributeValue (el, + Environment.XMLConstants.type, + true); + + if (type.equals ("number")) + { + + ret.put (ProjectInfo.Statistic.valueOf (id), + Double.parseDouble (val)); + + } + + if (type.equals ("string")) + { + + ret.put (ProjectInfo.Statistic.valueOf (id), + val); + + } + + } catch (Exception e) { + + Environment.logError ("Unable to get stats info from element: " + + DOM4JUtils.getPath (el), + e); + + } + + }); + + return ret; + + } + + public static Set getFilesFromXML (String t) + { + + Set ret = new LinkedHashSet<> (); + + if (t == null) + { + + return ret; + + } + + Element root = null; + + try + { + + root = DOM4JUtils.stringAsElement (t); + + } catch (Exception e) { + + Environment.logError ("Unable to convert string: " + + t + + " to an element", + e); + + return ret; + + } + + ret.addAll (root.elements (Environment.XMLConstants.file).stream () + .map (el -> Paths.get (el.getTextTrim ())) + .collect (Collectors.toList ())); +/* +TODO Remove + List els = null; + + try + { + + els = JDOMUtils.getChildElements (root, + Environment.XMLConstants.file, + false); + + } catch (Exception e) { + + Environment.logError ("Unable to get child file elements: " + + e); + + return ret; + + } + + // Get the user ones. + for (int i = 0; i < els.size (); i++) + { + + Element el = (Element) els.get (i); + + try + { + + String tf = JDOMUtils.getChildContent (el); + + ret.add (Paths.get (tf)); + + } catch (Exception e) { + + Environment.logError ("Unable to get file info from element: " + + JDOMUtils.getPath (el), + e); + + } + + } +*/ + return ret; + + } + +/* +TODO Remove + public static String getFilesAsXML (Set files) + { + + if (files == null) + { + + return null; + + } + + if (files.size () == 0) + { + + return null; + + } + + Element root = new Element (Environment.XMLConstants.files); + + for (File f : files) + { + + Element fel = new Element (Environment.XMLConstants.file); + + root.addContent (fel); + + fel.addContent (f.getPath ()); + + } + + try + { + + return JDOMUtils.getElementAsString (root); + + } catch (Exception e) { + + Environment.logError ("Unable to convert element to string for files: " + + files, + e); + + return null; + + } + + } +*/ + public static String getFilesAsXML (Set files) + { + + if (files == null) + { + + return null; + + } + + if (files.size () == 0) + { + + return null; + + } + + Element root = new DefaultElement (Environment.XMLConstants.files); + + for (Path f : files) + { + + Element fel = new DefaultElement (Environment.XMLConstants.file); + + root.add (fel); + + fel.add (new DefaultCDATA (f.toString ())); + + } + + try + { + + return Utils.getAsXML (root); + + } catch (Exception e) { + + Environment.logError ("Unable to convert element to string for files: " + + files, + e); + + return null; + + } + + } + + public static void getContentFromURL (final URL url, + final Map headers, + final ActionListener onSuccess, + final ActionListener onError, + final ActionListener onFailure) + { + + new Thread (new Runnable () + { + + public void run () + { + + try + { + + HttpURLConnection conn = (HttpURLConnection) url.openConnection (); + + if (headers != null) + { + + Iterator iter = headers.keySet ().iterator (); + + while (iter.hasNext ()) + { + + String n = iter.next (); + + conn.setRequestProperty (n, + headers.get (n)); + + } + + } + + conn.setRequestMethod ("GET"); + + conn.setDoInput (true); + conn.setDoOutput (true); + conn.connect (); + + // Try and get input stream, not all responses allow it. + InputStream in = null; + + final int resCode = conn.getResponseCode (); + + if (resCode != HttpURLConnection.HTTP_OK) + { + + in = conn.getErrorStream (); + + } else { + + in = conn.getInputStream (); + + } + + byte[] content = null; + + if (in != null) + { + + ByteArrayOutputStream bout = new ByteArrayOutputStream (); + + // Read everything. + byte[] buf = new byte[8192]; + + int count = 0; + + while ((count = in.read (buf, + 0, + 8192)) != -1) + { + + bout.write (buf, + 0, + count); + + } + + bout.flush (); + bout.close (); + in.close (); + + content = bout.toByteArray (); + + } + + final byte[] ret = content; + + conn.disconnect (); + + if (resCode != HttpURLConnection.HTTP_OK) + { + + if (onError != null) + { + + UIUtils.doLater (new ActionListener () + { + + public void actionPerformed (ActionEvent ev) + { + + onError.actionPerformed (new ActionEvent (ret, resCode, "error")); + + } + + }); + + } + + } else { + + if (onSuccess != null) + { + + UIUtils.doLater (new ActionListener () + { + + public void actionPerformed (ActionEvent ev) + { + + onSuccess.actionPerformed (new ActionEvent (ret, resCode, "success")); + + } + + }); + + } + + } + + } catch (final Exception e) { + + if (onFailure != null) + { + + UIUtils.doLater (new ActionListener () + { + + public void actionPerformed (ActionEvent ev) + { + + onFailure.actionPerformed (new ActionEvent (e, 0, "exception")); + + } + + }); + + } + + } + + } + + }).start (); + + } + + public static void postToURL (final URL url, + final Map headers, + final String content, + final BiConsumer onSuccess, + final BiConsumer onError, + final Consumer onFailure, + final UpdateEventListener progressListener) + { + + byte[] bytes = content.getBytes (StandardCharsets.UTF_8); + + Utils.postToURL (url, + headers, + "text/plain", + bytes.length, + new ByteArrayInputStream (bytes), + onSuccess, + onError, + onFailure, + progressListener); + + } + + public static void postToURL (final URL url, + final Map headers, + final Path file, + final BiConsumer onSuccess, + final BiConsumer onError, + final Consumer onFailure, + final UpdateEventListener progressListener) + throws IOException + { + + Utils.postToURL (url, + headers, + "application/octet-steam", + Files.size (file), + Files.newInputStream (file), + onSuccess, + onError, + onFailure, + progressListener); + + } + + public static void postToURL (final URL url, + final Map headers, + final String contentType, + final long contentLength, + final InputStream content, + final BiConsumer onSuccess, + final BiConsumer onError, + final Consumer onFailure, + final UpdateEventListener progressListener) + { + + Environment.scheduleImmediately (() -> + { + + try + { + + HttpURLConnection conn = (HttpURLConnection) url.openConnection (); + + if (headers != null) + { + + Iterator iter = headers.keySet ().iterator (); + + while (iter.hasNext ()) + { + + String n = iter.next (); + + conn.setRequestProperty (n, + headers.get (n)); + + } + + } + + conn.setRequestProperty ("content-type", + contentType); + conn.setRequestProperty ("content-length", + contentLength + ""); + + conn.setRequestMethod ("POST"); + + conn.setDoInput (true); + conn.setDoOutput (true); + conn.connect (); + + int count = 0; + int sent = 0; + + OutputStream out = conn.getOutputStream (); + + byte[] bytes = new byte[8192]; + + while ((count = content.read (bytes, + 0, + 8192)) != -1) + { + + out.write (bytes, + 0, + count); + + sent += count; + + if (progressListener != null) + { + + int _sent = sent; + + Environment.scheduleImmediately (() -> + { + + progressListener.valueUpdated (new UploadProgressEvent (Environment.class, + _sent, + contentLength)); + + }); + + } + + } + + out.flush (); + out.close (); + + if (progressListener != null) + { + + Environment.scheduleImmediately (() -> + { + + progressListener.valueUpdated (new UploadProgressEvent (Environment.class, + contentLength, + contentLength)); + + }); + + } + + // Try and get input stream, not all responses allow it. + InputStream in = null; + + final int resCode = conn.getResponseCode (); + + if (resCode != HttpURLConnection.HTTP_OK) + { + + in = conn.getErrorStream (); + + } else { + + in = conn.getInputStream (); + + } + + String r = null; + + if (in != null) + { + + StringBuilder b = new StringBuilder (); + + BufferedReader bin = new BufferedReader (new InputStreamReader (in)); + + // Read everything. + char chars[] = new char[8192]; + + count = 0; + + while ((count = bin.read (chars, + 0, + 8192)) != -1) + { + + b.append (chars, + 0, + count); + + } + + String s = b.toString (); + + String pref = Constants.JSON_RETURN_PREFIX; //"for(;;);"; + + if (s.startsWith (pref)) + { + + s = s.substring (pref.length ()); + + } + + r = s; + + } + + final String ret = r; + + conn.disconnect (); + + if (resCode != HttpURLConnection.HTTP_OK) + { + + if (onError != null) + { + + Environment.scheduleImmediately (() -> + { + + onError.accept (ret, resCode); + + }); + + } + + } else { + + if (onSuccess != null) + { + + Environment.scheduleImmediately (() -> + { + + onSuccess.accept (ret, resCode); + + }); + + } + + } + + } catch (final Exception e) { + + if (onFailure != null) + { + + Environment.scheduleImmediately (() -> + { + + onFailure.accept (e); + + }); + + } + + } + + }); + + } + + // TODO Use Paths. + public static void addDirToZip (File f, + File dirToWrite) + throws GeneralException + { + + if ((dirToWrite == null) + || + (f == null) + ) + { + + // Naughty but shouldn't happen. + throw new IllegalArgumentException ("Invalid args"); + + } + + if (dirToWrite.isFile ()) + { + + throw new IllegalArgumentException ("To write directory is actually a file: " + + dirToWrite); + + } + + if (f.isDirectory ()) + { + + throw new IllegalArgumentException ("File to write to is a directory: " + + f); + + } + + try + { + + Map env = new HashMap<> (); + env.put ("create", "true"); + + // JDK 12 - FileSystem fs = FileSystems.newFileSystem (f.toPath (), null); + FileSystem fs = FileSystems.newFileSystem (f.toPath ()); + //FileSystem fs = FileSystems.newFileSystem (Paths.get (f.getPath ()).toUri (), env); + + File[] files = dirToWrite.listFiles (); + + for (int i = 0; i < files.length; i++) + { + + Path fp = Paths.get (files[i].toURI ()); + + Path zp = fs.getPath ("/" + files[i].getParentFile ().getName () + "/" + files[i].getName ()); + + Files.createDirectories (zp.getParent ()); + + Files.copy (fp, + zp, + StandardCopyOption.REPLACE_EXISTING); + + } + + } catch (Exception e) { + + throw new GeneralException ("Unable to write dir to file: " + + dirToWrite + + ", file: " + + f, + e); + + } + + } + + // TODO Move to paths. + public static void extractZipFile (File f, + File toDir) + throws GeneralException + { + + if ((toDir == null) + || + (f == null) + ) + { + + // Naughty but shouldn't happen. + throw new IllegalArgumentException ("Invalid args"); + + } + + if (toDir.isFile ()) + { + + throw new IllegalArgumentException ("To directory is actually a file: " + + toDir); + + } + + if (f.isDirectory ()) + { + + throw new IllegalArgumentException ("File to extract is a directory: " + + f); + + } + + if (!f.exists ()) + { + + throw new IllegalArgumentException ("File doesn't exist: " + + f); + + } + + if (!toDir.exists ()) + { + + toDir.mkdirs (); + + } + + ZipFile zf = null; + + try + { + + zf = new ZipFile (f); + + } catch (Exception e) { + + throw new GeneralException ("Unable to open file as a zip file: " + + f, + e); + + } + + try + { + + Enumeration en = zf.entries (); + + while (en.hasMoreElements ()) + { + + ZipEntry ze = (ZipEntry) en.nextElement (); + + String n = ze.getName (); + + File zFile = new File (toDir.getPath () + "/" + n).getCanonicalFile (); + + // Make sure it is a subdirectory. + if (!zFile.getPath ().startsWith (toDir.getCanonicalFile ().getPath ())) + { + + throw new GeneralException ("Invalid zip entry: " + n + ", leads to a new file/directory that is outside of specified to dir: " + + toDir); + + } + + if (ze.isDirectory ()) + { + + if (zFile.isFile ()) + { + + throw new GeneralException ("Invalid zip entry: " + n + ", cannot create directory, a file already exists with that name: " + + zFile); + + } + + if (!zFile.exists ()) + { + + zFile.mkdirs (); + + } + + } else { + + zFile.getParentFile ().mkdirs (); + + InputStream in = null; + + try + { + + in = zf.getInputStream (ze); + + BufferedOutputStream bout = new BufferedOutputStream (new FileOutputStream (zFile)); + + Utils.streamTo (in, + bout, + 4096); + + bout.flush (); + bout.close (); + + } catch (Exception e) { + + throw new GeneralException ("Unable to write zip file entry: " + n + ", to: " + + zFile, + e); + + } finally { + + if (in != null) + { + + in.close (); + + } + + } + + } + + } + + } catch (Exception e) { + + throw new GeneralException ("Unable to extract file: " + + f + + " to: " + + toDir, + e); + + } finally { + + try + { + + zf.close (); + + } catch (Exception e) { + + // Not worth recording, what are we gonna do? + + } + + } + + } + + public static String toString (Collection c, + String sep) + { + + StringBuilder b = new StringBuilder (); + + Iterator iter = c.iterator (); + + while (iter.hasNext ()) + { + + Object o = iter.next (); + + String s = o + ""; + + if (b.length () > 0) + { + + b.append (sep); + + } + + b.append (s); + + } + + return b.toString (); + + } + + public static void writeBytesToFile (File f, + byte[] bytes) + throws IOException + { + + FileOutputStream fos = new FileOutputStream (f); + fos.write (bytes); + fos.close (); + + } + + public static String getFileType (Path f) + { + + if (f == null) + { + + return null; + + } + + if (Files.isDirectory (f)) + { + + return null; + + } + + String fn = f.getFileName ().toString (); + + int ind = fn.lastIndexOf ("."); + + if (ind > -1) + { + + return fn.substring (ind + 1); + + } + + return null; + + } + + public static String getFileType (File f) + { + + if (f == null) + { + + return null; + + } + + if (f.isDirectory ()) + { + + return null; + + } + + int ind = f.getName ().lastIndexOf ("."); + + if (ind > -1) + { + + return f.getName ().substring (ind + 1); + + } + + return null; + + } + + public static String stripEnd (String s) + { + + if (s == null) + { + + return s; + + } + + int end = s.length () - 1; + + for (int i = end; i > -1; i--) + { + + if (!Character.isWhitespace (s.charAt (i))) + { + + return s.substring (0, + i + 1); + + } + + } + + return s; + + } + + public static void printStackTrace () + { + + new Exception ().printStackTrace (); + + } + + public static com.gentlyweb.properties.Properties findPropertyInChain (String name, + com.gentlyweb.properties.Properties props) + { + + if (props.getPropertyNoParent (name) != null) + { + + return props; + + } + + props = props.getParentProperties (); + + while (props != null) + { + + if (props.getPropertyNoParent (name) != null) + { + + return props; + + } + + props = props.getParentProperties (); + + } + + return null; + + } + + public static String getPropertiesIdChain (com.gentlyweb.properties.Properties props) + { + + StringBuilder b = new StringBuilder (); + + b.append (props.getId ()); + + com.gentlyweb.properties.Properties parent = props.getParentProperties (); + + while (parent != null) + { + + b.append (" -> "); + b.append (parent.getId ()); + + parent = parent.getParentProperties (); + + } + + return b.toString (); + + } + + public static String getStackTrace (Throwable e) + { + + StackTraceElement[] els = (e != null ? e.getStackTrace () : new Exception ().getStackTrace ()); + + StringBuilder b = new StringBuilder (); + + b.append (e.getMessage ()); + + for (int i = 0; i < els.length; i++) + { + + b.append (els[i]); + b.append (String.valueOf ('\n')); + + } + + Throwable c = e.getCause (); + + if (c != null) + { + + b.append ("Caused by: " + c.getMessage () + "\n"); + b.append (Utils.getStackTrace (c)); + + } + + return b.toString (); + + } + + public static boolean isToday (Date d) + { + + if (d == null) + { + + return false; + + } + + Calendar now = new GregorianCalendar (); + + Calendar dCal = new GregorianCalendar (); + dCal.setTime (d); + + return (now.get (Calendar.DAY_OF_MONTH) == dCal.get (Calendar.DAY_OF_MONTH)) + && + (now.get (Calendar.MONTH) == dCal.get (Calendar.MONTH)) + && + (now.get (Calendar.YEAR) == dCal.get (Calendar.YEAR)); + + } + + public static boolean isYesterday (Date d) + { + + if (d == null) + { + + return false; + + } + + Calendar now = new GregorianCalendar (); + + // Take off one day. + now.add (Calendar.DAY_OF_MONTH, + -1); + + Calendar dCal = new GregorianCalendar (); + dCal.setTime (d); + + return (now.get (Calendar.DAY_OF_MONTH) == dCal.get (Calendar.DAY_OF_MONTH)) + && + (now.get (Calendar.MONTH) == dCal.get (Calendar.MONTH)) + && + (now.get (Calendar.YEAR) == dCal.get (Calendar.YEAR)); + + } + + public static String formatDate (Date d) + { + + return new SimpleDateFormat (UserProperties.get (Constants.DATE_FORMAT_PROPERTY_NAME)).format (d); + + } + + public static Date getDate (String d) + { + + try + { + + return new SimpleDateFormat (UserProperties.get (Constants.DATE_FORMAT_PROPERTY_NAME)).parse (d); + + } catch (Exception e) + { + + Environment.logError ("Unable to parse date: " + + d + + ", using format: " + + UserProperties.get (Constants.DATE_FORMAT_PROPERTY_NAME), + e); + + return null; + + } + + } + + public static String sanitizeForFilenameKeepCase (String n) + { + + char[] chars = n.toCharArray (); + + StringBuilder b = new StringBuilder (); + + for (int i = 0; i < chars.length; i++) + { + + if ((Character.isLetterOrDigit (chars[i])) + || + (chars[i] == ' ') + || + (chars[i] == '-') + ) + { + + b.append (chars[i]); + + } + + } + + return b.toString ().trim (); + + } + + public static String sanitizeForFilename (String n) + { + + char[] chars = n.toLowerCase ().toCharArray (); + + StringBuilder b = new StringBuilder (); + + for (int i = 0; i < chars.length; i++) + { + + if ((Character.isLetterOrDigit (chars[i])) || + (chars[i] == ' ')) + { + + b.append (chars[i]); + + } + + } + + return b.toString ().trim (); + + } + + public static long getTimeAsMillis (String v) + { + + if (v == null) + { + + return 0; + + } + + // Is this a legacy value, pre 2.6.5? + if (v.indexOf (" ") > 0) + { + + long min = 60000; + + if (v.equals ("5 mins")) + { + + return 5 * min; + + } + + if (v.equals ("10 mins")) + { + + return 10 * min; + + } + + if (v.equals ("20 mins")) + { + + return 20 * min; + + } + + if (v.equals ("30 mins")) + { + + return 30 * min; + + } + + long hour = 60 * min; + + if (v.equals ("1 hour")) + { + + return 1 * hour; + + } + + if (v.equals ("12 hours")) + { + + return 12 * hour; + + } + + if (v.equals ("24 hours")) + { + + return 24 * hour; + + } + + long day = hour * 24; + + if (v.equals ("2 days")) + { + + return 2 * day; + + } + + if (v.equals ("5 days")) + { + + return 5 * day; + + } + + if (v.equals ("1 week")) + { + + return 7 * day; + + } + + } + + try + { + + return Long.parseLong (v); + + } catch (Exception e) { + + Environment.logError ("Unable to parse: " + v + " into a long.", + e); + + } + + return 0; + + } + + @Deprecated + public static void createQuollWriterDirFile (File d) + throws GeneralException + { + + Utils.createQuollWriterDirFile (d.toPath ()); + + } + + public static void createQuollWriterDirFile (Path d) + throws GeneralException + { + + if (Files.notExists (d)) + { + + return; + + } + + if (!Files.isDirectory (d)) + { + + return; + + } + + Utils.writeStringToFile (d.resolve (Constants.QUOLLWRITER_DIR_FILE_NAME), + "This file indicates to quollwriter that the parent directory can be safely deleted or copied."); + + } + + public static boolean isDirectoryEmpty (Path d) + { + + try + { + + if (Files.notExists (d)) + { + + return true; + + } +/* + if (!Files.isDirectory (d)) + { +System.out.println ("RET1: " + d); + return false; + + } +*/ + try (Stream ls = Files.list (d)) + { + + Path p = ls.findFirst () + .orElse (null); + + return p == null; + + } + + } catch (Exception e) { + + Environment.logError ("Unable to determine if path is empty: " + d, + e); + + return false; + + } + + } + + public static boolean isDirectoryEmpty (File d) + { + + if (d == null) + { + + return true; + + } + + if (!d.exists ()) + { + + return true; + + } + + if (d.isFile ()) + { + + return false; + + } + + File[] files = d.listFiles (); + + if ((files != null) + && + (files.length > 0) + ) + { + + return false; + + } + + return true; + + } +/* +TODO REmove + public static File getQuollWriterDirFile (File parent) + { + + return new File (parent.getPath () + "/" + Constants.QUOLLWRITER_DIR_FILE_NAME); + + } +*/ + public static Path getQuollWriterDirFile (Path parent) + { + + return parent.resolve (Constants.QUOLLWRITER_DIR_FILE_NAME); + + } + + public static void copyFilesToDir (Set files, + File to) + throws IOException + { + + if (!to.exists ()) + { + + throw new IllegalArgumentException ("To dir must exist."); + + } + + if (to.isFile ()) + { + + throw new IllegalArgumentException ("To dir is a file."); + + } + + File tof = new File (to.getPath () + "/" + Constants.QUOLLWRITER_DIR_FILE_NAME); + + if (!tof.exists ()) + { + + throw new IllegalArgumentException ("To dir doesn't look like a Quoll Writer dir."); + + } + + for (File f : files) + { + + if (f.isFile ()) + { + + // Create the new file. + File nf = new File (to.getPath (), + f.getName ()); + + if (nf.exists ()) + { + + // Don't overwrite. + continue; + + } + + Files.copy (f.toPath (), + nf.toPath ()); + + } + + } + + } + + public static void copyDir (File from, + File to) + throws IOException + { + + // Only copy directories that have the specified file in it. + File f = new File (from.getPath () + "/" + Constants.QUOLLWRITER_DIR_FILE_NAME); + + if (!f.exists ()) + { + + return; + + } + + if (to.exists ()) + { + + return; + + } + + to.mkdirs (); + + File[] files = from.listFiles (); + + for (int i = 0; i < files.length; i++) + { + + f = files[i]; + + if (f.isFile ()) + { + + // Create the new file. + File nf = new File (to.getPath () + "/" + f.getName ()); + + if (nf.exists ()) + { + + // Don't overwrite. + continue; + + } + + Files.copy (f.toPath (), + nf.toPath ()); + + } else + { + + // Create a new directory. + File nd = new File (to.getPath () + "/" + f.getName ()); + + if (nd.exists ()) + { + + // Ignore. + continue; + + } + + Utils.copyDir (f, + nd); + + } + + } + + } + + public static void deleteDir (Path d) + throws GeneralException + { + + if (d == null) + { + + return; + + } + + if (!Files.isDirectory (d)) + { + + return; + + } + + // See if there is a file that indicates we can delete this directory and its contents. + if (Files.notExists (d.resolve (Constants.QUOLLWRITER_DIR_FILE_NAME))) + { + + return; + + } + + try + { + + // Need the try(){} to auto close the stream. + try (Stream ls = Files.list (d)) + { + + ls.forEach (f -> + { + + if (Files.notExists (f)) + { + + return; + + } + + try + { + + if (Files.isDirectory (f)) + { + + Utils.deleteDir (f); + + } else { + + Files.delete (f); + + } + + } catch (Exception e) { + + throw new RuntimeException ("Unable to delete file: " + f, + e); + + } + + }); + + } + + Files.delete (d); + + } catch (Exception e) { + + throw new GeneralException ("Unable to delete: " + d, + e); + + } + + } +/* + public static void deleteDir (File d) + { + + if (d == null) + { + + return; + + } + + if (d.isFile ()) + { + + return; + + } + + // See if there is a file that indicates we can delete this directory and it's contents. + File canDeleteF = new File (d.getPath () + "/" + Constants.QUOLLWRITER_DIR_FILE_NAME); + + if (!canDeleteF.exists ()) + { + + return; + + } + + // If we are here then we can delete this directory and it's contents. + File[] files = d.listFiles (); + + for (int i = 0; i < files.length; i++) + { + + File f = files[i]; + + if (f.isFile ()) + { + + if (!f.delete ()) + { + + Environment.logError ("Unable to delete file: " + f); + + } + + } else + { + + Utils.deleteDir (f); + + } + + } + + d.delete (); + + } +*/ + public static Date zeroTimeFields (Date d) + { + + GregorianCalendar gc = new GregorianCalendar (); + gc.setTime (d); + + gc.set (Calendar.HOUR_OF_DAY, + 0); + gc.set (Calendar.MINUTE, + 0); + gc.set (Calendar.SECOND, + 0); + gc.set (Calendar.MILLISECOND, + 0); + + return gc.getTime (); + + } + + public static String formatAsDuration (double duration) + { + + long millis = (long) duration; + + long days = 0; + long hours = 0; + long mins = 0; + + long min = 60 * 1000; + long hour = 60 * min; + long day = 24 * hour; + + days = millis / day; + + millis = millis - (day * days); + + hours = millis / hour; + + millis = millis - (hour * hours); + + mins = millis / min; + + StringBuilder b = new StringBuilder (); + + if (days > 0) + { + + b.append (days); + b.append ("d"); + + } + + if (hours > 0) + { + + if (b.length () > 0) + { + + b.append (" "); + + } + + b.append (hours); + b.append ("h"); + + } + + if (mins > 0) + { + + if (b.length () > 0) + { + + b.append (" "); + + } + + b.append (mins); + b.append ("m"); + + } + + if (b.length () == 0) + { + + b.append ("0m"); + + } + + return b.toString (); + + } + + public static Path getAsPath (URI u) + throws IOException + { + + try + { + + FileSystems.getFileSystem (u); + + } catch (FileSystemNotFoundException e) { + + Map env = new HashMap<> (); + env.put ("create", "true"); + FileSystems.newFileSystem (u, env); + + } catch (IllegalArgumentException e) { + + FileSystems.getDefault (); + + } + + return Paths.get (u); + + } + + public static void createZipFile (Path file, + Map entries) + throws GeneralException + { + + URI uri = URI.create ("jar:" + file.toFile ().toURI ().toString ()); + + Map env = new HashMap<>(); + env.put ("create", "true"); + env.put ("encoding", "UTF-8"); + + try + { + + Files.deleteIfExists (file); + + } catch (Exception e) { + + throw new GeneralException ("Unable to delete file: " + file, + e); + + } + + try (FileSystem zipfs = FileSystems.newFileSystem (uri, env)) + { + + for (String k : entries.keySet ()) + { + + Object o = entries.get (k); + + Path zk = zipfs.getPath ((k.startsWith ("/") ? "" : "/") + k); + + Path pzk = zk.getParent (); + + if (pzk != null) + { + + Files.createDirectories (pzk); + + } + + if (o instanceof String) + { + + String s = (String) o; + + Files.copy (new ByteArrayInputStream (s.getBytes (StandardCharsets.UTF_8)), + zk); + + } + + if (o instanceof File) + { + + File f = (File) o; + + Files.copy (Paths.get (f.toURI ()), + zk); + + } + + if (o instanceof Path) + { + + Path p = (Path) o; + + Files.copy (p, + zk); + + } + + } + + } catch (Exception e) { + + throw new GeneralException ("Unable to create/write to zip file: " + file, + e); + + } + + } + + public static String getFileContentAsString (Path f) + throws GeneralException + { + + try + { + + return new String (Files.readAllBytes (f), + StandardCharsets.UTF_8); + + } catch (Exception e) { + + throw new GeneralException ("Unable to get content of file: " + f, + e); + + } + + } + + public static void writeStringToFile (Path f, + String v) + throws GeneralException + { + + try + { + + try (BufferedWriter bw = Files.newBufferedWriter (f, + StandardCharsets.UTF_8)) + { + + bw.write (v, + 0, + v.length ()); + bw.flush (); + bw.close (); + + } + + } catch (Exception e) { + + throw new GeneralException ("Unable to write string to: " + f, + e); + + } + + } + + public static File writeStreamToTempFile (InputStream in) + throws IOException + { + + // TODO Change to use a path. + File f = File.createTempFile ("___" + Constants.QUOLL_WRITER_DIR_NAME + System.currentTimeMillis (), + null); + + BufferedOutputStream bout = new BufferedOutputStream (new FileOutputStream (f)); + + Utils.streamTo (new BufferedInputStream (in), + bout, + 4096); + + bout.flush (); + bout.close (); + + return f; + + } + + public static void extractResourceToFile (String name, + File outFile) + throws GeneralException + { + + try + { + + BufferedInputStream bin = new BufferedInputStream (Environment.class.getResourceAsStream (name)); + + BufferedOutputStream bout = new BufferedOutputStream (new FileOutputStream (outFile)); + + Utils.streamTo (bin, + bout, + 4096); + + } catch (Exception e) + { + + throw new GeneralException ("Unable to stream resource: " + + name + + " to output file: " + + outFile, + e); + + } + + } + + public static Date zeroTimeFieldsForDate (Date d) + { + + GregorianCalendar gc = new GregorianCalendar (); + gc.setTime (d); + + Utils.zeroTimeFields (gc); + + return gc.getTime (); + + } + + public static void zeroTimeFields (GregorianCalendar gc) + { + + // Zero-out the non date fields. + gc.set (Calendar.HOUR_OF_DAY, + 0); + gc.set (Calendar.MINUTE, + 0); + gc.set (Calendar.SECOND, + 0); + gc.set (Calendar.MILLISECOND, + 0); + + } + + public static URL getResourceUrl (String path) + throws Exception + { + + URL u = Environment.class.getResource (path); + + URI ui = null; + + try + { + + ui = u.toURI (); + + } catch (Exception e) { + + throw new IllegalArgumentException ("Unable to convert path: " + path + " to a uri.", + e); + + } +/* + try + { + + FileSystems.getFileSystem (ui); + + } catch (Exception e) { + + Map env = new HashMap<> (); + env.put ("create", "true"); + FileSystems.newFileSystem (ui, env); + + } +*/ + return u; + + } + + /** + * List directory contents for a resource folder. Not recursive. + * This is basically a brute-force implementation. + * Works for regular files and also JARs. + * + * @author Greg Briggs + * @param clazz Any java class that lives in the same place as the resources you want. + * @param path Should end with "/", but not start with one. + * @return Just the name of each member item, not the full paths. + * @throws URISyntaxException + * @throws IOException + */ + public static Set getResourceListing (String path) + throws URISyntaxException, + GeneralException, + IOException + { + + URL dirURL = Environment.class.getResource (path); + + if (dirURL == null) + { + + throw new GeneralException ("Unable to find resource: " + path); + + } + + if (dirURL.getProtocol ().equals ("jar")) + { + + /* A JAR path */ + String jarPath = dirURL.getPath ().substring (5, + dirURL.getPath ().indexOf ("!")); // strip out only the JAR file + + JarFile jar = new JarFile (URLDecoder.decode (jarPath, + "UTF-8")); + + Enumeration entries = jar.entries (); // gives ALL entries in jar + + Set result = new HashSet (); // avoid duplicates in case it is a subdirectory + + while (entries.hasMoreElements ()) + { + + String name = "/" + entries.nextElement ().getName (); + + if (name.startsWith (path)) + { // filter according to the path + + String entry = name.substring (path.length ()); + + if (entry.length () == 0) + { + + continue; + + } + + int checkSubdir = entry.indexOf ("/"); + + if (checkSubdir >= 0) + { + + // if it is a subdirectory, we just return the directory name + entry = entry.substring (0, + checkSubdir); + + } + + result.add (entry); + } + + } + + return result; + + } + + throw new UnsupportedOperationException ("Cannot list files for URL " + dirURL); + } + + public static InputStream getResourceStream (String name) + { + + return Environment.class.getResourceAsStream (name); + + } + + public static String getResourceFileAsString (String name) + throws GeneralException + { + + // TODO Change this... + InputStream is = Utils.getResourceStream (name); + + if (is == null) + { + + return null; + + } + + StringBuilder b = new StringBuilder (); + + BufferedReader r = null; + + try + { + + r = new BufferedReader (new InputStreamReader (is, "utf-8")); + + String line = r.readLine (); + + while (line != null) + { + + b.append (line); + b.append ('\n'); + + line = r.readLine (); + + } + + } catch (Exception e) + { + + throw new GeneralException ("Unable to read from resource: " + + name, + e); + + } finally + { + + // Oh how I hate this... + try + { + + if (r != null) + { + + r.close (); + + } + + } catch (Exception e) + { + + // Ignore... What could we do otherwise? + + } + + } + + return b.toString (); + + } + + // TODO: Change to use a new thread. + public static String getUrlFileAsString (URL url) + throws Exception + { + + URLConnection c = url.openConnection (); + + InputStream bin = c.getInputStream (); + + return Utils.getStreamAsString (bin, + StandardCharsets.UTF_8); + + } + + public static int getPercent (float t, + float b) + { + + if (b == 0) + { + + return 0; + + } + + return (int) ((t / b) * 100); + + } + + public static LocalDate dateToLocalDate (Date d) + { + + LocalDate ld = null; + + if (d != null) + { + + ld = Instant.ofEpochMilli (d.getTime ()) + .atZone (ZoneId.systemDefault ()) + .toLocalDate (); + //ld = LocalDate.from (i); + + } + + return ld; + + } + + public static Date localDateToDate (LocalDate d) + { + + if (d == null) + { + + return null; + + } + + return Date.from (d.atStartOfDay (ZoneId.systemDefault ()).toInstant ()); + + } + + public static boolean isProjectDir (Path p) + { + + Path pf = p.resolve (Constants.PROJECT_DB_FILE_NAME_PREFIX + Constants.H2_DB_FILE_SUFFIX); + + if ((Files.exists (pf)) + && + (!Files.isDirectory (pf)) + ) + { + + return true; + + } + + return false; + + } + + public static boolean isBackupFile (Path p) + throws IOException + { + + if (Files.isDirectory (p)) + { + + return false; + + } + + if (Files.notExists (p)) + { + + return false; + + } + + String fn = p.getFileName ().toString (); + + if ((!fn.startsWith (Constants.BACKUP_FILE_NAME_PREFIX)) + || + (!fn.endsWith (Constants.BACKUP_FILE_NAME_SUFFIX)) + ) + { + + return false; + + } + + // JDK 12 - FileSystem fs = FileSystems.newFileSystem (p, null); + FileSystem fs = FileSystems.newFileSystem (p); + Path pp = fs.getPath ("/" + Constants.PROJECT_DB_FILE_NAME_PREFIX + Constants.H2_DB_FILE_SUFFIX); + + if (Files.notExists (pp)) + { + + return false; + + } + + return true; + + } + + public static int clamp (int v, + int min, + int max) + { + + return Math.min (Math.max (v, min), max); + + } + + public static String replaceString (String text, + String str, + String replace) + throws NullPointerException + { + + if (text == null) + { + + throw new NullPointerException ("text parm (arg 1)."); + + } + + if (str == null) + { + + throw new NullPointerException ("str parm (arg 2)."); + + } + + if (replace == null) + { + + throw new NullPointerException ("replace parm (arg3)."); + + } + + StringBuilder buf = new StringBuilder (text); + + int index = buf.indexOf (str); + + while (index != -1) + { + + buf.replace (index, + index + str.length (), + replace); + + index = buf.indexOf (str, + index + replace.length ()); + + } + + return buf.toString (); + + } + + public static void streamTo (InputStream in, + OutputStream out, + int bufSize) + throws IOException + { + + byte buf[] = new byte[bufSize]; + + int bRead = -1; + + while ((bRead = in.read (buf)) != -1) + { + + out.write (buf, + 0, + bRead); + + } + + } + + public static String getExceptionTraceAsString (Throwable e) + { + + StringWriter sw = new StringWriter (); + PrintWriter pw = new PrintWriter (sw); + e.printStackTrace (pw); + pw.flush (); + pw.close (); + return sw.toString (); + + } + + public static String encodeParms (Map parms) + { + + StringBuilder b = new StringBuilder (); + + for (String k : parms.keySet ()) + { + + if (b.length () > 0) + { + + b.append ("&"); + + } + + b.append (k); + b.append ("="); + b.append (parms.get (k)); + + } + + b.insert (0, + "?"); + + return b.toString (); + + } + + /** + * Determines if LocalTime.now is between the from and to. + * If to > from then now is between if now.isAfter (from) && now.isBefore (to) + * If from > to then now is between if now.isAfter (from) || now.isBefore (to) + from 20:00, to 10:00, now 21:00 = true + from 20:00, to 10:00, now 11:00 = false + from 20:00, to 10:00, now 9:00 = true + */ + public static boolean isNowBetween (LocalTime from, + LocalTime to) + { + + LocalTime now = LocalTime.now (); + + if (from.isBefore (to)) + { + + return (now.isAfter (from) && (now.isBefore (to))); + + } else { + + return (now.isAfter (from) || (now.isBefore (to))); + + } + + } + + public static long getMillisFromNowToNearestNextTime (LocalTime from, + LocalTime to) + { + + LocalDateTime now = LocalDateTime.now (); + now = now.with (ChronoField.MILLI_OF_SECOND, 0); + + if (from.isBefore (to)) + { + + if (now.toLocalTime ().isAfter (to)) + { + + // Get the next day with the from time. + LocalDateTime f = LocalDateTime.now (); + f = f.with (from); + f = f.plusDays (1); + return Math.abs (ChronoUnit.MILLIS.between (now, f)); + + } + + if (now.toLocalTime ().isAfter (from)) + { + + // Get to with current date. + LocalDateTime t = LocalDateTime.now (); + t = t.with (to); + return Math.abs (ChronoUnit.MILLIS.between (now, t)); + + } + + // Get the from time with current date. + LocalDateTime f = LocalDateTime.now (); + f = f.with (from); + return Math.abs (ChronoUnit.MILLIS.between (now, f)); + + } + + // From is after the to. + if (now.toLocalTime ().isAfter (from)) + { + + // Need to on next day. + LocalDateTime t = LocalDateTime.now (); + t = t.with (to); + t = t.plusDays (1); + return Math.abs (ChronoUnit.MILLIS.between (now, t)); + + } + + if (now.toLocalTime ().isAfter (to)) + { + + // Need from on current date. + LocalDateTime f = LocalDateTime.now (); + f = f.with (from); + return Math.abs (ChronoUnit.MILLIS.between (now, f)); + + } + + if (now.toLocalTime ().isBefore (to)) + { + + // Need to on current date. + LocalDateTime t = LocalDateTime.now (); + t = t.with (to); + return Math.abs (ChronoUnit.MILLIS.between (now, t)); + + } + + throw new IllegalStateException ("Unable to find the least."); + + } + +} diff --git a/src/main/java/com/quollwriter/Version.java b/src/main/java/com/quollwriter/Version.java new file mode 100644 index 00000000..11a10662 --- /dev/null +++ b/src/main/java/com/quollwriter/Version.java @@ -0,0 +1,289 @@ +package com.quollwriter; + +import java.util.*; + +/** + * Models the version numbers, format is: [version.version.version...]b[version] + * where each version is an integer. The b[version] is optional and indicates a beta version. + * + * Examples: + * + * 2.2 + * 2.3b1 + * 2.4b1 + * 2.4 + * 2.2.1b1 + * 2.3.9 + * + * A value of 2.3 is considered to be "newer" than 2.3b1 and 2.3b2 is newer than 2.3b1. + */ +public class Version implements Comparable +{ + + private String _version = null; + private int betaVersion = 0; + private List parts = new ArrayList<> (); + + public Version (String v) + { + + if (v == null) + { + + throw new IllegalArgumentException ("Version must be specified"); + + } + + this._version = v.trim (); + + String ver = this._version; + + int bind = this._version.indexOf ("b"); + + if (bind > 0) + { + + // Get the version then the beta. + ver = this._version.substring (0, bind); + + String bver = this._version.substring (bind + 1); + + this.betaVersion = Integer.parseInt (bver); + + } + + this.getVersionParts (ver); + + //this.version = this.getVersionAsInt (ver); + + } + + @Override + public int compareTo (Version v) + { + + if (v == null) + { + + return 1; + + } + + if (this.isSame (v)) + { + + return 0; + + } + + if (this.isNewer (v)) + { + + return -1; + + } + + return 1; + + } + + public String getVersionNoBeta () + { + + int bind = this._version.indexOf ("b"); + + if (bind > 0) + { + + return this._version.substring (0, bind); + + } + + return this._version; + + } + + public String getVersion () + { + + return this._version; + + } + + public String toString () + { + + return this._version; + + } + + private List getVersionParts (String v) + { + + if (v == null) + { + + v = "0"; + + } + + //v = this.expandVersion (v); + + StringTokenizer t = new StringTokenizer (v, + "."); + + //List parts = new ArrayList (); + + while (t.hasMoreTokens ()) + { + + this.parts.add (Integer.parseInt (t.nextToken ())); + + } + + return this.parts; + + } + + public boolean isBeta () + { + + return this.betaVersion > 0; + + } + + public boolean isSame (Version other) + { + + return this.equals (other); + + } + + private int getPart (int i) + { + + if (i < this.parts.size ()) + { + + return this.parts.get (i); + + } + + return -1; + + } + + private int getPartsCount () + { + + return this.parts.size (); + + } + + /** + * Is the passed in version newer than this one. + * + * @param other The version to check. + * @return true if other is newer than this version. + */ + public boolean isNewer (Version other) + { + + if (other == null) + { + + return false; + + } + + for (int i = 0; i < other.getPartsCount (); i++) + { + + int op = other.getPart (i); + int tp = this.getPart (i); + + if (op > tp) + { + + return true; + + } + + if (op < tp) + { + + return false; + + } + + } + + if ((other.betaVersion > 0) + && + (this.betaVersion > 0) + ) + { + + return other.betaVersion > this.betaVersion; + + } + + return false; + + } + + @Override + public int hashCode () + { + + return this._version.hashCode (); + + } + + @Override + public boolean equals (Object o) + { + + if ((o == null) || (!(o instanceof Version))) + { + + return false; + + } + + Version v = (Version) o; + + return this._version.equals (v._version); + + } + + public boolean equalsIgnoreBeta (Version v) + { + + if (v == null) + { + + return false; + + } + + for (int i = 0; i < v.getPartsCount (); i++) + { + + int op = v.getPart (i); + int tp = this.getPart (i); + + if (op != tp) + { + + return false; + + } + + } + + return true; + + } + +} diff --git a/src/com/quollwriter/achievements/AchievementReachedEvent.java b/src/main/java/com/quollwriter/achievements/AchievementReachedEvent.java similarity index 100% rename from src/com/quollwriter/achievements/AchievementReachedEvent.java rename to src/main/java/com/quollwriter/achievements/AchievementReachedEvent.java diff --git a/src/com/quollwriter/achievements/AchievementReachedListener.java b/src/main/java/com/quollwriter/achievements/AchievementReachedListener.java similarity index 100% rename from src/com/quollwriter/achievements/AchievementReachedListener.java rename to src/main/java/com/quollwriter/achievements/AchievementReachedListener.java diff --git a/src/main/java/com/quollwriter/achievements/AchievementsManager.java b/src/main/java/com/quollwriter/achievements/AchievementsManager.java new file mode 100644 index 00000000..2fb7aa47 --- /dev/null +++ b/src/main/java/com/quollwriter/achievements/AchievementsManager.java @@ -0,0 +1,1505 @@ +package com.quollwriter.achievements; + +import java.util.*; +import java.util.stream.*; +import java.util.concurrent.*; +import java.io.*; +import java.nio.file.*; + +import javafx.beans.property.*; +import javafx.scene.media.*; +import javafx.collections.*; +import javafx.event.*; + +import org.dom4j.*; +import org.dom4j.tree.*; + +import com.gentlyweb.properties.*; + +import com.quollwriter.*; +import com.quollwriter.ui.fx.viewers.*; +import com.quollwriter.ui.fx.*; +import com.quollwriter.ui.fx.components.*; + +import com.quollwriter.achievements.rules.*; + +public class AchievementsManager implements ProjectEventListener +{ + + // TODO Make a singleton... like UILanguageStringsManager + + public static final String USER = "user"; + public static final String PROJECT = "project"; + public static final String CHAPTER = "chapter"; + + public class XMLConstants + { + + public static final String item = "item"; + public static final String id = "id"; + public static final String category = "category"; + public static final String state = "state"; + + } + + // The key here is the AchievementRule.getEventId + private Map> userRules = new HashMap<> (); + + // The inner map key is the AchievementRule.getEventId. + // TODO Separate out into own subclass, i.e ProjectAchievementsManager. + private Map>> eventRules = new HashMap<> (); + private Map checkers = new HashMap<> (); + private Map> projAchievedRules = new HashMap<> (); + + // The key is the id attribute of the element. + private Map ruleEls = new LinkedHashMap<> (); + + //private AudioClip achievementSound = null; + private javax.sound.sampled.Clip achievementSound = null; + + private Map listeners = null; + private Object listenerFillObj = new Object (); + + private boolean soundRunning = false; + //private SetProperty userAchievedProp = null; + private ObservableSet userAchievedRules = null; + + public AchievementsManager () + throws Exception + { + + this.listeners = Collections.synchronizedMap (new WeakHashMap<> ()); + + // Load our list of user achieved achievements. + Set userAchievedIds = this.getAchievedIds (UserProperties.get (Constants.USER_ACHIEVEMENTS_ACHIEVED_PROPERTY_NAME)); + + this.userAchievedRules = FXCollections.observableSet (); + //this.userAchievedProp = new SimpleSetProperty<> (FXCollections.observableSet (this.userAchievedRules)); + + // Load the state for the user achievements. + Map initEls = this.getInitElements (UserProperties.get (Constants.USER_ACHIEVEMENTS_STATE_PROPERTY_NAME)); + + // Create the achievements for the project and chapter categories. + String achFile = Utils.getResourceFileAsString (Constants.ACHIEVEMENTS_FILE); + + if (achFile == null) + { + + return; + + } + + Element root = DOM4JUtils.stringAsElement (achFile); + + Set userSessionRules = new HashSet<> (); + + for (Element el : root.elements (XMLConstants.item)) + { + + String id = el.attributeValue (XMLConstants.id).toLowerCase ().trim (); + + if (el.attributeValue (XMLConstants.category).equals (USER)) + { + + // Load the rule. + AchievementRule ar = AchievementRuleFactory.createRule (el); + + if (ar == null) + { + + DOM4JUtils.raiseException ("Unable to create rule from element: %1$s", + el); + + } + + // Have we achieved this one. + if (userAchievedIds.contains (id)) + { + + this.userAchievedRules.add (ar); + + } + + // Init. + Element initEl = initEls.get (ar.getId ()); + + if (initEl != null) + { + + ar.init (initEl); + + } + + if (ar.isEventTrigger ()) + { + + for (String eid : ar.getEventIds ()) + { + + Set rs = this.userRules.get (eid); + + if (rs == null) + { + + rs = new LinkedHashSet (); + + this.userRules.put (eid, + rs); + + } + + rs.add (ar); + + } + + } else { + + userSessionRules.add (ar); + + } + + } else { + + this.ruleEls.put (id, + el); + + } + + } + + if (userSessionRules.size () > 0) + { + + AchievementsChecker ac = new AchievementsChecker (null, + userSessionRules, + this); + + ac.scheduledFuture = Environment.schedule (ac, + 10 * 1000, + 10 * 1000); + + this.checkers.put (null, + ac); + + } + + this.userAchievedRules.addListener ((SetChangeListener) ev -> + { + + try + { + + UserProperties.set (Constants.USER_ACHIEVEMENTS_ACHIEVED_PROPERTY_NAME, + this.userAchievedRules.stream () + .map (r -> r.getId ()) + .collect (Collectors.joining (","))); + + } catch (Exception e) { + + Environment.logError ("Unable to update user achievements achieved property", + e); + + return; + + } + + AchievementRule ar = ev.getElementAdded (); + + if (ar != null) + { + + try + { + + Environment.getFocusedViewer ().showAchievement (ar); + + this.playAchievementSound (); + + } catch (Exception e) { + + // Log the error. + Environment.logError ("Unable to set user achievement as reached: " + + ar, + e); + + } + + } + + }); + + Environment.addUserProjectEventListener (this); + + } + +/* +TODO Remove + public void removeAchievementReachedListener (AchievementReachedListener l) + { + + this.listeners.remove (l); + + } + + public void addAchievementReachedListener (AchievementReachedListener l) + { + + this.listeners.put (l, this.listenerFillObj); + + } + + protected void fireAchievementReachedEvent (AchievementRule ar) + { + + final AchievementsManager _this = this; + + final AchievementReachedEvent ev = new AchievementReachedEvent (ar); + + UIUtils.doActionLater (new ActionListener () + { + + public void actionPerformed (ActionEvent aev) + { + + Set ls = null; + + // Get a copy of the current valid listeners. + synchronized (_this.listeners) + { + + ls = new LinkedHashSet (_this.listeners.keySet ()); + + } + + for (AchievementReachedListener l : ls) + { + + l.achievementReached (ev); + + } + + } + + }); + + } +*/ + + public ObservableSet userAchievedRules () + { + + return this.userAchievedRules; + + } + + public Set getProjectAchievedIds (AbstractProjectViewer v) + { + + SetProperty prop = this.projAchievedRules.get (v); + + if (prop == null) + { + + return new LinkedHashSet<> (); + + } + + return new LinkedHashSet<> (prop.getValue ()); + + } + + public Set getProjectAchievedRules (AbstractProjectViewer v) + { + + return this.projAchievedRules.get (v); + + } + + public Set getUserAchievedRules () + { + + return new LinkedHashSet<> (this.userAchievedRules); + // TODO return this.getAchievedIds (UserProperties.get (Constants.USER_ACHIEVEMENTS_ACHIEVED_PROPERTY_NAME)); + + } + + private Set getRules (String type, + boolean includeHidden) + throws Exception + { + + // Create the achievements for the project and chapter categories. + String achFile = Utils.getResourceFileAsString (Constants.ACHIEVEMENTS_FILE); + + if (achFile == null) + { + + return null; + + } + + Element root = null; + + try + { + + root = DOM4JUtils.stringAsElement (achFile); + + } catch (Exception e) { + + Environment.logError ("Unable to convert file: " + + achFile + + " to an element", + e); + + return null; + + } + + Set rules = new LinkedHashSet<> (); + + // Get the user ones. + for (Element el : root.elements (XMLConstants.item)) + { + + try + { + + String id = el.attributeValue (XMLConstants.id).toLowerCase ().trim (); + + if (el.attributeValue (XMLConstants.category).equals (type)) + { + + AchievementRule ar = AchievementRuleFactory.createRule (el); + + if ((!includeHidden) + && + (ar.isHidden ()) + ) + { + + continue; + + } + + rules.add (ar); + + } + + } catch (Exception e) { + + Environment.logError ("Unable to convert element: " + + DOM4JUtils.getPath (el) + + " to a rule", + e); + + } + + } + + return rules; + + } + + public Set getUserRules () + { + + try + { + + return this.getRules (USER, + true); + + } catch (Exception e) { + + Environment.logError ("Unable to get user rules", + e); + + return null; + + } + + } + + public Set getPerProjectRules () + { + + try + { + + return this.getRules (PROJECT, + true); + + } catch (Exception e) { + + Environment.logError ("Unable to get project rules", + e); + + return null; + + } + + } + + + private Set getAchievedIds (String v) + { + + Set achievedM = new HashSet (); + + if (v != null) + { + + // Split on , + StringTokenizer t = new StringTokenizer (v, + ","); + + while (t.hasMoreTokens ()) + { + + achievedM.add (t.nextToken ().toLowerCase ().trim ()); + + } + + } + + return achievedM; + + } + + private String getState (Set rules) + throws Exception + { + + Element root = new DefaultElement (XMLConstants.state); + + // Now persist any user rules. + for (AchievementRule ar : rules) + { + + if (ar.shouldPersistState ()) + { + + Element el = new DefaultElement (XMLConstants.item); + + el.addAttribute (XMLConstants.id, + ar.getId ()); + ar.fillState (el); + + root.add (el); + + } + + } + + return DOM4JUtils.elementAsString (root); + + } + + public void stop () + throws Exception + { + + Set viewers = new HashSet<> (this.eventRules.keySet ()); + + for (AbstractViewer pv : viewers) + { + + this.removeViewer (pv); + + } + + UserProperties.set (Constants.USER_ACHIEVEMENTS_STATE_PROPERTY_NAME, + this.getState (new HashSet (this.userRules.values ()))); + + } + +/* + TODO Remove + public Map> getAchievedAchievementIds (AbstractViewer viewer) + { + + Map> achieved = new HashMap<> (); + + achieved.put (USER, + new LinkedHashSet<> (his.userAchievedIds)); + + if ((viewer != null) + && + (viewer instanceof AbstractProjectViewer) + ) + { + + AbstractProjectViewer pv = (AbstractProjectViewer) viewer; + + SetProperty projIds = this.projAchievedIds.get (pv); + + if (projIds != null) + { + + achieved.put (PROJECT, + new LinkedHashSet<> (projIds.getValue ())); + // TODO Remove this.getAchievedIds (pv.getProject ().getProperty (Constants.PROJECT_ACHIEVEMENTS_ACHIEVED_PROPERTY_NAME))); + + } + + } + + return achieved; + + } +*/ + private Map getInitElements (String v) + throws Exception + { + + Map initEls = new HashMap<> (); + + if (v != null) + { + + try + { + + Element root = DOM4JUtils.stringAsElement (v); + + for (Element el : root.elements (XMLConstants.item)) + { + + initEls.put (el.attributeValue (XMLConstants.id), + el); + + } + + } catch (Exception e) { + + Environment.logError ("Unable to get achievement init elements for string: " + + v, + e); + + } + + } + + return initEls; + + } + + public void removeViewer (AbstractViewer v) + throws Exception + { + + if (v == null) + { + + return; + + } + + Map> rules = this.eventRules.get (v); + + if (rules == null) + { + + // Already removed. + return; + + } + + Set rs = new HashSet<> (); + + if (rules != null) + { + + for (String id : rules.keySet ()) + { + + rs.addAll (rules.get (id)); + + } + + } + + this.eventRules.remove (v); + + // Check to see if we meet any of the achievements. + AchievementsChecker t = this.checkers.get (v); + + if (t != null) + { + + // Get the rules. + rs.addAll (t.getRules ()); + + } + + this.projAchievedRules.remove (v); + + if (v instanceof AbstractProjectViewer) + { + + AbstractProjectViewer pv = (AbstractProjectViewer) v; + + // Save the state. + pv.getProject ().setProperty (Constants.PROJECT_ACHIEVEMENTS_STATE_PROPERTY_NAME, + this.getState (rs)); + + pv.saveProject (); + + } + + if (t != null) + { + + Environment.unschedule (t.scheduledFuture); + + } + + this.checkers.remove (v); + + } + + public SetProperty projectAchievedProperty (AbstractProjectViewer v) + { + + return this.projAchievedRules.get (v); + + } + + public void addProjectViewer (AbstractProjectViewer v) + throws Exception + { + + AchievementsManager _this = this; + + EventHandler h = new EventHandler<> () + { + + @Override + public void handle (Viewer.ViewerEvent ev) + { + + _this.projAchievedRules.remove (v); + _this.eventRules.remove (v); + _this.checkers.remove (v); + v.removeProjectEventListener (_this); + v.getViewer ().removeEventHandler (Viewer.ViewerEvent.CLOSE_EVENT, + this); + + } + + }; + + v.getViewer ().addEventHandler (Viewer.ViewerEvent.CLOSE_EVENT, + h); + + // Get the list of project/chapter achieved achievements. + Set achieved = this.getAchievedIds (v.getProject ().getProperty (Constants.PROJECT_ACHIEVEMENTS_ACHIEVED_PROPERTY_NAME)); + + Set achievedRules = new HashSet<> (); + + SetProperty prop = new SimpleSetProperty<> (FXCollections.observableSet (achievedRules)); + + this.projAchievedRules.put (v, + prop); + + // Load the state for the achievements and init. + Map initEls = this.getInitElements (v.getProject ().getProperty (Constants.PROJECT_ACHIEVEMENTS_STATE_PROPERTY_NAME)); + + // The key is the event id. + Map> evRules = new HashMap<> (); + + Set constantRules = new LinkedHashSet<> (); + + // Load the project/chapter achievements (not in the list above). + for (String id : this.ruleEls.keySet ()) + { + + Element el = this.ruleEls.get (id); + + // Load the rule. + AchievementRule ar = AchievementRuleFactory.createRule (el); + + if (ar == null) + { + + throw new GeneralException ("Unable to create rule from element: " + + DOM4JUtils.getPath (el)); + + } + + if (achieved.contains (id)) + { + + achievedRules.add (ar); + + } + + // Init. + Element initEl = initEls.get (ar.getId ()); + + if (initEl != null) + { + + ar.init (initEl); + + } + + if (ar.isEventTrigger ()) + { + + // Get the event ids, there can be more than one for example + // if we are looking for new and/or edit events for an object type. + Set eventIds = ar.getEventIds (); + + for (String eid : eventIds) + { + + Set rules = evRules.get (eid); + + if (rules == null) + { + + rules = new LinkedHashSet<> (); + + evRules.put (eid, + rules); + + } + + rules.add (ar); + + } + + } else { + + constantRules.add (ar); + + } + + } + + this.eventRules.put (v, + evRules); + + if (constantRules.size () > 0) + { + + // Create the achievements checker and schedule. + AchievementsChecker ac = new AchievementsChecker (v, + constantRules, + this); + + ac.scheduledFuture = Environment.schedule (ac, + 10 * 1000, + 10 * 1000); + + this.checkers.put (v, + ac); + + } + + v.getBinder ().addSetChangeListener (prop, + ev -> + { + + AchievementRule ar = ev.getElementAdded (); + + try + { + + v.getProject ().getProperties ().setProperty (Constants.PROJECT_ACHIEVEMENTS_ACHIEVED_PROPERTY_NAME, + new com.gentlyweb.properties.StringProperty (Constants.PROJECT_ACHIEVEMENTS_ACHIEVED_PROPERTY_NAME, + achievedRules.stream () + .map (r -> r.getId ()) + .collect (Collectors.joining (",")))); + + v.saveProject (); + + if (ar != null) + { + + v.showAchievement (ar); + + //this.fireAchievementReachedEvent (ar); + + this.playAchievementSound (); + + v.createActionLogEntry (v.getProject (), + "Achievement: " + ar.getId () + "[" + ar.nameProperty ().getValue () + "] reached."); + + } + + } catch (Exception e) { + + Environment.logError ("Unable to set achievement achieved: " + + ar, + e); + + } + + }); + + v.addProjectEventListener (this); + + } + + private void logAchievementReached () + { + + + } + + // TODO: Allow for just AbstractViewer. + public synchronized void projectAchievementReached (AbstractProjectViewer viewer, + AchievementRule ar) + { + + if (Environment.isDebugModeEnabled ()) + { + + Environment.logMessage ("Achievement reached: " + ar + ", enabled: " + this.isAchievementsEnabled ()); + + } + + if (!this.isAchievementsEnabled ()) + { + + return; + + } + + try + { + + SetProperty prop = this.projAchievedRules.get (viewer); + + if (prop == null) + { + + // How did this happen? + return; + + } + + Set rules = prop.getValue (); + + UIUtils.runLater (() -> + { + + rules.add (ar); + + }); +/* +TODO Remove + // Add to the list of project achievements. + Set achieved = this.getAchievedIds (viewer.getProject ().getProperty (Constants.PROJECT_ACHIEVEMENTS_ACHIEVED_PROPERTY_NAME)); + + if (achieved.contains (ar.getId ())) + { + + return; + + } + + achieved.add (ar.getId ()); + */ +/* +TODO + viewer.getProject ().getProperties ().setProperty (Constants.PROJECT_ACHIEVEMENTS_ACHIEVED_PROPERTY_NAME, + new StringProperty (Constants.PROJECT_ACHIEVEMENTS_ACHIEVED_PROPERTY_NAME, + this.getAsString (achieved))); + + viewer.saveProject (); +*/ + } catch (Exception e) { + + Environment.logError ("Unable to set achievement achieved: " + + ar, + e); + + } + + } + + private void removeRule (AchievementRule ar, + AbstractProjectViewer viewer) + { + + Map> rules = this.eventRules.get (viewer); + + Set eventIds = ar.getEventIds (); + + for (String eid : eventIds) + { + + Set rs = rules.get (eid); + + rs.remove (ar); + + } + + } + + public synchronized void userAchievementReached (AchievementRule ar) + { + + if (Environment.isDebugModeEnabled ()) + { + + Environment.logMessage ("User achievement reached: " + ar + ", enabled: " + this.isAchievementsEnabled ()); + + } + + if (!this.isAchievementsEnabled ()) + { + + return; + + } + + try + { + + this.userAchievedRules.add (ar); +/* +TODO Remove + // Add to the list of user achievements. + Set achieved = this.getAchievedIds (UserProperties.get (Constants.USER_ACHIEVEMENTS_ACHIEVED_PROPERTY_NAME)); + + if (achieved.contains (ar.getId ())) + { + + return; + + } + + achieved.add (ar.getId ()); +*/ +/* + UserProperties.set (Constants.USER_ACHIEVEMENTS_ACHIEVED_PROPERTY_NAME, + this.getAsString (achieved)); +xxx + this.fireAchievementReachedEvent (ar); +*/ + // TODO Environment.getFocusedViewer ().showAchievement (ar); + + //this.playAchievementSound (); + + } catch (Exception e) { + + // Log the error. + Environment.logError ("Unable to set user achievement as reached: " + + ar, + e); + + } + + } + + public void setAchievementsEnabled (boolean v) + { + + UserProperties.set (Constants.ACHIEVEMENTS_ENABLED_PROPERTY_NAME, + v); + + } + + public boolean isAchievementsEnabled () + { + + return UserProperties.getAsBoolean (Constants.ACHIEVEMENTS_ENABLED_PROPERTY_NAME) + && + !Environment.isDistractionFreeModeEnabled (); + + } + + public boolean isSoundsInFullScreenEnabled () + { + + return UserProperties.getAsBoolean (Constants.ACHIEVEMENTS_SOUND_IN_FULL_SCREEN_ENABLED_PROPERTY_NAME); + + } + + public void setSoundsInFullScreenEnabled (boolean v) + { + + UserProperties.set (Constants.ACHIEVEMENTS_SOUND_IN_FULL_SCREEN_ENABLED_PROPERTY_NAME, + v); + + } + + public void setSoundEnabled (boolean v) + { + + UserProperties.set (Constants.ACHIEVEMENTS_SOUND_ENABLED_PROPERTY_NAME, + v); + + } + + public boolean isSoundEnabled () + { + + return UserProperties.getAsBoolean (Constants.ACHIEVEMENTS_SOUND_ENABLED_PROPERTY_NAME); + + } + + public void playAchievementSound () + { + + if (!this.isSoundEnabled ()) + { + + return; + + } + + if ((Environment.isInFullScreen ()) + && + (!this.isSoundsInFullScreenEnabled ()) + ) + { + + return; + + } + + if (this.achievementSound == null) + { + + try + { + + Path p = Utils.getAsPath (Utils.getResourceUrl (Constants.DEFAULT_ACHIEVEMENT_SOUND_FILE).toURI ()); + + byte[] bytes = Files.readAllBytes (p); + + try (javax.sound.sampled.AudioInputStream audioInputStream = javax.sound.sampled.AudioSystem.getAudioInputStream (new BufferedInputStream (new ByteArrayInputStream (bytes)))) + { + + this.achievementSound = javax.sound.sampled.AudioSystem.getClip (); + this.achievementSound.open (audioInputStream); + //clip.start (); + //audioInputStream.close (); + + } catch (Exception e) { + + Environment.logError ("Unable to get/play achievement sound: " + p, + e); + + } + + // TODO Make this configurable? + //this.achievementSound = new AudioClip (Utils.getResourceUrl (Constants.DEFAULT_ACHIEVEMENT_SOUND_FILE).toExternalForm ()); + +/* +TODO Remove + InputStream is = new BufferedInputStream (Utils.getResourceStream (Constants.DEFAULT_ACHIEVEMENT_SOUND_FILE)); + + // Get the clip. + AudioInputStream ais = AudioSystem.getAudioInputStream (is); + + this.achievementSound = AudioSystem.getClip (); + + this.achievementSound.open (ais); +*/ + } catch (Exception e) + { + + Environment.logError ("Unable to get sound file to play on achievement", + e); + + return; + + } + + } + + if (this.soundRunning) + { + + return; + + } + + this.soundRunning = true; + + final AchievementsManager _this = this; + + Environment.schedule (() -> + { + + UIUtils.runLater (() -> + { + + try + { + + //this.achievementSound.play (); + this.achievementSound.setFramePosition (0); + this.achievementSound.start (); + + } finally { + + this.soundRunning = false; + + } + + }); + + }, + 500, + -1); +/* +TODO Remove + javax.swing.Timer t = new javax.swing.Timer (1000, + new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + // Play after 1s. + try + { + + _this.achievementSound.setFramePosition (0); + + _this.achievementSound.start (); + + _this.soundRunning = false; + + } catch (Exception e) + { + + Environment.logError ("Unable to play achievement sound", + e); + + } + + } + + }); + + t.setRepeats (false); + + t.start (); +*/ + } + + private String getAsString (Set ids) + { + + return ids.stream () + .collect (Collectors.joining (",")); +/* + StringBuilder b = new StringBuilder (); + + for (String id : ids) + { + + if (b.length () > 0) + { + + b.append (","); + + } + + b.append (id); + + } + + return b.toString (); +*/ + } + + public void eventOccurred (ProjectEvent ev) + { + + // Get our matching user rules for the event. + if (Environment.isDebugModeEnabled ()) + { + + Environment.logMessage ("Event occurred: " + ev); + + } + + long start = System.currentTimeMillis (); + + Set rules = this.userRules.get (ev.getEventId ()); + + if (rules != null) + { + + Set achieved = new HashSet<> (); + + for (AchievementRule ar : rules) + { + + try + { + + if (ar.achieved (null, + ev)) + { + + // Just pick a viewer and display there. + this.userAchievementReached (ar); + + achieved.add (ar); + + } + + } catch (Exception e) { + + Environment.logError ("Unable to check for achievement: " + + ar, + e); + + } + + } + + for (AchievementRule ar : achieved) + { + + for (String eid : ar.getEventIds ()) + { + + this.userRules.remove (eid); + + } + + } + + } + + if (ev.getSource () instanceof AbstractProjectViewer) + { + + AbstractProjectViewer pv = (AbstractProjectViewer) ev.getSource (); + + Map> evRules = this.eventRules.get (pv); + + if (evRules != null) + { + + Set rs = evRules.get (ev.getEventId ()); + + if (rs != null) + { + + Set achieved = new HashSet<> (); + + for (AchievementRule ar : rs) + { + + try + { + + if (ar.achieved (pv, + ev)) + { + + this.projectAchievementReached (pv, + ar); + + achieved.add (ar); + + } + + } catch (Exception e) { + + Environment.logError ("Unable to check for achievement: " + + ar, + e); + + } + + } + + for (AchievementRule ar : achieved) + { + + this.removeRule (ar, + pv); + + } + + } + + } + + } + + if ((System.currentTimeMillis () - start) > 500) + { + + Environment.logMessage ("Warning! Achievements event processing took: " + (System.currentTimeMillis () - start)); + + } + + } + + public class AchievementsChecker implements Runnable + { + + public ScheduledFuture scheduledFuture = null; + public AbstractProjectViewer viewer = null; + private boolean running = false; + public AchievementsManager manager = null; + public Set rules = null; + private int count = 0; + public AchievementsChecker (AbstractProjectViewer viewer, + Set rules, + AchievementsManager manager) + { + + this.viewer = viewer; + this.rules = rules; + this.manager = manager; + + } + + public Set getRules () + { + + return this.rules; + + } + + public boolean isRunning () + { + + return this.running; + + } + + public void run () + { + + try{ + this.count++; + + if (this.running) + { + + return; + + } + + this.running = true; + + if (rules.size () == 0) + { + + try + { + + manager.removeViewer (this.viewer); + + } catch (Exception e) { + + // Ignore. + + } + + this.running = false; + + return; + + } + + Iterator iter = this.rules.iterator (); + + while (iter.hasNext ()) + { + + AchievementRule ar = iter.next (); + + try + { + + if (ar.achieved (this.viewer)) + { + + if (ar.getCategory ().equals (USER)) + { + + manager.userAchievementReached (ar); + + } else { + + manager.projectAchievementReached (this.viewer, + ar); + + } + + iter.remove (); + + } + + } catch (Exception e) { + + Environment.logError ("Unable to check achievement: " + ar, + e); + + } + + } + + this.running = false; + + }catch(Exception e) { + + Environment.logError ("Unable to check for achievements for project: " + + this.viewer.getProject (), + e); + + } + + } + + } + + public void removeAchievedAchievement (String type, + String id, + AbstractViewer viewer) + throws Exception + { + + if (type.toLowerCase ().equals (USER)) + { + + Set achieved = this.getAchievedIds (UserProperties.get (Constants.USER_ACHIEVEMENTS_ACHIEVED_PROPERTY_NAME)); + + achieved.remove (id.toLowerCase ()); + + UserProperties.set (Constants.USER_ACHIEVEMENTS_ACHIEVED_PROPERTY_NAME, + this.getAsString (achieved)); + + } else { + + if ((viewer != null) + && + (viewer instanceof AbstractProjectViewer) + ) + { + + AbstractProjectViewer pv = (AbstractProjectViewer) viewer; + + Set achieved = this.getAchievedIds (pv.getProject ().getProperty (Constants.PROJECT_ACHIEVEMENTS_ACHIEVED_PROPERTY_NAME)); + + achieved.remove (id); + + pv.getProject ().getProperties ().setProperty (Constants.PROJECT_ACHIEVEMENTS_ACHIEVED_PROPERTY_NAME, + new com.gentlyweb.properties.StringProperty (Constants.PROJECT_ACHIEVEMENTS_ACHIEVED_PROPERTY_NAME, + this.getAsString (achieved))); + + } + + } + + } + +} diff --git a/src/com/quollwriter/achievements/rules/AbstractAchievementRule.java b/src/main/java/com/quollwriter/achievements/rules/AbstractAchievementRule.java similarity index 76% rename from src/com/quollwriter/achievements/rules/AbstractAchievementRule.java rename to src/main/java/com/quollwriter/achievements/rules/AbstractAchievementRule.java index bfe84bc6..5b9fcc51 100644 --- a/src/com/quollwriter/achievements/rules/AbstractAchievementRule.java +++ b/src/main/java/com/quollwriter/achievements/rules/AbstractAchievementRule.java @@ -2,12 +2,16 @@ import java.util.*; -import org.jdom.*; +import javafx.beans.property.*; -import com.gentlyweb.xml.*; +import org.dom4j.*; import com.quollwriter.*; -import com.quollwriter.ui.*; +import com.quollwriter.ui.fx.viewers.*; +import com.quollwriter.ui.fx.*; + +import static com.quollwriter.LanguageStrings.*; +import static com.quollwriter.uistrings.UILanguageStringsManager.getUILanguageStringProperty; public abstract class AbstractAchievementRule implements AchievementRule { @@ -31,8 +35,10 @@ public class XMLConstants private String icon = null; private String cat = null; private boolean hidden = false; + private StringProperty nameProp = null; + private StringProperty descProp = null; - protected Set eventIds = new HashSet (); + protected Set eventIds = new HashSet<> (); public String toString () { @@ -42,24 +48,21 @@ public String toString () } public AbstractAchievementRule (Element root) - throws JDOMException + throws GeneralException { - this.id = JDOMUtils.getAttributeValue (root, - XMLConstants.id, - true); - this.cat = JDOMUtils.getAttributeValue (root, - XMLConstants.category, - true); - this.hidden = JDOMUtils.getAttributeValueAsBoolean (root, + this.id = DOM4JUtils.attributeValue (root, + XMLConstants.id); + this.cat = DOM4JUtils.attributeValue (root, + XMLConstants.category); + this.hidden = DOM4JUtils.attributeValueAsBoolean (root, XMLConstants.hidden, false); // Get the name from the language string. - this.name = Environment.getUIString (LanguageStrings.achievements, - this.id, - LanguageStrings.name); + this.nameProp = getUILanguageStringProperty (LanguageStrings.achievements,this.id,LanguageStrings.name); +/* if (this.name == null) { @@ -67,11 +70,10 @@ public AbstractAchievementRule (Element root) this.id); } +*/ + this.descProp = getUILanguageStringProperty (achievements,this.id,description); - this.desc = Environment.getUIString (LanguageStrings.achievements, - this.id, - LanguageStrings.description); - +/* if (this.desc == null) { @@ -79,23 +81,16 @@ public AbstractAchievementRule (Element root) this.id); } - - this.icon = JDOMUtils.getAttributeValue (root, +*/ + this.icon = DOM4JUtils.attributeValue (root, XMLConstants.icon, false); - if (this.icon.equals ("")) - { - - this.icon = null; - - } - - String ev = JDOMUtils.getAttributeValue (root, + String ev = DOM4JUtils.attributeValue (root, XMLConstants.event, false); - if (!ev.equals ("")) + if (ev != null) { StringTokenizer t = new StringTokenizer (ev, @@ -127,7 +122,7 @@ public AbstractAchievementRule (Element root) } else { - this.eventIds.add (type + "." + ProjectEvent.ANY); + this.eventIds.add (type + "." + ProjectEvent.Type.any); } @@ -164,7 +159,8 @@ public String getCategory () return this.cat; } - +/* +TODO Remove public String getDescription () { @@ -178,6 +174,21 @@ public String getName () return this.name; } +*/ + + public StringProperty descriptionProperty () + { + + return this.descProp; + + } + + public StringProperty nameProperty () + { + + return this.nameProp; + + } public String getIcon () { diff --git a/src/main/java/com/quollwriter/achievements/rules/AchievementRule.java b/src/main/java/com/quollwriter/achievements/rules/AchievementRule.java new file mode 100644 index 00000000..8d9b5e5a --- /dev/null +++ b/src/main/java/com/quollwriter/achievements/rules/AchievementRule.java @@ -0,0 +1,51 @@ +package com.quollwriter.achievements.rules; + +import java.util.*; + +import org.dom4j.*; + +import javafx.beans.property.*; + +import com.quollwriter.ui.fx.*; +import com.quollwriter.ui.fx.viewers.*; + +public interface AchievementRule +{ + + public StringProperty nameProperty (); + + public StringProperty descriptionProperty (); + + // TODO Remove? public String getName (); + + public String getIcon (); + + // TODO Remove? public String getDescription (); + + public String getId (); + + public Set getEventIds (); + + public boolean shouldPersistState (); + + public boolean isEventTrigger (); + + public boolean isHidden (); + + public String getCategory (); + + public boolean achieved (AbstractProjectViewer viewer, + ProjectEvent ev) + throws Exception; + + public boolean achieved (ProjectEvent ev) + throws Exception; + + public boolean achieved (AbstractProjectViewer viewer) + throws Exception; + + public void init (Element root); + + public void fillState (Element root); + +} diff --git a/src/com/quollwriter/achievements/rules/AchievementRuleFactory.java b/src/main/java/com/quollwriter/achievements/rules/AchievementRuleFactory.java similarity index 76% rename from src/com/quollwriter/achievements/rules/AchievementRuleFactory.java rename to src/main/java/com/quollwriter/achievements/rules/AchievementRuleFactory.java index 01165051..1092d8fa 100644 --- a/src/com/quollwriter/achievements/rules/AchievementRuleFactory.java +++ b/src/main/java/com/quollwriter/achievements/rules/AchievementRuleFactory.java @@ -1,79 +1,79 @@ package com.quollwriter.achievements.rules; -import org.jdom.*; +import org.dom4j.*; -import com.gentlyweb.xml.*; +import com.quollwriter.*; public class AchievementRuleFactory { - + public class XMLConstants { - + public static final String type = "type"; - + } - + public static AchievementRule createRule (Element root) - throws JDOMException + throws GeneralException { - - String type = JDOMUtils.getAttributeValue (root, + + String type = DOM4JUtils.attributeValue (root, XMLConstants.type, true); - + // TODO: Make this nicer. if (type.equals (ItemAchievementRule.RULE_TYPE)) { - + return new ItemAchievementRule (root); - + } - + if (type.equals (EventAchievementRule.RULE_TYPE)) { - + return new EventAchievementRule (root); - + } if (type.equals (SessionAchievementRule.RULE_TYPE)) { - + return new SessionAchievementRule (root); - + } if (type.equals (WordCountAchievementRule.RULE_TYPE)) { - + return new WordCountAchievementRule (root); - + } if (type.equals (WordAchievementRule.RULE_TYPE)) { - + return new WordAchievementRule (root); - + } if (type.equals (SentenceAchievementRule.RULE_TYPE)) { - + return new SentenceAchievementRule (root); - + } - + if (type.equals (EditorMessageAchievementRule.RULE_TYPE)) { - + return new EditorMessageAchievementRule (root); - + } return null; - + } - -} \ No newline at end of file + +} diff --git a/src/main/java/com/quollwriter/achievements/rules/EditorMessageAchievementRule.java b/src/main/java/com/quollwriter/achievements/rules/EditorMessageAchievementRule.java new file mode 100644 index 00000000..fa8ffbb8 --- /dev/null +++ b/src/main/java/com/quollwriter/achievements/rules/EditorMessageAchievementRule.java @@ -0,0 +1,213 @@ +package com.quollwriter.achievements.rules; + +import java.util.*; + +import org.dom4j.*; + +import com.quollwriter.*; +import com.quollwriter.data.*; +import com.quollwriter.ui.fx.*; +import com.quollwriter.editors.*; +import com.quollwriter.editors.messages.*; + +public class EditorMessageAchievementRule extends AbstractAchievementRule implements EditorMessageListener +{ + + public static final String RULE_TYPE = "editor-message"; + + public class XMLConstants + { + + public static final String messageTypes = "messageTypes"; + public static final String count = "count"; + public static final String sentByMe = "sentByMe"; + public static final String savedCount = "savedCount"; + public static final String match = "match"; + + } + + private Set messageTypes = new HashSet<> (); + private ObjectMatch match = null; + private int count = 0; + private boolean sentByMe = true; + private int savedCount = 0; + + public EditorMessageAchievementRule (Element root) + throws GeneralException + { + + super (root); + + Element mEl = root.element (XMLConstants.match); + + if (mEl != null) + { + + this.match = new ObjectMatch (mEl); + + } + + this.count = DOM4JUtils.attributeValueAsInt (root, + XMLConstants.count, + false); + + if (root.attribute (XMLConstants.sentByMe) != null) + { + + this.sentByMe = DOM4JUtils.attributeValueAsBoolean (root, + XMLConstants.sentByMe, + false); + + } + + String mt = DOM4JUtils.attributeValue (root, + XMLConstants.messageTypes); + + StringTokenizer t = new StringTokenizer (mt.toLowerCase (), + ","); + + while (t.hasMoreTokens ()) + { + + String tok = t.nextToken ().trim (); + + try + { + + EditorMessage m = MessageFactory.getInstance (tok); + + if (this.match != null) + { + + // Just a check to see if the accessor will work. + this.match.match (m); + + } + + this.messageTypes.add (tok); + + } catch (Exception e) { + + throw new GeneralException ("Invalid message type: " + + tok + + ", referenced by: " + + DOM4JUtils.getPath (root), + e); + + } + + } + + EditorsEnvironment.addEditorMessageListener (this); + + } + + public boolean shouldPersistState () + { + + return (this.count > 0); + + } + + public void handleMessage (EditorMessageEvent ev) + { + + if (ev.getType () != EditorMessageEvent.MESSAGE_ADDED) + { + + return; + + } + + EditorMessage mess = ev.getMessage (); + + if (!this.messageTypes.contains (mess.getMessageType ())) + { + + return; + + } + + if ((mess.isSentByMe () && !this.sentByMe) + || + (!mess.isSentByMe () && this.sentByMe) + ) + { + + return; + + } + + try + { + + if ((this.match != null) + && + (!this.match.match (mess)) + ) + { + + return; + + } + + } catch (Exception e) { + + Environment.logError ("Unable to check for message match: " + + mess, + e); + + return; + + } + + this.savedCount++; + + if (this.savedCount < this.count) + { + + return; + + } + + Environment.getAchievementsManager ().userAchievementReached (this); + + EditorsEnvironment.removeEditorMessageListener (this); + + } + + public void init (Element root) + { + + if (this.count > 0) + { + + try + { + + this.savedCount = DOM4JUtils.attributeValueAsInt (root, + XMLConstants.savedCount, + false); + //this.savedCount = 0; + } catch (Exception e) { + + Environment.logError ("Unable to set saved count for rule: " + + this, + e); + + } + + } + + } + + @Override + public void fillState (Element root) + { + + root.addAttribute (XMLConstants.savedCount, + String.valueOf (this.savedCount)); + + } + +} diff --git a/src/main/java/com/quollwriter/achievements/rules/EventAchievementRule.java b/src/main/java/com/quollwriter/achievements/rules/EventAchievementRule.java new file mode 100644 index 00000000..6dc76a97 --- /dev/null +++ b/src/main/java/com/quollwriter/achievements/rules/EventAchievementRule.java @@ -0,0 +1,156 @@ +package com.quollwriter.achievements.rules; + +import java.util.*; + +import org.dom4j.*; + +import com.quollwriter.*; +import com.quollwriter.ui.fx.*; +import com.quollwriter.ui.fx.viewers.*; + +public class EventAchievementRule extends AbstractAchievementRule +{ + + public static final String RULE_TYPE = "event"; + + public class XMLConstants + { + + public static final String count = "count"; + public static final String match = "match"; + + } + + private int count = -1; + private ObjectMatch match = null; + private int matchCount = 0; + + public EventAchievementRule (Element root) + throws GeneralException + { + + super (root); + + this.count = DOM4JUtils.attributeValueAsInt (root, + XMLConstants.count, + false); + + Element mEl = root.element (XMLConstants.match); + + if (mEl != null) + { + + this.match = new ObjectMatch (mEl); + + } + + if (this.getEventIds ().size () == 0) + { + + throw new GeneralException ("Expected at least one event/action to be defined, referenced by: " + + DOM4JUtils.getPath (root)); + + } + + } + + public String toString () + { + + return super.toString () + "(count: " + this.count + ", matched: " + this.matchCount + ", match: " + this.match + ")"; + + } + + public boolean isEventTrigger () + { + + return true; + + } + + public boolean shouldPersistState () + { + + return this.matchCount > 0; + + } + + public boolean achieved (AbstractProjectViewer viewer, + ProjectEvent ev) + throws Exception + { + + return this.achieved (ev); + + } + + public boolean achieved (ProjectEvent ev) + throws Exception + { + + if (this.match != null) + { + + if (!this.match.match (ev.getContextObject ())) + { + + return false; + + } + + } + + this.matchCount++; + + return this.matchCount >= this.count; + + } + + public boolean achieved (AbstractProjectViewer viewer) + { + + return false; + + } + + public void init (Element root) + { + + // Init the count. + try + { + + if (root != null) + { + + this.matchCount = DOM4JUtils.attributeValueAsInt (root, + XMLConstants.count, + false); + + if (this.matchCount < 0) + { + + this.matchCount = 0; + + } + + } + + } catch (Exception e) { + + // Ignore it, for now. + + } + + } + + @Override + public void fillState (Element root) + { + + root.addAttribute (XMLConstants.count, + String.valueOf (this.matchCount)); + + } + +} diff --git a/src/main/java/com/quollwriter/achievements/rules/ItemAchievementRule.java b/src/main/java/com/quollwriter/achievements/rules/ItemAchievementRule.java new file mode 100644 index 00000000..c0524b31 --- /dev/null +++ b/src/main/java/com/quollwriter/achievements/rules/ItemAchievementRule.java @@ -0,0 +1,252 @@ +package com.quollwriter.achievements.rules; + +import java.util.*; + +import org.dom4j.*; + + +import com.quollwriter.*; +import com.quollwriter.data.*; +import com.quollwriter.ui.fx.*; +import com.quollwriter.ui.fx.viewers.*; + +public class ItemAchievementRule extends AbstractAchievementRule +{ + + public static final String RULE_TYPE = "item"; + + public static Map objTypeToClassMapping = new HashMap<> (); + + static + { + + Map m = ItemAchievementRule.objTypeToClassMapping; + + m.put (Note.OBJECT_TYPE, + Note.class); + m.put (Chapter.OBJECT_TYPE, + Chapter.class); + m.put (QCharacter.OBJECT_TYPE, + QCharacter.class); + m.put (QObject.OBJECT_TYPE, + QObject.class); + m.put (Location.OBJECT_TYPE, + Location.class); + m.put (IdeaType.OBJECT_TYPE, + IdeaType.class); + m.put (Idea.OBJECT_TYPE, + Idea.class); + m.put (OutlineItem.OBJECT_TYPE, + OutlineItem.class); + m.put (Scene.OBJECT_TYPE, + Scene.class); + m.put (ResearchItem.OBJECT_TYPE, + ResearchItem.class); + + } + + public class XMLConstants + { + + public static final String action = "action"; + public static final String actions = "actions"; + public static final String objectType = "objectType"; + public static final String count = "count"; + public static final String match = "match"; + public static final String asset = "asset"; + + } + + private Set actions = new HashSet<> (); + private String objType = null; + private ObjectMatch match = null; + private int count = 0; + private Class objClass = null; + private boolean asset = false; + + public ItemAchievementRule (Element root) + throws GeneralException + { + + super (root); + + this.asset = DOM4JUtils.attributeValueAsBoolean (root, + XMLConstants.asset, + false); + + this.objType = DOM4JUtils.attributeValue (root, + XMLConstants.objectType, + true); + + this.objClass = ItemAchievementRule.objTypeToClassMapping.get (this.objType); + + if (this.objClass == null) + { + + throw new GeneralException ("Object type: " + + this.objType + + ", referenced by: " + + DOM4JUtils.getPath (root.attribute (XMLConstants.objectType)) + + " is not supported."); + + } + + String act = DOM4JUtils.attributeValue (root, + XMLConstants.action, + false); + + if (act != null) + { + + this.eventIds.add ((this.asset ? "asset" : this.objType) + "." + act.toLowerCase ()); + + } + + String acts = DOM4JUtils.attributeValue (root, + XMLConstants.actions, + false); + + if (acts != null) + { + + StringTokenizer t = new StringTokenizer (acts, + ",;"); + + while (t.hasMoreTokens ()) + { + + this.eventIds.add ((this.asset ? "asset" : this.objType) + t.nextToken ().toLowerCase ()); + + } + + } + + Element mEl = root.element (XMLConstants.match); + + if (mEl != null) + { + + this.match = new ObjectMatch (mEl); + + } + + this.count = DOM4JUtils.attributeValueAsInt (root, + XMLConstants.count, + false); + + } + + public boolean shouldPersistState () + { + + return false; + + } + + @Override + public boolean achieved (AbstractProjectViewer viewer, + ProjectEvent ev) + throws Exception + { + + return this.achieved (viewer); + + } + + @Override + public boolean achieved (ProjectEvent ev) + { + + return false; + + } + + @Override + public boolean achieved (AbstractProjectViewer viewer) + throws Exception + { + + Set objs = new HashSet<> (); + + if (this.asset) + { + + Set types = viewer.getProject ().getAssetTypes (); + + for (UserConfigurableObjectType t : types) + { + + // This only applies to legacy types. + if ((t.isAssetObjectType ()) + && + (t.isLegacyObjectType ()) + && + (t.getUserObjectType ().equals (this.objType)) + ) + { + + viewer.getProject ().getAssets (t).stream () + .forEach (o -> + { + + objs.add (o); + + }); + break; + + } + } + + } else { + + // Get all the objects of the required type. + viewer.getProject ().getAllNamedChildObjects (this.objClass).stream () + .forEach (o -> + { + + objs.add (o); + + }); + + } + + int c = objs.size (); + + if (this.match != null) + { + + c = 0; + + for (NamedObject n : objs) + { + + if (this.match.match (n)) + { + + c++; + + } + + } + + } + + return c >= this.count; + + } + + @Override + public void init (Element root) + { + + + + } + + @Override + public void fillState (Element root) + { + + } + +} diff --git a/src/main/java/com/quollwriter/achievements/rules/ObjectMatch.java b/src/main/java/com/quollwriter/achievements/rules/ObjectMatch.java new file mode 100644 index 00000000..30c3267f --- /dev/null +++ b/src/main/java/com/quollwriter/achievements/rules/ObjectMatch.java @@ -0,0 +1,153 @@ +package com.quollwriter.achievements.rules; + +import org.dom4j.*; + +import com.quollwriter.data.*; +import com.quollwriter.*; + +public class ObjectMatch +{ + + public class XMLConstants + { + + public static final String accessor = "accessor"; + public static final String value = "value"; + + } + + private Getter accessor = null; + private String value = null; + private String acc = null; + private boolean not = false; + + public ObjectMatch (Element root) + throws GeneralException + { + + this.value = DOM4JUtils.attributeValue (root, + XMLConstants.value, + true); + + if (this.value.startsWith ("!")) + { + + this.not = true; + this.value = this.value.substring (1); + + } + + if (this.value.equals ("null")) + { + + this.value = null; + + } + + this.acc = DOM4JUtils.attributeValue (root, + XMLConstants.accessor, + true); + + } + + public boolean match (Object d) + throws Exception + { + + if ((d == null) + && + (this.acc.equals ("")) + ) + { + + if (this.value == null) + { + + if (this.not) + { + + return false; + + } + + return true; + + } + + } + + if (this.accessor == null) + { + + this.accessor = new Getter (this.acc, + d.getClass ()); + + } + + Object obj = this.accessor.getValue (d); + + if (obj == null) + { + + if (this.value == null) + { + + if (this.not) + { + + return false; + + } + + return true; + + } + + } else { + + if (this.value == null) + { + + if (this.not) + { + + return true; + + } + + return false; + + } + + } + + String v = obj.toString (); + + if (v.equals (this.value)) + { + + if (this.not) + { + + return false; + + } + + return true; + + } else { + + if (this.not) + { + + return true; + + } + + return false; + + } + + } + +} diff --git a/src/main/java/com/quollwriter/achievements/rules/SentenceAchievementRule.java b/src/main/java/com/quollwriter/achievements/rules/SentenceAchievementRule.java new file mode 100644 index 00000000..2c39d70c --- /dev/null +++ b/src/main/java/com/quollwriter/achievements/rules/SentenceAchievementRule.java @@ -0,0 +1,131 @@ +package com.quollwriter.achievements.rules; + +import java.util.*; + +import org.dom4j.*; +import org.dom4j.tree.*; + +import com.quollwriter.*; +import com.quollwriter.data.*; +import com.quollwriter.ui.fx.*; +import com.quollwriter.ui.fx.viewers.*; + +public class SentenceAchievementRule extends AbstractAchievementRule +{ + + public static final String RULE_TYPE = "sentence"; + + public class XMLConstants + { + + public static final String sentenceCount = "sentenceCount"; + public static final String chapterCount = "chapterCount"; + + } + + private int sentenceCount = -1; + private int chapterCount = -1; + + public SentenceAchievementRule (Element root) + throws GeneralException + { + + super (root); + + this.sentenceCount = DOM4JUtils.attributeValueAsInt (root, + XMLConstants.sentenceCount, + false); + + this.chapterCount = DOM4JUtils.attributeValueAsInt (root, + XMLConstants.chapterCount, + false); + + } + + public String toString () + { + + return super.toString () + "(sentence count: " + this.sentenceCount + ", chapter count: " + this.chapterCount + ")"; + + } + + public boolean shouldPersistState () + { + + return false; + + } + + @Override + public boolean achieved (AbstractProjectViewer viewer, + ProjectEvent ev) + throws Exception + { + + return this.achieved (viewer); + + } + + @Override + public boolean achieved (AbstractProjectViewer viewer) + { + + if (viewer.getProject () == null) + { + + throw new IllegalArgumentException ("No project found."); + + } + + Set chapters = viewer.getProject ().getAllNamedChildObjects (Chapter.class); + + if (this.chapterCount > 0) + { + + if (this.chapterCount > chapters.size ()) + { + + return false; + + } + + } + + for (NamedObject c : chapters) + { + + ChapterCounts cc = viewer.getChapterCounts ((Chapter) c); + + if (cc == null) + { + + return false; + + } + + if (cc.getSentenceCount () >= this.sentenceCount) + { + + return true; + + } + + } + + return false; + + } + + @Override + public void init (Element root) + { + + } + + @Override + public void fillState (Element root) + { + + } + +} diff --git a/src/main/java/com/quollwriter/achievements/rules/SessionAchievementRule.java b/src/main/java/com/quollwriter/achievements/rules/SessionAchievementRule.java new file mode 100644 index 00000000..ed7ee77a --- /dev/null +++ b/src/main/java/com/quollwriter/achievements/rules/SessionAchievementRule.java @@ -0,0 +1,471 @@ +package com.quollwriter.achievements.rules; + +import java.util.*; + +import org.dom4j.*; +import org.dom4j.tree.*; + +import com.quollwriter.ui.fx.*; +import com.quollwriter.ui.fx.viewers.*; + +import com.quollwriter.data.*; + +import com.quollwriter.*; + +public class SessionAchievementRule extends AbstractAchievementRule +{ + + public static final String RULE_TYPE = "session"; + + public static final String EDIT = "edit"; + public static final String NO_EDIT = "noedit"; + + public class XMLConstants + { + + + public static final String mins = "mins"; + public static final String wordCount = "wordCount"; + public static final String currentSession = "currentSession"; + public static final String count = "count"; + public static final String days = "days"; + public static final String action = "action"; + public static final String lastChecked = "lastChecked"; + + } + + private int mins = -1; + private int wordCount = 0; + private int count = -1; + private int days = 0; + private String action = null; + private boolean currentSession = false; + + private long lastChecked = 0; + + private List previousSessions = new ArrayList (); + + private SessionData currData = new SessionData (); + + private long lastEdit = -1; + private long startEdit = -1; + + private Set editedChapters = new HashSet (); + + public SessionAchievementRule (Element root) + throws GeneralException + { + + super (root); + + this.action = DOM4JUtils.attributeValue (root, + XMLConstants.action, + false); + + this.currentSession = DOM4JUtils.attributeValueAsBoolean (root, + XMLConstants.currentSession, + false); + + this.count = DOM4JUtils.attributeValueAsInt (root, + XMLConstants.count, + false); + + this.wordCount = DOM4JUtils.attributeValueAsInt (root, + XMLConstants.wordCount, + false); + + this.days = DOM4JUtils.attributeValueAsInt (root, + XMLConstants.days, + false); + + this.mins = DOM4JUtils.attributeValueAsInt (root, + XMLConstants.mins, + false); + + } + + public String toString () + { + + return super.toString () + "(current session: " + this.currentSession + ", action: " + this.action + ", count: " + this.count + ", wordCount: " + this.wordCount + ", days: " + this.days + ", mins: " + this.mins + ", previous session: " + this.previousSessions + ")"; + + } + + public boolean shouldPersistState () + { + + return !this.currentSession || this.lastChecked != 0; + + } + + @Override + public boolean achieved (AbstractProjectViewer viewer, + ProjectEvent ev) + { + + if (ev.getType ().equals (ProjectEvent.Type.project)) + { + + if (ev.getAction ().equals (ProjectEvent.Action.open)) + { + + this.currData.start = System.currentTimeMillis (); + + } + + if (ev.getAction ().equals (ProjectEvent.Action.close)) + { + + this.currData.end = System.currentTimeMillis (); + + this.currData.wordCount = viewer.getSessionWordCount (); + + this.lastChecked = System.currentTimeMillis (); + + } + + } + + long now = System.currentTimeMillis (); + + if (this.currentSession) + { + + if ((ev.getType ().equals (ProjectEvent.Type.chapter)) + && + (ev.getAction ().equals (ProjectEvent.Action.edit)) + ) + { + + if (this.count > 0) + { + + Object o = ev.getContextObject (); + + if (o != null) + { + + if (o instanceof Chapter) + { + + this.editedChapters.add (((Chapter) o).getKey ()); + + } + + if (this.editedChapters.size () >= this.count) + { + + return true; + + } + + } + + } + + if (this.mins > 0) + { + + if (this.lastEdit < 0) + { + + this.lastEdit = now; + this.startEdit = now; + + return false; + + } else { + + if ((now - this.lastEdit) > 300000) + { + + this.startEdit = now; + + } else { + + if ((now - this.startEdit) >= (this.mins * 60000)) + { + + return true; + + } + + } + + this.lastEdit = now; + + } + + } + + } + + } + + if (ev.getType ().equals (ProjectEvent.Type.project)) + { + + if (ev.getAction ().equals (ProjectEvent.Action.open)) + { + + if (NO_EDIT.equals (this.action)) + { + + if (viewer != null) + { + + if (this.lastChecked > 0) + { + + if (this.days > 0) + { + + long diff = now - this.lastChecked; + + long time = (long) 86400000 * (long) this.days; + + if (diff > time) + { + + return true; + + } + + } + + } + + } + + } + + int sessSize = this.previousSessions.size (); + + if ((this.count > 0) + && + (sessSize < this.count) + ) + { + + return false; + + } + + // Check the days. + if (this.days > 0) + { + + long diff = this.previousSessions.get (sessSize - 1).end - this.previousSessions.get (0).start; + + int days = (int) (diff / (24 * 60 * 60 * 1000)); + + if (days != this.days) + { + + return false; + + } + + } + + if (this.wordCount > 0) + { + + // Check each session. + for (SessionData sd : this.previousSessions) + { + + if (sd.wordCount < this.wordCount) + { + + return false; + + } + + } + + } + + return true; + + } + + } + + return false; + + } + + @Override + public boolean achieved (AbstractProjectViewer viewer) + { + + if (this.currentSession) + { + + if (this.wordCount > 0) + { + + if (viewer != null) + { + + return viewer.getSessionWordCount () > this.wordCount; + + } + + } + + } + + return false; + + } + + @Override + public void init (Element root) + + { + + try + { + + for (Element el : root.elements (SessionData.XMLConstants.root)) + { + + this.previousSessions.add (new SessionData (el)); + + } + + } catch (Exception e) { + + // Ignore. + Environment.logError ("Unable to init from: " + + DOM4JUtils.getPath (root), + e); + + } + + try + { + + String lc = DOM4JUtils.attributeValue (root, + XMLConstants.lastChecked, + false); + + if (!lc.equals ("")) + { + + this.lastChecked = Long.parseLong (lc); + + } + + } catch (Exception e) { + + // Ignore... + + } + + } + + @Override + public void fillState (Element root) + { + + if (this.count > 0) + { + + List sessions = new ArrayList<> (this.previousSessions); + + sessions.add (this.currData); + + // Only keep sessions within the past 2 weeks. + long last = System.currentTimeMillis () - (14 * 24 * 60 * 60 * 1000); + + for (SessionData sd : sessions) + { + + if (sd.end < last) + { + + continue; + + } + + root.add (sd.getAsElement ()); + + } + + } + + if (this.lastChecked > 0) + { + + root.addAttribute (XMLConstants.lastChecked, + String.valueOf (this.lastChecked)); + + } + + } + + public class SessionData + { + + public class XMLConstants + { + + public static final String root = "session"; + public static final String start = "start"; + public static final String end = "end"; + public static final String wordCount = "wordCount"; + + } + + public long start = 0; + public long end = 0; + public int wordCount = 0; + + public SessionData () + { + + } + + public SessionData (Element root) + throws GeneralException + { + + this.start = Long.parseLong (DOM4JUtils.attributeValue (root, + XMLConstants.start)); + this.end = Long.parseLong (DOM4JUtils.attributeValue (root, + XMLConstants.end)); + + this.wordCount = DOM4JUtils.attributeValueAsInt (root, + XMLConstants.wordCount); + this.wordCount = 560; + } + + public Element getAsElement () + { + + Element root = new DefaultElement (XMLConstants.root); + + root.addAttribute (XMLConstants.start, + String.valueOf (this.start)); + root.addAttribute (XMLConstants.end, + String.valueOf (this.end)); + root.addAttribute (XMLConstants.wordCount, + String.valueOf (this.wordCount)); + + return root; + + } + + public String toString () + { + + return "start: " + new Date (this.start) + ", end: " + new Date (this.end) + ", word count: " + this.wordCount; + + } + + } + +} diff --git a/src/main/java/com/quollwriter/achievements/rules/WordAchievementRule.java b/src/main/java/com/quollwriter/achievements/rules/WordAchievementRule.java new file mode 100644 index 00000000..39151a80 --- /dev/null +++ b/src/main/java/com/quollwriter/achievements/rules/WordAchievementRule.java @@ -0,0 +1,179 @@ +package com.quollwriter.achievements.rules; + +import java.util.*; + +import org.dom4j.*; + +import com.quollwriter.*; +import com.quollwriter.data.*; +import com.quollwriter.ui.fx.*; +import com.quollwriter.ui.fx.viewers.*; + +public class WordAchievementRule extends AbstractAchievementRule +{ + + public static final String RULE_TYPE = "word"; + + public class XMLConstants + { + + public static final String wordCount = "wordCount"; + public static final String count = "count"; + public static final String chapter = "chapter"; + public static final String allowRepeats = "allowRepeats"; + public static final String words = "words"; + + } + + private int count = -1; + private boolean allowRepeats = false; + private boolean chaptersOnly = false; + private Map words = new HashMap (); + + public WordAchievementRule (Element root) + throws GeneralException + { + + super (root); + + this.allowRepeats = DOM4JUtils.attributeValueAsBoolean (root, + XMLConstants.allowRepeats, + false); + + this.count = DOM4JUtils.attributeValueAsInt (root, + XMLConstants.count, + false); + + this.chaptersOnly = DOM4JUtils.attributeValueAsBoolean (root, + XMLConstants.chapter, + false); + + if ((this.count < 1) + && + (this.chaptersOnly) + ) + { + + this.count = 1; + + } + + String w = root.attributeValue (XMLConstants.words); + + if (w == null) + { + + DOM4JUtils.raiseException ("Expected: %1$s to have an attribute: %2$s", + root, + XMLConstants.words); + + } + + StringTokenizer t = new StringTokenizer (w, + ",;"); + + while (t.hasMoreTokens ()) + { + + this.words.put (t.nextToken ().trim ().toLowerCase (), + ""); + + } + + } + + public String toString () + { + + return super.toString () + "(count: " + this.count + ", words: " + this.words + ", chapters only: " + this.chaptersOnly + ", allow repeats: " + this.allowRepeats + ")"; + + } + + @Override + public boolean shouldPersistState () + { + + return false; + + } + + @Override + public boolean achieved (AbstractProjectViewer viewer, + ProjectEvent ev) + throws Exception + { + + return this.achieved (viewer); + + } + + @Override + public boolean achieved (AbstractProjectViewer viewer) + { + + if (this.chaptersOnly) + { + + Set counts = viewer.getAllChapterCountsAsSet (); + + for (ChapterCounts cc : counts) + { + + int c = 0; + + for (String w : this.words.keySet ()) + { + + if (cc.wordFrequency != null) + { + + Integer wc = cc.wordFrequency.get (w); + + if (wc != null) + { + + if (this.allowRepeats) + { + + c += wc.intValue (); + + } else { + + c++; + + } + + } + + } + + } + + if (c >= this.count) + { + + return true; + + } + + } + + } + + return false; + + } + + @Override + public void init (Element root) + { + + } + + @Override + public void fillState (Element root) + { + + } + +} diff --git a/src/main/java/com/quollwriter/achievements/rules/WordCountAchievementRule.java b/src/main/java/com/quollwriter/achievements/rules/WordCountAchievementRule.java new file mode 100644 index 00000000..4c1007b2 --- /dev/null +++ b/src/main/java/com/quollwriter/achievements/rules/WordCountAchievementRule.java @@ -0,0 +1,144 @@ +package com.quollwriter.achievements.rules; + +import java.util.*; + +import org.dom4j.*; + +import com.quollwriter.*; +import com.quollwriter.data.*; +import com.quollwriter.ui.fx.*; +import com.quollwriter.ui.fx.viewers.*; + +public class WordCountAchievementRule extends AbstractAchievementRule +{ + + public static final String RULE_TYPE = "wordcount"; + + public class XMLConstants + { + + public static final String wordCount = "wordCount"; + public static final String count = "count"; + public static final String chapter = "chapter"; + + } + + private int count = -1; + private int wordCount = 0; + private boolean chaptersOnly = false; + + public WordCountAchievementRule (Element root) + throws GeneralException + { + + super (root); + + this.count = DOM4JUtils.attributeValueAsInt (root, + XMLConstants.count, + false); + + this.wordCount = DOM4JUtils.attributeValueAsInt (root, + XMLConstants.wordCount, + true); + + this.chaptersOnly = DOM4JUtils.attributeValueAsBoolean (root, + XMLConstants.chapter, + false); + + if ((this.count < 1) + && + (this.chaptersOnly) + ) + { + + this.count = 1; + + } + + } + + public String toString () + { + + return super.toString () + "(count: " + this.count + ", wordCount: " + this.wordCount + ", chapters only: " + this.chaptersOnly + ")"; + + } + + public boolean shouldPersistState () + { + + return false; + + } + + public boolean achieved (AbstractProjectViewer viewer, + ProjectEvent ev) + throws Exception + { + + return this.achieved (viewer); + + } + + public boolean achieved (AbstractProjectViewer viewer) + { + + if (viewer == null) + { + + return false; + + } + + if (this.chaptersOnly) + { + + int c = 0; + + Set counts = viewer.getAllChapterCountsAsSet (); + + for (ChapterCounts cc : counts) + { + + if (cc.getWordCount () >= this.wordCount) + { + + c++; + + } + + } + + if (c >= this.count) + { + + return true; + + } + + } + + if (viewer.getAllChapterCounts ().getWordCount () >= this.wordCount) + { + + return true; + + } + + return false; + + } + + @Override + public void init (Element root) + { + + } + + @Override + public void fillState (Element root) + { + + } + +} diff --git a/src/com/quollwriter/achievements/ui/AchievementBox.java b/src/main/java/com/quollwriter/achievements/ui/AchievementBox.java similarity index 85% rename from src/com/quollwriter/achievements/ui/AchievementBox.java rename to src/main/java/com/quollwriter/achievements/ui/AchievementBox.java index 5a60b1a1..629f0d8b 100644 --- a/src/com/quollwriter/achievements/ui/AchievementBox.java +++ b/src/main/java/com/quollwriter/achievements/ui/AchievementBox.java @@ -13,45 +13,45 @@ public class AchievementBox extends Box { - + private AchievementRule rule = null; - + private ImagePanel ip = null; - + public AchievementBox (AchievementRule ar, boolean achieved, boolean limitDescSize) { - + super (BoxLayout.X_AXIS); - - this.rule = ar; - + + this.rule = ar; + this.ip = new ImagePanel (this.getIcon (achieved), null); - + this.ip.setAlignmentY (JComponent.TOP_ALIGNMENT); - + this.add (this.ip); this.add (Box.createHorizontalStrut (5)); Box t = new Box (BoxLayout.Y_AXIS); t.setAlignmentY (JComponent.TOP_ALIGNMENT); - + this.add (t); - - JLabel name = new JLabel (Environment.replaceObjectNames (ar.getName ())); - - name.setFont (name.getFont ().deriveFont ((float) UIUtils.getScaledFontSize (14)).deriveFont (Font.PLAIN)); + + JLabel name = new JLabel (Environment.replaceObjectNames (ar.nameProperty ().getValue ())); + + name.setFont (name.getFont ().deriveFont ((float) UIUtils.getScaledFontSize (14)).deriveFont (Font.PLAIN)); name.setAlignmentX (JComponent.LEFT_ALIGNMENT); - + t.add (name); - - JTextArea desc = new JTextArea (Environment.replaceObjectNames (ar.getDescription ())); + + JTextArea desc = new JTextArea (Environment.replaceObjectNames (ar.descriptionProperty ().getValue ())); desc.setAlignmentX (JComponent.LEFT_ALIGNMENT); - + if (limitDescSize) { @@ -67,45 +67,45 @@ public AchievementBox (AchievementRule ar, desc.setBorder (new EmptyBorder (3, 5, 0, 5)); t.add (desc); - + this.setAlignmentX (JComponent.LEFT_ALIGNMENT); this.setBorder (new EmptyBorder (5, 5, 5, 5)); this.setMinimumSize (new Dimension (200, - this.getPreferredSize ().height)); - + this.getPreferredSize ().height)); + } - + public void setAchieved (boolean achieved) { - + this.ip.setIcon (this.getIcon (achieved)); - + } - + private ImageIcon getIcon (boolean achieved) { - + ImageIcon image = null; - + try { - + image = (this.rule.getIcon () != null ? Environment.getIcon (this.rule.getIcon (), Constants.ICON_ACHIEVEMENT_HEADER) : Environment.getAchievementIcon ()); - + } catch (Exception e) { - + // Ignore. - + } - + if (image == null) { - + image = Environment.getAchievementIcon (); - + } - + image.setImage (image.getImage ().getScaledInstance (24, 24, Image.SCALE_SMOOTH)); if (achieved) @@ -113,24 +113,24 @@ private ImageIcon getIcon (boolean achieved) ImageIcon tick =Environment.getIcon ("tick", Constants.ICON_ACHIEVEMENT_HEADER); - + tick.setImage (tick.getImage ().getScaledInstance (12, 12, Image.SCALE_SMOOTH)); image = UIUtils.overlayImage (image, tick, "br"); - } - + } + return image; - + } - + public AchievementRule getRule () { - + return this.rule; - + } - -} \ No newline at end of file + +} diff --git a/src/com/quollwriter/achievements/ui/Achievements.java b/src/main/java/com/quollwriter/achievements/ui/Achievements.java similarity index 97% rename from src/com/quollwriter/achievements/ui/Achievements.java rename to src/main/java/com/quollwriter/achievements/ui/Achievements.java index 1cd74889..b2cf0102 100644 --- a/src/com/quollwriter/achievements/ui/Achievements.java +++ b/src/main/java/com/quollwriter/achievements/ui/Achievements.java @@ -63,7 +63,7 @@ public void achievementReached (AchievementReachedEvent ev) AchievementsManager man = Environment.getAchievementsManager (); - Map> achieved = man.getAchievedAchievementIds (this.viewer); + Map> achieved = null; // TODO man.getAchievedAchievementIds (this.viewer); Box b = this.boxes.get (t); @@ -156,7 +156,7 @@ public void init () final AchievementsManager man = Environment.getAchievementsManager (); - man.addAchievementReachedListener (this); + // TODO man.addAchievementReachedListener (this); this.add (header); @@ -175,7 +175,7 @@ public void init () Set userRules = man.getUserRules (); - Map> achieved = man.getAchievedAchievementIds (this.viewer); + Map> achieved = null; // TODO man.getAchievedAchievementIds (this.viewer); Box main = new Box (BoxLayout.Y_AXIS); @@ -301,7 +301,7 @@ private JComponent getAchievementsBox (Set rules, ab.setVisible (true); - ab.setBorder (new CompoundBorder (new MatteBorder (0, 0, 1, 0, Environment.getInnerBorderColor ()), + ab.setBorder (new CompoundBorder (new MatteBorder (0, 0, 1, 0, UIUtils.getInnerBorderColor ()), ab.getBorder ())); } else { @@ -311,7 +311,7 @@ private JComponent getAchievementsBox (Set rules, if (c < (rules.size () - 1)) { - ab.setBorder (new CompoundBorder (new MatteBorder (0, 0, 1, 0, Environment.getInnerBorderColor ()), + ab.setBorder (new CompoundBorder (new MatteBorder (0, 0, 1, 0, UIUtils.getInnerBorderColor ()), ab.getBorder ())); } diff --git a/src/com/quollwriter/data/Asset.java b/src/main/java/com/quollwriter/data/Asset.java similarity index 100% rename from src/com/quollwriter/data/Asset.java rename to src/main/java/com/quollwriter/data/Asset.java diff --git a/src/main/java/com/quollwriter/data/BlankNamedObject.java b/src/main/java/com/quollwriter/data/BlankNamedObject.java new file mode 100644 index 00000000..c026205d --- /dev/null +++ b/src/main/java/com/quollwriter/data/BlankNamedObject.java @@ -0,0 +1,58 @@ +package com.quollwriter.data; + +import java.util.*; +import javafx.beans.property.*; + +import org.dom4j.*; + + +public class BlankNamedObject extends NamedObject +{ + + public BlankNamedObject() + { + + super (null); + + } + + public BlankNamedObject (String objType) + { + + super (objType); + + } + + public BlankNamedObject(String objType, + String name) + { + + super (objType, + name); + + } + + @Override + public void getChanges (NamedObject old, + Element root) + { + + } + + @Override + public void setObjectType (String t) + { + + super.setObjectType (t); + + } + + @Override + public Set getAllNamedChildObjects () + { + + return new HashSet<> (); + + } + +} diff --git a/src/com/quollwriter/data/Book.java b/src/main/java/com/quollwriter/data/Book.java similarity index 85% rename from src/com/quollwriter/data/Book.java rename to src/main/java/com/quollwriter/data/Book.java index 13cbb822..d739a039 100644 --- a/src/com/quollwriter/data/Book.java +++ b/src/main/java/com/quollwriter/data/Book.java @@ -4,7 +4,7 @@ import java.util.*; -import com.gentlyweb.xml.*; +import javafx.collections.*; import com.quollwriter.*; @@ -12,9 +12,7 @@ import com.quollwriter.text.*; -import com.quollwriter.ui.events.*; - -import org.jdom.*; +import org.dom4j.*; public class Book extends NamedObject @@ -31,8 +29,8 @@ public class XMLConstants } - private Project project = null; - private List chapters = new ArrayList (); + // TODO Change to use a set. + private ObservableList chapters = FXCollections.observableList (new ArrayList<> ()); private ChapterSorter sort = null; public Book() @@ -47,9 +45,7 @@ public Book(Project p) super (Book.OBJECT_TYPE); - this.project = p; - - this.setParent (p); + this.setProject (p); } @@ -68,13 +64,13 @@ public void fillToStringProperties (Map props) { super.fillToStringProperties (props); - + this.addToStringProperties (props, "chapterCount", this.chapters.size ()); - + } - + public void setChapterSorter (ChapterSorter c) { @@ -90,12 +86,14 @@ public void setChapterSorter (ChapterSorter c) } + @Override public void getChanges (NamedObject old, Element root) { } + @Override public Set getAllNamedChildObjects () { @@ -116,89 +114,75 @@ public Set getAllNamedChildObjects () public void removeAllChapters () { - + synchronized (this) { - + for (Chapter c : this.chapters) { - + c.setBook (null); - + } - this.chapters = new ArrayList (); - + this.chapters.clear (); + } - + } - +/* +TODO Remove private void setChapters (List c) { this.chapters = c; } - - void setProject (Project p) - { - - this.project = p; - - this.setParent (p); - - } - - public Project getProject () - { - - return this.project; - - } +*/ public Chapter getFirstChapter () { - + if (this.chapters == null) { - + return null; - + } - + if (this.chapters.size () == 0) { - + return null; - + } - + return this.chapters.get (0); - + } - + public Chapter getLastChapter () { - + if (this.chapters == null) { - + return null; - + } - + if (this.chapters.size () == 0) { - + return null; - + } - + return this.chapters.get (this.chapters.size () - 1); - + } - public List getChapters () + public ObservableList getChapters () { return this.chapters; @@ -207,54 +191,54 @@ public List getChapters () public int getChapterWordCount () { - + int i = 0; - + for (Chapter c : this.chapters) { - + String t = (c.getText () != null ? c.getText ().getText () : null); - + i += TextUtilities.getWordCount (t); - + } - + return i; - + } - + public int getChapterIndex (Chapter c) { // This can happen for imports when no key has been assigned yet. if (c.getKey () == null) { - + for (int i = 0; i < this.chapters.size (); i++) { - + Chapter cc = this.chapters.get (i); - + if (cc.getName ().equals (c.getName ())) { - + return i; - + } - + } - + return -1; - + } int ind = this.chapters.indexOf (c); - + if (ind > -1) { - + ind++; - + } return ind; @@ -291,7 +275,7 @@ public void removeChapter (Chapter c) { c.setBook (null); - + this.chapters.remove (c); } @@ -299,13 +283,13 @@ public void removeChapter (Chapter c) public void moveChapter (Chapter c, int newIndex) { - + Book b = c.getBook (); - + this.removeChapter (c); c.setBook (b); - + this.chapters.add (newIndex, c); @@ -334,9 +318,9 @@ public Chapter getChapter (Long key) public Set getAllChaptersWithName (String name) { - + Set ret = new LinkedHashSet (); - + for (int i = 0; i < this.chapters.size (); i++) { @@ -354,7 +338,7 @@ public Set getAllChaptersWithName (String name) return ret; } - + public Chapter getChapterByName (String name) { @@ -425,23 +409,23 @@ public Chapter createChapterAfter (Chapter after, public void addChapter (Chapter c) { - + this.addChapter (c, -1); } - private void addChapter (Chapter c, - int where) + public void addChapter (Chapter c, + int where) { if (this.chapters.contains (c)) { - + return; - + } - + if ((where > this.chapters.size ()) || (where < 0)) { @@ -451,7 +435,7 @@ private void addChapter (Chapter c, } c.setBook (this); - + this.chapters.add (where, c); diff --git a/src/main/java/com/quollwriter/data/Chapter.java b/src/main/java/com/quollwriter/data/Chapter.java new file mode 100644 index 00000000..5ecf4e7e --- /dev/null +++ b/src/main/java/com/quollwriter/data/Chapter.java @@ -0,0 +1,1606 @@ +package com.quollwriter.data; + +import java.io.*; + +import java.util.*; + +import javax.swing.text.Position; +import javax.swing.text.Document; + +import javafx.collections.*; +import javafx.beans.property.*; + +import com.quollwriter.*; +import com.quollwriter.data.comparators.*; + +import org.incava.util.diff.*; + +import org.dom4j.*; +import org.dom4j.tree.*; + +import org.reactfx.*; + +import com.quollwriter.text.*; + +public class Chapter extends LegacyUserConfigurableObject +{ + + public static final String PLAN_LEGACY_FIELD_ID = "plan"; + public static final String GOALS_LEGACY_FIELD_ID = "goals"; + + public static final String OBJECT_TYPE = "chapter"; + public static final String INFORMATION_OBJECT_TYPE = "chapterinformation"; + public static final String EDIT_POSITION = "editposition"; + + private Book book = null; + private StringWithMarkup text = null; + private StringWithMarkup goals = null; + private StringWithMarkup plan = null; + private ObjectProperty planProp = new SimpleObjectProperty<> (); + private ObservableSet outlineItems = FXCollections.observableSet (new TreeSet<> (new ChapterItemSorter ())); + private ObservableSet scenes = FXCollections.observableSet (new TreeSet<> (new ChapterItemSorter ())); + private int editPosition = -1; + + private IntegerProperty editPositionProp = new SimpleIntegerProperty (-1); + //private Position textEditPos = null; + private boolean editComplete = false; + private BooleanProperty editCompleteProp = new SimpleBooleanProperty (false); + private ObservableSet problemFinderIgnores = FXCollections.observableSet (new HashSet<> ()); + + private ProjectVersion projVersion = null; + + private EventSource> chapterItemsEventSource = new EventSource<> (); + private EventSource chapterItemsPositionEventSource = new EventSource<> (); + private Map> eventSourceSubscriptions = new HashMap<> (); + + public Chapter() + { + + super (Chapter.OBJECT_TYPE); + + this.outlineItems.addListener ((SetChangeListener) ev -> + { + + if (ev.wasRemoved ()) + { + + OutlineItem it = ev.getElementRemoved (); + + it.dispose (); + + this.chapterItemsEventSource.push (new CollectionEvent (this.outlineItems, + it, + CollectionEvent.Type.remove)); + + } + + if (ev.wasAdded ()) + { + + OutlineItem it = ev.getElementAdded (); + + this.chapterItemsEventSource.push (new CollectionEvent (this.outlineItems, + it, + CollectionEvent.Type.add)); + + it.addChangeListener (it.positionProperty (), + (pr, oldv, newv) -> + { + + this.chapterItemsPositionEventSource.push (new ChapterItem.ChapterItemEvent (it, + ChapterItem.ChapterItemEvent.Type.positionchange, + pr, + oldv.intValue (), + newv.intValue ())); + + }); + + } + + }); + + this.scenes.addListener ((SetChangeListener) ev -> + { + + if (ev.wasAdded ()) + { + + Scene it = ev.getElementAdded (); + + this.chapterItemsEventSource.push (new CollectionEvent (this.scenes, + it, + CollectionEvent.Type.add)); + + it.addChangeListener (it.positionProperty (), + (pr, oldv, newv) -> + { + + this.chapterItemsPositionEventSource.push (new ChapterItem.ChapterItemEvent (it, + ChapterItem.ChapterItemEvent.Type.positionchange, + pr, + oldv.intValue (), + newv.intValue ())); + + }); + + List subs = new ArrayList<> (); + subs.add (it.outlineItemsPositionEvents ().subscribe (oev -> + { + + this.chapterItemsPositionEventSource.push (oev); + + })); + subs.add (it.outlineItemsEvents ().subscribe (oev -> + { + + this.chapterItemsEventSource.push (oev); + + })); + + this.eventSourceSubscriptions.put (it, + subs); + + } + + if (ev.wasRemoved ()) + { + + Scene s = ev.getElementRemoved (); + + s.dispose (); + + // Need to unsubscribe from the scene AND the outline items set... + this.eventSourceSubscriptions.get (s).stream () + .forEach (ss -> ss.unsubscribe ()); + + this.chapterItemsEventSource.push (new CollectionEvent (this.scenes, + ev.getElementRemoved (), + CollectionEvent.Type.remove)); + + } + + }); + + this.getNotes ().addListener ((SetChangeListener) ev -> + { + + if (ev.wasAdded ()) + { + + Note it = ev.getElementAdded (); + + this.chapterItemsEventSource.push (new CollectionEvent (this.getNotes (), + it, + CollectionEvent.Type.add)); + + it.addChangeListener (it.positionProperty (), + (pr, oldv, newv) -> + { + + this.chapterItemsPositionEventSource.push (new ChapterItem.ChapterItemEvent (it, + ChapterItem.ChapterItemEvent.Type.positionchange, + pr, + oldv.intValue (), + newv.intValue ())); + + }); + + } + + if (ev.wasRemoved ()) + { + + Note s = ev.getElementRemoved (); + + // NamedObject handles the removal and disposes. + + this.chapterItemsEventSource.push (new CollectionEvent (this.getNotes (), + ev.getElementRemoved (), + CollectionEvent.Type.remove)); + + } + + }); + + } + + public Chapter(Book b) + { + + this (); + + this.setBook (b); + + } + + public Chapter(Book b, + String name) + { + + this (b); + + this.setName (name); + + } + + protected Chapter(String objType) + { + + super (objType); + + } + + public EventStream> chapterItemsEvents () + { + + return this.chapterItemsEventSource; + + } + + public EventStream chapterItemsPositionEvents () + { + + return this.chapterItemsPositionEventSource; + + } + + public boolean isFieldSupported (String id) + { + + if ((id.equals (DESCRIPTION_LEGACY_FIELD_ID)) + || + (id.equals (ALIASES_LEGACY_FIELD_ID)) + || + (id.equals (PLAN_LEGACY_FIELD_ID)) + || + (id.equals (GOALS_LEGACY_FIELD_ID)) + ) + { + + return true; + + } + + return false; + + } + + public void initProblemFinderIgnoreDocumentPositions (Document doc) + throws Exception + { + + for (Issue i : this.problemFinderIgnores) + { + + i.setStartPosition (doc.createPosition (i.getStartIssuePosition ())); + + } + + } + + public Set getProblemFinderIgnores (Rule forRule) + { + + Set ignores = new LinkedHashSet<> (); + + for (Issue i : this.problemFinderIgnores) + { + + if (i.getRuleId ().equals (forRule.getId ())) + { + + ignores.add (i); + + } + + } + + return ignores; + + } + + public ObservableSet getProblemFinderIgnores () + { + + return this.problemFinderIgnores; + + } + + public void setProblemFinderIgnores (Set ignores) + { + + this.problemFinderIgnores.clear (); + + this.problemFinderIgnores.addAll (ignores); + + } + + public void setProjectVersion (ProjectVersion v) + { + + this.projVersion = v; + + } + + public ProjectVersion getProjectVersion () + { + + if (this.projVersion == null) + { + + return this.getBook ().getProject ().getProjectVersion (); + + } + + return this.projVersion; + + } + + /** + * If a chapter item has it's position changed (say via a drag/drop operation to move it) + * then the sets need to be "reindexed" since the ordering is dependent on the position and + * it is only done once when the item is added (probably for performance sake). + * + * This method recreates the sets backing the scenes/notes/outline items and calls the + * same reindex method on child objects, so re-initing the entire tree. + */ + /* + public synchronized void reindex () + { + + super.reindex (); + + TreeSet sscenes = new TreeSet (new ChapterItemSorter ()); + + sscenes.addAll (this.scenes); + + this.scenes = sscenes; + + TreeSet ooutlineItems = new TreeSet (new ChapterItemSorter ()); + + ooutlineItems.addAll (this.outlineItems); + + this.outlineItems = ooutlineItems; + + for (Scene s : this.scenes) + { + + s.reindex (); + + } + + for (OutlineItem it : this.outlineItems) + { + + it.reindex (); + + } + + } +*/ + public boolean isEditComplete () + { + + return this.editComplete; + + } + + public void setEditComplete (boolean b) + { + + this.editComplete = b; + this.editCompleteProp.setValue (b); + + } + + public BooleanProperty editCompleteProperty () + { + + return this.editCompleteProp; + + } + + /* + public String getMarkup () + { + + return this.markup; + + } + + public void setMarkup (String m) + { + + this.markup = m; + + } +*/ + @Override + public void getChanges (NamedObject old, + Element root) + { + + Chapter c = (Chapter) old; + + this.addFieldChangeElement (root, + "goals", + ((old != null) ? c.getGoals () : null), + this.goals); + + this.addFieldChangeElement (root, + "plan", + ((old != null) ? c.getPlan () : null), + this.plan); + + if (old != null) + { + + String ot = c.getChapterText (); + + if (ot == null) + { + + ot = ""; + + } + + ot = TextUtilities.stripNonValidXMLCharacters (ot); + + String nt = this.getChapterText (); + + if (nt == null) + { + + nt = ""; + + } + + nt = TextUtilities.stripNonValidXMLCharacters (nt); + + String[] oldText = ot.split ("\\n"); + String[] newText = nt.split ("\\n"); + + List diffs = new Diff (oldText, + newText).diff (); + + if (diffs.size () > 0) + { + + Element fieldEl = new DefaultElement ("field"); + + root.add (fieldEl); + + fieldEl.addAttribute ("name", + "text"); + + fieldEl.addAttribute ("type", + "diff"); + + for (int i = 0; i < diffs.size (); i++) + { + + Difference d = (Difference) diffs.get (i); + + if (d.getDeletedEnd () == Difference.NONE) + { + + // This is an addition. + for (int k = d.getAddedStart (); k < (d.getAddedEnd () + 1); k++) + { + + Element el = new DefaultElement ("change"); + fieldEl.add (el); + el.addAttribute ("type", + "add"); + el.addAttribute ("line", + String.valueOf (k)); + el.add (new DefaultCDATA (newText[k])); + + } + + continue; + + } + + if (d.getAddedEnd () == Difference.NONE) + { + + // This is a deletion. + for (int k = d.getDeletedStart (); k < (d.getDeletedEnd () + 1); k++) + { + + Element el = new DefaultElement ("change"); + fieldEl.add (el); + el.addAttribute ("type", + "remove"); + el.addAttribute ("line", + String.valueOf (k)); + el.add (new DefaultCDATA (oldText[k])); + + } + + continue; + + } + + // This is a modification. + for (int k = d.getAddedStart (); k < (d.getAddedEnd () + 1); k++) + { + + Element el = new DefaultElement ("change"); + fieldEl.add (el); + el.addAttribute ("type", + "change"); + el.addAttribute ("line", + String.valueOf (k)); + + Element oel = new DefaultElement ("old"); + el.add (oel); + + ot = ""; + + if (k < oldText.length) + { + + ot = oldText[k]; + + } + + oel.add (new DefaultCDATA (ot)); + + Element nel = new DefaultElement ("new"); + el.add (nel); + + nt = ""; + + if (k < newText.length) + { + + nt = newText[k]; + + } + + nel.add (new DefaultCDATA (nt)); + + } + + } + + } + + } else + { + + this.addFieldChangeElement (root, + "text", + null, + this.getChapterText ()); + + } + + } + + @Override + public DataObject getObjectForReference (ObjectReference r) + { + + DataObject d = super.getObjectForReference (r); + + if (d != null) + { + + return d; + + } + + for (Scene s : this.scenes) + { + + d = s.getObjectForReference (r); + + if (d != null) + { + + return d; + + } + + } + + for (OutlineItem i : this.outlineItems) + { + + d = i.getObjectForReference (r); + + if (d != null) + { + + return d; + + } + + } + + return null; + + } + + public Set getChapterItemsWithPositionGreaterThan (int pos) + { + + Set items = new TreeSet<> (new ChapterItemSorter ()); + + for (OutlineItem it : this.outlineItems) + { + + if (it.getPosition () > pos) + { + + items.add (it); + + } + + } + + for (Scene s : this.scenes) + { + + if (s.getPosition () > pos) + { + + items.add (s); + + } + + } + + for (Note n : this.getNotes ()) + { + + if (n.getPosition () > pos) + { + + items.add (n); + + } + + } + + return items; + + } + + public Set getChapterItemsWithPositionBetween (int start, + int end) + { + + Set items = new TreeSet<> (new ChapterItemSorter ()); + + for (OutlineItem it : this.outlineItems) + { + + if ((it.getPosition () >= start) + && + (it.getPosition () <= end) + ) + { + + items.add (it); + + } + + } + + for (Scene s : this.scenes) + { + + if ((s.getPosition () >= start) + && + (s.getPosition () <= end) + ) + { + + items.add (s); + + } + + } + + for (Note n : this.getNotes ()) + { + + if ((n.getPosition () >= start) + && + (n.getPosition () <= end) + ) + { + + items.add (n); + + } + + } + + return items; + + } + + public Set getItemsFromPositionToNextScene (int pos) + { + + Set items = new TreeSet<> (new ChapterItemSorter ()); + + for (OutlineItem it : this.outlineItems) + { + + if (it.getPosition () >= pos) + { + + items.add (it); + + } + + } + + Scene s = this.getLastScene (pos); + + if (s != null) + { + + for (OutlineItem it : s.getOutlineItems ()) + { + + if (it.getPosition () >= pos) + { + + items.add (it); + + } + + } + + } + + return items; + + } + + public Scene getSceneAt (int pos) + { + + for (Scene s : this.scenes) + { + + if (s.getPosition () == pos) + { + + return s; + + } + + } + + return null; + + } + + public Set getScenesAt (int pos) + { + + Set scenes = new TreeSet (new ChapterItemSorter ()); + + for (Scene s : this.scenes) + { + + if (s.getPosition () == pos) + { + + scenes.add (s); + + } + + } + + return scenes; + + } + + public OutlineItem getOutlineItemAt (int pos) + { + + for (Scene s : this.scenes) + { + + OutlineItem it = s.getOutlineItemAt (pos); + + if (it != null) + { + + return it; + + } + + } + + for (OutlineItem it : this.outlineItems) + { + + if (it.getPosition () == pos) + { + + return it; + + } + + } + + return null; + + } + + public Set getOutlineItemsAt (int pos) + { + + Set its = new TreeSet<> (new ChapterItemSorter ()); + + for (Scene s : this.scenes) + { + + its.addAll (s.getOutlineItemsAt (pos)); + + } + + for (OutlineItem it : this.outlineItems) + { + + if (it.getPosition () == pos) + { + + its.add (it); + + } + + } + + return its; + + } + + public Set getAllNamedChildObjects () + { + + Set objs = new TreeSet<> (new ChapterItemSorter ()); + + for (Scene s : this.scenes) + { + + objs.add (s); + + } + + for (OutlineItem oi : this.outlineItems) + { + + objs.add (oi); + + } + + for (Note n : this.getNotes ()) + { + + objs.add (n); + + } + + return new LinkedHashSet (objs); + + /* + List objs = new ArrayList<> (); + objs.addAll (this.scenes); + objs.addAll (this.outlineItems); + objs.addAll (this.getNotes ()); + + Collections.sort (objs, + new ChapterItemSorter ()); + + return new TreeSet (objs); + */ +/* + Set objs = new TreeSet<> (new ChapterItemSorter ()); + + objs.addAll (this.scenes); + objs.addAll (this.outlineItems); + objs.addAll (this.getNotes ()); + + return objs; +*/ + } + + public void addChapterItem (ChapterItem item) + { + + if (item.getObjectType ().equals (Note.OBJECT_TYPE)) + { + + this.addNote ((Note) item); + + } + + if (item.getObjectType ().equals (OutlineItem.OBJECT_TYPE)) + { + + this.addOutlineItem ((OutlineItem) item); + + } + + if (item.getObjectType ().equals (Scene.OBJECT_TYPE)) + { + + this.addScene ((Scene) item); + + } + + } + + public Set getAllStructureItemsWithinRange (int min, + int max) + { + + Set items = new TreeSet<> (new ChapterItemSorter ()); + + for (OutlineItem it : this.outlineItems) + { + + if (it.getPosition () < min || it.getPosition () > max) + { + + continue; + + } + + items.add (it); + + } + + for (Scene s : this.scenes) + { + + if (s.getPosition () >= min && s.getPosition () <= max) + { + + items.add (s); + + } + + Set oitems = s.getOutlineItems (); + + for (OutlineItem oit : oitems) + { + + if (oit.getPosition () < min || oit.getPosition () > max) + { + + continue; + + } + + items.add (oit); + + } + + } + + return items; + + } + + public Set getChapterItems (String objType) + { + + if (objType.equals (OutlineItem.OBJECT_TYPE)) + { + + return this.getOutlineItems (); + + } + + if (objType.equals (Note.OBJECT_TYPE)) + { + + return this.getNotes (); + + } + + if (objType.equals (Scene.OBJECT_TYPE)) + { + + return this.getScenes (); + + } + + return null; + + } + + public void addNote (Note n) + { + + for (Note _n : this.getNotes ()) + { + + if (_n.equals (n)) + { + + return; + + } + + } + + if ((n.getChapter () != null) + && + (n.getChapter () != this) + ) + { + + n.getChapter ().removeNote (n); + + } + + super.addNote (n); + + } + + public void addScene (Scene s) + { + + // The contains call is unreliable... seems to fail sometimes... + for (Scene _s : this.scenes) + { + + if (_s.equals (s)) + { + + return; + + } + + } + + if ((s.getChapter () != null) + && + (!s.getChapter ().equals (this)) + ) + { + + s.getChapter ().removeScene (s); + + } + + s.setChapter (this); +/* + for (OutlineItem i : s.getOutlineItems ()) + { + + i.setChapter (this); + + } +*/ + this.scenes.add (s); + + } + + public void removeScene (Scene s) + { + + s.getOutlineItems ().clear (); + + this.scenes.remove (s); + + s.dispose (); + + } + + public ObservableSet getScenes () + { + + return this.scenes; +/* + Set items = new TreeSet (new ChapterItemSorter ()); + + items.addAll (this.scenes); + + return items; +*/ + } + + public ObservableSet getOutlineItems () + { + + return this.outlineItems; + +/* + Set items = new TreeSet (new ChapterItemSorter ()); + + items.addAll (this.outlineItems); + + return items; +*/ + } +/* + private void setOutlineItems (List l) + { + + this.outlineItems = l; + + } +*/ + public void removeChapterItem (ChapterItem i) + { + + if (i.getObjectType ().equals (OutlineItem.OBJECT_TYPE)) + { + + this.removeOutlineItem ((OutlineItem) i); + + } + + if (i.getObjectType ().equals (Note.OBJECT_TYPE)) + { + + this.removeNote ((Note) i); + + } + + if (i.getObjectType ().equals (Scene.OBJECT_TYPE)) + { + + this.removeScene ((Scene) i); + + } + + } + + public void removeOutlineItem (OutlineItem i) + { + + this.outlineItems.remove (i); + + } + + public void addOutlineItem (OutlineItem i) + { + + if (i.getScene () != null) + { + + i.getScene ().removeOutlineItem (i); + + i.setScene (null); + + } + + if ((i.getChapter () != null) + && + (i.getChapter () != this) + ) + { + + i.getChapter ().removeOutlineItem (i); + + } + + i.setChapter (this); + + for (OutlineItem oi : this.outlineItems) + { + + if (oi.equals (i)) + { + + return; + + } + + } + + this.outlineItems.add (i); + + } + + public String getChapterText () + { + + return (this.text != null ? this.text.getText () : null); + + } + + public StringWithMarkup getText () + { + + return this.text; + + } + + public void setText (StringWithMarkup t) + { + + if (t != null) + { + + String _t = t.getText (); + + if (_t != null) + { + + _t = com.quollwriter.text.TextUtilities.sanitizeText (_t); +/* + _t = StringUtils.replaceString (_t, + String.valueOf ('\r'), + ""); + */ + t.update (_t, + t.getMarkup ()); + + } + + } + + this.text = t; + + this.setLastModified (new Date ()); + + } + + public StringWithMarkup getGoals () + { + + return this.goals; + + } + + public void setGoals (StringWithMarkup t) + { + + if ((t != null) + && + (t.hasText ()) + ) + { + + t.update (Utils.replaceString (t.getText (), + String.valueOf ('\r'), + ""), + t.getMarkup ()); + + } + + UserConfigurableObjectField f = this.getLegacyField (GOALS_LEGACY_FIELD_ID); + + if (f == null) + { + + UserConfigurableObjectTypeField type = this.getLegacyTypeField (GOALS_LEGACY_FIELD_ID); + + f = new UserConfigurableObjectField (type); + + f.setParent (this); + this.fields.add (f); + + } + + try + { + + f.setValue (JSONEncoder.encode (t)); + + } catch (Exception e) { + + throw new IllegalArgumentException ("Unable to json encode string with markup: " + + t, + e); + + } + + this.goals = t; + + this.setLastModified (new Date ()); + + } + + public ObjectProperty planProperty () + { + + return this.planProp; + + } + + public StringWithMarkup getPlan () + { + + return this.plan; + + } + + public void setPlan (StringWithMarkup t) + { + + if ((t != null) + && + (t.hasText ()) + ) + { + + t.update (Utils.replaceString (t.getText (), + String.valueOf ('\r'), + ""), + t.getMarkup ()); + + } + + UserConfigurableObjectField f = this.getLegacyField (PLAN_LEGACY_FIELD_ID); + + if (f == null) + { + + UserConfigurableObjectTypeField type = this.getLegacyTypeField (PLAN_LEGACY_FIELD_ID); + + f = new UserConfigurableObjectField (type); + + f.setParent (this); + this.fields.add (f); + + } + + try + { + + f.setValue (JSONEncoder.encode (t)); + + } catch (Exception e) { + + throw new IllegalArgumentException ("Unable to json encode string with markup: " + + t, + e); + + } + + this.plan = t; + this.planProp.setValue (t); + + this.setLastModified (new Date ()); + + } + /* + @Override + public String toString () + { + + return Environment.formatObjectToStringProperties (this); + + } + */ + @Override + public void fillToStringProperties (Map props) + { + + super.fillToStringProperties (props); + + this.addToStringProperties (props, + "editPosition", + this.editPosition); + this.addToStringProperties (props, + "editComplete", + this.editComplete); + this.addToStringProperties (props, + "textLength", + this.getChapterLength ()); + this.addToStringProperties (props, + "book", + this.book); + this.addToStringProperties (props, + "scenes", + this.scenes.size ()); + this.addToStringProperties (props, + "outlineItems", + this.outlineItems.size ()); + + } + + public void setBook (Book b) + { + + this.book = b; + + this.setParent (b); + + } + + public Book getBook () + { + + return this.book; + + } + + public Scene getNextScene (Scene s) + { + + TreeSet items = new TreeSet (new ChapterItemSorter ()); + + items.addAll (this.scenes); + + return items.higher (s); + + } + + public Scene getLastScene (int position) + { + + List scs = new ArrayList<> (this.getScenes ()); + + Collections.sort (scs, + new ChapterItemSorter ()); + Collections.reverse (scs); + + for (Scene s : scs) + { + + if (position > s.getPosition ()) + { + + return s; + + } + + } + + return null; + + } + +/* +TODO Remove + public Scene getLastScene (int position) + { + + Scene last = null; + + for (Scene s : this.getScenes ()) + { + + if (s.getPosition () >= position) + { + + return last; + + } else + { + + last = s; + + } + + } + + return last; + + } +*/ + public List getNotesBetween (int start, + int end) + { + + List newNotes = new ArrayList (); + + for (Note n : this.getNotes ()) + { + + if ((n.getPosition () >= start) && + (n.getPosition () <= end)) + { + + newNotes.add (n); + + } + + } + + return newNotes; + + } + + /* + * Do not use, swing method. + */ + @Deprecated + public void setTextEditPosition (Position p) + { + + //this.textEditPos = p; + + if (p == null) + { + + //this.editPosition = -1; + //this.editPositionProp.setValue (-1); + + } + + } + + public IntegerProperty editPositionProperty () + { + + return this.editPositionProp; + + } + + public void setEditPosition (int p) + { + + int oldPos = this.editPosition; + + this.editPositionProp.setValue (p); + + this.editPosition = p; + + this.firePropertyChangedEvent (EDIT_POSITION, + oldPos, + p); + //this.editPosition); + + } + + public int getEditPosition () + { +/* + if (this.textEditPos != null) + { + + return this.textEditPos.getOffset (); + + } +*/ + return this.editPositionProp.getValue (); + + } + + public int getChapterLength () + { + + if (this.text == null) + { + + return 0; + + } + + if (this.text.getText () == null) + { + + return 0; + + } + + return this.text.getText ().length (); + + } + + public boolean isPositionAtChapterEnd (int p) + { + + int cl = this.getChapterLength (); + + if (cl == 0) + { + + return p == cl; + + } + + return p >= cl - 1; + + } + +} diff --git a/src/main/java/com/quollwriter/data/ChapterCounts.java b/src/main/java/com/quollwriter/data/ChapterCounts.java new file mode 100644 index 00000000..7ce1e078 --- /dev/null +++ b/src/main/java/com/quollwriter/data/ChapterCounts.java @@ -0,0 +1,391 @@ +package com.quollwriter.data; + +import java.util.*; + +import javafx.beans.property.*; + +import com.quollwriter.ui.fx.*; +import com.quollwriter.text.*; +import com.quollwriter.*; + +public class ChapterCounts implements Stateful +{ + + //public Chapter chapter = null; + private int wordCount = 0; + private IntegerProperty wordCountProp = null; + private IntegerProperty sentenceCountProp = null; + private IntegerProperty standardPageCountProp = null; + private IntegerProperty paragraphCountProp = null; + private int sentenceCount = 0; + private int standardPageCount = 0; + private int paragraphCount = 0; + private int spellingErrorCount = 0; + public Map wordFrequency = null; + private ObjectProperty readabilityIndicesProp = null; + private IntegerProperty spellingErrorCountProp = null; + private int problemFinderProblemsCount = 0; + private IntegerProperty problemFinderProblemsCountProp = null; + + public ChapterCounts () + { + + this.wordCountProp = new SimpleIntegerProperty (0); + //this.wordCount); + this.sentenceCountProp = new SimpleIntegerProperty (0); + //this.sentenceCount); + this.standardPageCountProp = new SimpleIntegerProperty (0); + this.paragraphCountProp = new SimpleIntegerProperty (0); + //this.standardPageCount); + this.standardPageCountProp = new SimpleIntegerProperty (0); + this.readabilityIndicesProp = new SimpleObjectProperty<> (null); + this.spellingErrorCountProp = new SimpleIntegerProperty (0); + this.readabilityIndicesProp.setValue (new ReadabilityIndices ()); + this.problemFinderProblemsCountProp = new SimpleIntegerProperty (0); + //this.paragraphCount); + + } + + public ChapterCounts (String t) + { + + this (); + if (t != null) + { + + TextIterator ti = new TextIterator (t); + this.setWordCount (ti.getWordCount ()); + this.setSentenceCount (ti.getSentenceCount ()); + this.setParagraphCount (ti.getParagraphCount ()); + this.wordFrequency = ti.getWordFrequency (); + + } + + } + + @Override + public State getState () + { + + State s = new State (); + s.set ("wordcount", + this.getWordCount ()); + s.set ("sentencecount", + this.getSentenceCount ()); + s.set ("paragraphcount", + this.getParagraphCount ()); + s.set ("spellingerrorcount", + this.getSpellingErrorCount ()); + s.set ("problemfinderproblemscount", + this.getProblemFinderProblemsCount ()); + s.set ("pagecount", + this.getStandardPageCount ()); + s.set ("syllablecount", + this.getReadabilityIndices ().getSyllableCount ()); + s.set ("threesyllablewordcount", + this.getReadabilityIndices ().getThreeSyllableWordCount ()); + + return s; + + } + + @Override + public void init (State s) + { + + if (s == null) + { + + return; + + } + + this.setWordCount (s.getAsInt ("wordcount", + 0)); + this.setSentenceCount (s.getAsInt ("sentencecount", + 0)); + this.setParagraphCount (s.getAsInt ("paragraphcount", + 0)); + this.setStandardPageCount (s.getAsInt ("pagecount", + 0)); + this.setSpellingErrorCount (s.getAsInt ("spellingerrorcount", + 0)); + this.setProblemFinderProblemsCount (s.getAsInt ("problemfinderproblemscount", + 0)); + + int sylc = s.getAsInt ("syllablecount", + 0); + int thrsylc = s.getAsInt ("threesyllablewordcount", + 0); + + ReadabilityIndices ri = new ReadabilityIndices (this.getWordCount (), + this.getSentenceCount (), + thrsylc, + sylc); + + this.readabilityIndicesProp.getValue ().updateFrom (ri); + + } + + @Override + public String toString () + { + + return String.format ("wordcount: %1$s, sentencecount: %2$s, paragraphcount: %3$s, spellingerrorcount: %4$s, pagecount: %5$s, problemfinderproblemcount: %6$s", + Environment.formatNumber (this.wordCount), + Environment.formatNumber (this.sentenceCount), + Environment.formatNumber (this.paragraphCount), + Environment.formatNumber (this.spellingErrorCount), + Environment.formatNumber (this.standardPageCount), + Environment.formatNumber (this.problemFinderProblemsCount)); + + } + + public void setProblemFinderProblemsCount (int v) + { + + this.problemFinderProblemsCount = v; + + UIUtils.runLater (() -> + { + + this.problemFinderProblemsCountProp.setValue (v); + + }); + + } + + public IntegerProperty problemFinderProblemsCountProperty () + { + + return this.problemFinderProblemsCountProp; + + } + + public int getProblemFinderProblemsCount () + { + + return this.problemFinderProblemsCount; + + } + + public void setSpellingErrorCount (int v) + { + + this.spellingErrorCount = v; + + UIUtils.runLater (() -> + { + + this.spellingErrorCountProp.setValue (v); + + }); + + } + + public int getSpellingErrorCount () + { + + return this.spellingErrorCount; + + } + + public IntegerProperty spellingErrorCountProp () + { + + return this.spellingErrorCountProp; + + } + + public void setReadabilityIndices (ReadabilityIndices ri) + { + + UIUtils.runLater (() -> + { + + this.readabilityIndicesProp.setValue (ri); + + }); + + } + + public ReadabilityIndices getReadabilityIndices () + { + + return this.readabilityIndicesProp.getValue (); + + } + + public ObjectProperty readabilityIndicesProperty () + { + + return this.readabilityIndicesProp; + + } + + public void setWordCount (int c) + { + + this.wordCount = c; + UIUtils.runLater (() -> + { + + this.wordCountProp.setValue (c); + + }); + + } + + public int getWordCount () + { + + return this.wordCount; + + } + + public IntegerProperty wordCountProperty () + { + + return this.wordCountProp; + + } + + public void setSentenceCount (int c) + { + + this.sentenceCount = c; + + UIUtils.runLater (() -> + { + + this.sentenceCountProp.setValue (c); + + }); + + } + + public int getSentenceCount () + { + + return this.sentenceCount; + + } + + public IntegerProperty sentenceCountProperty () + { + + return this.sentenceCountProp; + + } + + public void setStandardPageCount (int c) + { + + this.standardPageCount = c; + + UIUtils.runLater (() -> + { + + this.standardPageCountProp.setValue (c); + + }); + + } + + public int getStandardPageCount () + { + + return this.standardPageCount; + + } + + public IntegerProperty standardPageCountProperty () + { + + return this.standardPageCountProp; + + } + + public int getParagraphCount () + { + + return this.paragraphCount; + + } + + public IntegerProperty paragraphCountProperty () + { + + return this.paragraphCountProp; + + } + + public void setParagraphCount (int v) + { + + this.paragraphCount = v; + UIUtils.runLater (() -> + { + + this.paragraphCountProp.setValue (v); + + }); + + } + + public void add (ChapterCounts c) + { + + //this.chapter = null; + //this.wordCount += c.wordCount; + this.setWordCount (this.getWordCount () + c.getWordCount ()); + //this.sentenceCount += c.sentenceCount; + this.setSentenceCount (this.getSentenceCount () + c.getSentenceCount ()); + //this.standardPageCount += c.standardPageCount; + this.setStandardPageCount (this.getStandardPageCount () + c.getStandardPageCount ()); + this.setSpellingErrorCount (this.getSpellingErrorCount () + c.getSpellingErrorCount ()); + + if (this.wordFrequency == null) + { + + this.wordFrequency = new HashMap<> (); + + } + + if (c.wordFrequency != null) + { + + for (Map.Entry en : c.wordFrequency.entrySet ()) + { + + String w = en.getKey (); + Integer oc = en.getValue (); + + Integer count = this.wordFrequency.get (w); + + int wc = 1; + + if (count != null) + { + + wc += count.intValue (); + + } + + if (oc != null) + { + + wc += oc.intValue (); + + } + + this.wordFrequency.put (w, + Integer.valueOf (wc)); + + } + + } + + } + +} diff --git a/src/main/java/com/quollwriter/data/ChapterItem.java b/src/main/java/com/quollwriter/data/ChapterItem.java new file mode 100644 index 00000000..375b6cf0 --- /dev/null +++ b/src/main/java/com/quollwriter/data/ChapterItem.java @@ -0,0 +1,433 @@ +package com.quollwriter.data; + +import java.util.*; + +import javafx.beans.value.*; +import javafx.beans.property.*; + +import javax.swing.text.Position; + +import com.quollwriter.data.comparators.*; + +public abstract class ChapterItem extends NamedObject +{ + + //private int position = -1; + //private int endPosition = -1; + private Position textPos = null; + private Position endTextPos = null; + //private com.quollwriter.ui.fx.components.TextEditor.Position textPos2 = null; + //private com.quollwriter.ui.fx.components.TextEditor.Position endTextPos2 = null; + protected Chapter chapter = null; + private SimpleIntegerProperty positionProp = new SimpleIntegerProperty (0); + private SimpleIntegerProperty endPositionProp = new SimpleIntegerProperty (-1); + + public static Set getEmptyChapterItemSet () + { + + return new TreeSet (new ChapterItemSorter ()); + + } + + protected ChapterItem(String objType) + { + + super (objType); + + } + + protected ChapterItem(String objType, + int at, + Chapter c) + { + + this (objType); + + this.setPosition (at); + this.chapter = c; + + } + + protected ChapterItem(String objType, + int start, + int end, + Chapter c) + { + + this (objType, + start, + c); + + this.setEndPosition (end); + + } + + //public void dispose () + //{ + + //this.positionProp.unbind (); + //this.endPositionProp.unbind (); +/* + if (this.textPos2 != null) + { + + this.textPos2.dispose (); + + } + + if (this.endTextPos2 != null) + { + + this.endTextPos2.dispose (); + + } +*/ + //} + + public SimpleIntegerProperty positionProperty () + { + + return this.positionProp; + + } + + public SimpleIntegerProperty endPositionProperty () + { + + return this.endPositionProp; + + } + + @Override + public void fillToStringProperties (Map props) + { + + super.fillToStringProperties (props); + + this.addToStringProperties (props, + "position", + this.positionProp.getValue ()); + this.addToStringProperties (props, + "endPosition", + this.endPositionProp.getValue ()); + /* + this.addToStringProperties (props, + "textPosition", + (this.textPos != null ? this.textPos.getOffset () : null)); + this.addToStringProperties (props, + "endTextPosition", + (this.endTextPos != null ? this.endTextPos.getOffset () : null)); + */ + this.addToStringProperties (props, + "chapter", + this.chapter); + + } + + public Set getAllNamedChildObjects () + { + + return new HashSet<> (this.getNotes ()); + + } + + public Chapter getChapter () + { + + return this.chapter; + + } + + public void setChapter (Chapter c) + { + + if ((this.chapter != null) + && + (this.chapter.equals (c)) + ) + { + + // Already set. + return; + + } + + if ((this.chapter != null) + && + (!this.chapter.equals (c)) + ) + { + + // Remove this item from the existing chapter. + this.chapter.removeChapterItem (this); + + } + + this.chapter = c; + + if (this.getKey () == null) + { + + // Don't try and add the item if there is no key. + return; + + } + + this.chapter.addChapterItem (this); + + } +/* + public void bindPosition (com.quollwriter.ui.fx.components.TextEditor.Position t) + { + + this.unbindPosition (); + this.positionProp.bindBidirectional (t.positionProperty ()); + + } + + public void unbindPosition () + { + + this.positionProp.unbindBidirectional (); + + } + + public void bindEndPosition (com.quollwriter.ui.fx.components.TextEditor.Position t) + { + + this.unbindBidirectional (); + this.endPositionProp.bindBidirectional (t.positionProperty ()); + + } + + + public void unbindEndPosition () + { + + this.endPositionProp.unbindBidirectional (); + + } +*/ +/* + public void setTextPosition2 (com.quollwriter.ui.fx.components.TextEditor.Position t) + { + + if (this.textPos2 != null) + { + + this.textPos2.dispose (); + + } + + this.textPos2 = t; + this.positionProp.unbindBidirectional (); + this.positionProp.bindBidirectional (t.positionProperty ()); + + } +*/ + + public void setTextPosition (Position t) + { + + this.textPos = t; + + } + + public void setEndTextPosition (Position t) + { + + this.endTextPos = t; + + } +/* + public void setEndTextPosition2 (com.quollwriter.ui.fx.components.TextEditor.Position t) + { + + if (this.endTextPos2 != null) + { + + this.endTextPos2.dispose (); + + } + + this.endTextPos2 = t; + this.endPositionProp.unbindBidirectional (); + this.endPositionProp.bindBidirectional (t.positionProperty ()); + + } +*/ + public Position getTextPosition () + { + + return this.textPos; + + } + + public void setEndPosition (int p) + { + + if (p <= this.positionProp.getValue ()) + { + + this.endPositionProp.setValue (-1); + //this.endPosition = -1; + + //this.endTextPos = null; + + return; + + } + + if (p > -1) + { + + this.endPositionProp.setValue (p); + + } else + { + + this.endPositionProp.setValue (-1); + + } + + //this.endTextPos = null; + + } + + public int getEndPosition () + { +/* + if (this.endTextPos != null) + { + + return this.endTextPos.getOffset (); + + } +*/ + return this.endPositionProp.getValue (); + + } + + public int getStartPosition () + { + + return this.getPosition (); + + } + + public void setPosition (int p) + { + + //this.position = p; + //this.positionProp.unbind (); + + if (p < 0) + { + + p = 0; + + } + + int op = this.positionProp.getValue (); + + this.positionProp.setValue (p); + + if (this.endPositionProp.getValue () > -1) + { + + this.endPositionProp.setValue (this.endPositionProp.getValue () + (p - op)); + + } + + } + + public void shiftPositionBy (int p) + { + + this.setPosition (this.getPosition () + p); + + this.setEndPosition (this.getEndPosition () + p); + + } + + public int getPosition () + { +/* + if (this.textPos2 != null) + { + + return this.textPos2.getOffset (); + + } +*/ + return this.positionProp.getValue (); + + } + + public void setSummary (String s) + { + + this.setName (s); + + } + + public String getSummary () + { + + return this.getName (); + + } + + public static class ChapterItemEvent + { + + public enum Type + { + positionchange + } + + private ChapterItem item = null; + private Type type = null; + private ObservableValue pos = null; + private Integer oldV = null; + private Integer newV = null; + + public ChapterItemEvent (ChapterItem i, + Type t, + ObservableValue pos, + Integer oldV, + Integer newV) + { + + this.item = i; + this.type = t; + this.pos = pos; + this.oldV = oldV; + this.newV = newV; + + } + + public ChapterItem getItem () + { + + return this.item; + + } + + public Integer getOld () + { + + return this.oldV; + + } + + public Integer getNew () + { + + return this.newV; + + } + + } + +} diff --git a/src/main/java/com/quollwriter/data/CollectionEvent.java b/src/main/java/com/quollwriter/data/CollectionEvent.java new file mode 100644 index 00000000..cf8773ca --- /dev/null +++ b/src/main/java/com/quollwriter/data/CollectionEvent.java @@ -0,0 +1,44 @@ +package com.quollwriter.data; + +import java.util.*; + +public class CollectionEvent +{ + + public enum Type + { + + add, + remove + } + + private Type type = null; + private T source = null; + private Collection col = null; + + public CollectionEvent (Collection col, + T source, + Type type) + { + + this.type = type; + this.source = source; + this.col = col; + + } + + public Type getType () + { + + return this.type; + + } + + public T getSource () + { + + return this.source; + + } + +} diff --git a/src/com/quollwriter/data/DataObject.java b/src/main/java/com/quollwriter/data/DataObject.java similarity index 86% rename from src/com/quollwriter/data/DataObject.java rename to src/main/java/com/quollwriter/data/DataObject.java index 6f428daf..d4525249 100644 --- a/src/com/quollwriter/data/DataObject.java +++ b/src/main/java/com/quollwriter/data/DataObject.java @@ -14,18 +14,18 @@ import java.util.HashSet; import java.util.Arrays; -import com.gentlyweb.properties.*; +import org.reactfx.*; -import com.gentlyweb.xml.*; +import com.gentlyweb.properties.*; import com.quollwriter.*; import com.quollwriter.events.*; -import org.jdom.*; +import org.dom4j.*; -public abstract class DataObject +public abstract class DataObject implements IPropertyBinder { private String objType = null; @@ -34,15 +34,19 @@ public abstract class DataObject private String id = null; private String version = null; private boolean latest = true; + private javafx.beans.property.BooleanProperty modifiedProp = null; // protected Date lastModified = null; private Date dateCreated = new Date (); protected DataObject parent = null; - private Map listeners = null; + private Map weakListeners = null; + private Set nonWeakListeners = null; // Just used in the maps above as a placeholder for the listeners. private static final Object listenerFillObj = new Object (); + private PropertyBinder binder = new PropertyBinder (); + public DataObject(String objType) { @@ -51,7 +55,9 @@ public DataObject(String objType) // Where possible listeners should de-register as normal but this just ensure that objects // that don't have a controlled pre-defined lifecycle. - this.listeners = Collections.synchronizedMap (new WeakHashMap ()); + this.weakListeners = Collections.synchronizedMap (new WeakHashMap<> ()); + + this.nonWeakListeners = Collections.synchronizedSet (new HashSet<> ()); if (objType != null) { @@ -261,13 +267,20 @@ protected synchronized void firePropertyChangedEvent (String type, Object o = new Object (); - Set ls = null; + Set ls = new HashSet<> (); // Get a copy of the current valid listeners. - synchronized (this.listeners) + synchronized (this.weakListeners) + { + + ls.addAll (this.weakListeners.keySet ()); + + } + + synchronized (this.nonWeakListeners) { - ls = new HashSet (this.listeners.keySet ()); + ls.addAll (this.nonWeakListeners); } @@ -295,7 +308,14 @@ protected synchronized void firePropertyChangedEvent (String type, public void removePropertyChangedListener (PropertyChangedListener l) { - this.listeners.remove (l); + this.weakListeners.remove (l); + + } + + public void removeNonWeakPropertyChangedListener (PropertyChangedListener l) + { + + this.nonWeakListeners.remove (l); } @@ -344,8 +364,43 @@ public void removePropertyChangedListener (PropertyChangedListener l) public void addPropertyChangedListener (PropertyChangedListener l) { - this.listeners.put (l, - this.listenerFillObj); + this.weakListeners.put (l, + this.listenerFillObj); + + } + + public void addNonWeakPropertyChangedListener (PropertyChangedListener l) + { + + this.nonWeakListeners.add (l); + + } + + public Project getProject () + { + + if (this.parent != null) + { + + if (this.parent instanceof Project) + { + + return (Project) this.parent; + + } + + return this.parent.getProject (); + + } + + return null; + + } + + public void setProject (Project p) + { + + this.setParent (p); } @@ -391,7 +446,7 @@ public String getPropertiesAsString () { // Conver the properties to a string. - return JDOMUtils.getElementAsString (this.props.getAsJDOMElement ()); + return DOM4JUtils.elementAsString (this.props.getAsElement ()); } @@ -407,7 +462,7 @@ public void setPropertiesAsString (String p) } // Convert to XML, convert to Properties. - Element root = JDOMUtils.getStringAsElement (p); + Element root = DOM4JUtils.stringAsElement (p); if (this.props == null) { @@ -481,6 +536,21 @@ public void setProperty (String name, } + public void setProperty (String name, + float value) + throws IOException + { + + FloatProperty p = new FloatProperty (name, + value); + + p.setDescription ("N/A"); + + this.props.setProperty (name, + p); + + } + public void removeProperty (String name) { @@ -676,4 +746,19 @@ public ObjectReference getObjectReference () } + @Override + public IPropertyBinder getBinder () + { + + return this.binder; + + } + + public void dispose () + { + + this.binder.dispose (); + + } + } diff --git a/src/com/quollwriter/data/DateRange.java b/src/main/java/com/quollwriter/data/DateRange.java similarity index 100% rename from src/com/quollwriter/data/DateRange.java rename to src/main/java/com/quollwriter/data/DateRange.java diff --git a/src/main/java/com/quollwriter/data/DateUserConfigurableObjectTypeField.java b/src/main/java/com/quollwriter/data/DateUserConfigurableObjectTypeField.java new file mode 100644 index 00000000..caa7d2f8 --- /dev/null +++ b/src/main/java/com/quollwriter/data/DateUserConfigurableObjectTypeField.java @@ -0,0 +1,127 @@ +package com.quollwriter.data; + +import java.awt.Dimension; + +import java.time.*; +import java.util.Date; +import java.util.Map; +import java.util.Set; +import java.util.LinkedHashSet; + +import javax.swing.*; + +import com.toedter.calendar.*; + +import com.quollwriter.*; +import com.quollwriter.ui.fx.*; +import com.quollwriter.ui.fx.userobjects.*; +import com.quollwriter.ui.fx.viewers.*; + +public class DateUserConfigurableObjectTypeField extends UserConfigurableObjectTypeField +{ + + public static final String def = "def"; + public static final String max = "max"; + public static final String min = "min"; + + public DateUserConfigurableObjectTypeField () + { + + super (Type.date); + + } + + @Override + public boolean isSortable () + { + + return true; + + } + + @Override + public com.quollwriter.ui.userobjects.UserConfigurableObjectFieldViewEditHandler getViewEditHandler (UserConfigurableObject obj, + UserConfigurableObjectField field, + com.quollwriter.ui.AbstractProjectViewer viewer) + { + + return new com.quollwriter.ui.userobjects.DateUserConfigurableObjectFieldViewEditHandler (this, + obj, + field, + viewer); + + } + + @Override + public UserConfigurableObjectFieldViewEditHandler getViewEditHandler2 (UserConfigurableObject obj, + UserConfigurableObjectField field, + IPropertyBinder binder, + AbstractProjectViewer viewer) + { + + return new DateUserConfigurableObjectFieldViewEditHandler (this, + obj, + field, + viewer); + + } + + @Override + public com.quollwriter.ui.userobjects.UserConfigurableObjectTypeFieldConfigHandler getConfigHandler () + { + + return new com.quollwriter.ui.userobjects.DateUserConfigurableObjectTypeFieldConfigHandler (this); + + } + + @Override + public UserConfigurableObjectTypeFieldConfigHandler getConfigHandler2 () + { + + return new DateUserConfigurableObjectTypeFieldConfigHandler (this); + + } + + public void setMaximum (LocalDate d) + { + + this.setDefinitionValue (max, (d != null ? UserConfigurableObjectTypeField.formatDate (d) : null)); + + } + + public LocalDate getMaximum () + { + + return this.getDateDefinitionValue (max); + + } + + public void setMinimum (LocalDate d) + { + + this.setDefinitionValue (min, (d != null ? UserConfigurableObjectTypeField.formatDate (d) : null)); + + } + + public LocalDate getMinimum () + { + + return this.getDateDefinitionValue (min); + + } + + public void setDefault (LocalDate d) + { + + this.setDefinitionValue (def, (d != null ? UserConfigurableObjectTypeField.formatDate (d) : null)); + + } + + public LocalDate getDefault () + { + + return this.getDateDefinitionValue (def); + + } + +} diff --git a/src/main/java/com/quollwriter/data/DocumentsUserConfigurableObjectTypeField.java b/src/main/java/com/quollwriter/data/DocumentsUserConfigurableObjectTypeField.java new file mode 100644 index 00000000..b68de7ae --- /dev/null +++ b/src/main/java/com/quollwriter/data/DocumentsUserConfigurableObjectTypeField.java @@ -0,0 +1,67 @@ +package com.quollwriter.data; + +import java.util.*; + +import com.quollwriter.ui.fx.*; +import com.quollwriter.ui.fx.userobjects.*; +import com.quollwriter.ui.fx.viewers.*; + +public class DocumentsUserConfigurableObjectTypeField extends UserConfigurableObjectTypeField +{ + + protected DocumentsUserConfigurableObjectTypeField (Type type) + { + + super (type); + + } + + public DocumentsUserConfigurableObjectTypeField () + { + + super (Type.documents); + + } + + @Override + public com.quollwriter.ui.userobjects.UserConfigurableObjectFieldViewEditHandler getViewEditHandler (UserConfigurableObject obj, + UserConfigurableObjectField field, + com.quollwriter.ui.AbstractProjectViewer viewer) + { + + return null; + + } + + @Override + public UserConfigurableObjectFieldViewEditHandler getViewEditHandler2 (UserConfigurableObject obj, + UserConfigurableObjectField field, + IPropertyBinder binder, + AbstractProjectViewer viewer) + { + + return new DocumentsUserConfigurableObjectFieldViewEditHandler (this, + obj, + field, + binder, + viewer); + + } + + @Override + public com.quollwriter.ui.userobjects.UserConfigurableObjectTypeFieldConfigHandler getConfigHandler () + { + + return null; + + } + + @Override + public UserConfigurableObjectTypeFieldConfigHandler getConfigHandler2 () + { + + return new DocumentsUserConfigurableObjectTypeFieldConfigHandler (this); + + } + +} diff --git a/src/main/java/com/quollwriter/data/FileUserConfigurableObjectTypeField.java b/src/main/java/com/quollwriter/data/FileUserConfigurableObjectTypeField.java new file mode 100644 index 00000000..e0b15da3 --- /dev/null +++ b/src/main/java/com/quollwriter/data/FileUserConfigurableObjectTypeField.java @@ -0,0 +1,61 @@ +package com.quollwriter.data; + +import java.util.*; + +import com.quollwriter.ui.fx.viewers.*; +import com.quollwriter.ui.fx.userobjects.*; + +public class FileUserConfigurableObjectTypeField extends UserConfigurableObjectTypeField +{ + + public FileUserConfigurableObjectTypeField () + { + + super (Type.file); + + } + + @Override + public com.quollwriter.ui.userobjects.UserConfigurableObjectFieldViewEditHandler getViewEditHandler (UserConfigurableObject obj, + UserConfigurableObjectField field, + com.quollwriter.ui.AbstractProjectViewer viewer) + { + + return new com.quollwriter.ui.userobjects.FileUserConfigurableObjectFieldViewEditHandler (this, + obj, + field, + viewer); + + } + + @Override + public UserConfigurableObjectFieldViewEditHandler getViewEditHandler2 (UserConfigurableObject obj, + UserConfigurableObjectField field, + IPropertyBinder binder, + AbstractProjectViewer viewer) + { + + return new FileUserConfigurableObjectFieldViewEditHandler (this, + obj, + field, + viewer); + + } + + @Override + public com.quollwriter.ui.userobjects.UserConfigurableObjectTypeFieldConfigHandler getConfigHandler () + { + + return new com.quollwriter.ui.userobjects.FileUserConfigurableObjectTypeFieldConfigHandler (this); + + } + + @Override + public UserConfigurableObjectTypeFieldConfigHandler getConfigHandler2 () + { + + return new FileUserConfigurableObjectTypeFieldConfigHandler (this); + + } + +} diff --git a/src/main/java/com/quollwriter/data/IPropertyBinder.java b/src/main/java/com/quollwriter/data/IPropertyBinder.java new file mode 100644 index 00000000..f9888cb9 --- /dev/null +++ b/src/main/java/com/quollwriter/data/IPropertyBinder.java @@ -0,0 +1,65 @@ +package com.quollwriter.data; + +import java.util.*; + +import javafx.scene.*; +import javafx.beans.value.*; +import javafx.beans.property.*; +import javafx.collections.*; + +public interface IPropertyBinder +{ + + IPropertyBinder getBinder (); + + default ListenerHandle addMapChangeListener (ObservableMap value, + MapChangeListener listener) + { + + return this.getBinder ().addMapChangeListener (value, + listener); + + } + + default ListenerHandle addChangeListener (ObservableValue value, + ChangeListener listener) + { + + return this.getBinder ().addChangeListener (value, + listener); + + } + + default ListenerHandle addSetChangeListener (ObservableSet set, + SetChangeListener listener) + { + + return this.getBinder ().addSetChangeListener (set, + listener); + + } + + default ListenerHandle addListChangeListener (ObservableList list, + ListChangeListener listener) + { + + return this.getBinder ().addListChangeListener (list, + listener); + + } + + default void dispose () + { + + this.getBinder ().dispose (); + + } + + public interface ListenerHandle + { + + void dispose (); + + } + +} diff --git a/src/com/quollwriter/data/Idea.java b/src/main/java/com/quollwriter/data/Idea.java similarity index 90% rename from src/com/quollwriter/data/Idea.java rename to src/main/java/com/quollwriter/data/Idea.java index 28027a26..ffba8f49 100644 --- a/src/com/quollwriter/data/Idea.java +++ b/src/main/java/com/quollwriter/data/Idea.java @@ -2,8 +2,7 @@ import java.util.*; -import org.jdom.*; - +import org.dom4j.*; public class Idea extends NamedObject { @@ -22,9 +21,9 @@ public Idea() public String getName () { - + return this.getDescriptionText (); - + } @Override @@ -36,23 +35,23 @@ public void fillToStringProperties (Map props) this.addToStringProperties (props, "type", this.type); - + } - + public Date getLastModified () { - + Date d = super.getLastModified (); - + if (d != null) { - + return d; - + } - + return this.getDateCreated (); - + } public IdeaType getType () @@ -66,7 +65,7 @@ public void setType (IdeaType t) { this.type = t; - + this.setParent (t); } @@ -92,6 +91,7 @@ public Set getAllNamedChildObjects () } + @Override public void getChanges (NamedObject old, Element root) { diff --git a/src/com/quollwriter/data/IdeaType.java b/src/main/java/com/quollwriter/data/IdeaType.java similarity index 85% rename from src/com/quollwriter/data/IdeaType.java rename to src/main/java/com/quollwriter/data/IdeaType.java index ef8c360a..7747e336 100644 --- a/src/com/quollwriter/data/IdeaType.java +++ b/src/main/java/com/quollwriter/data/IdeaType.java @@ -2,9 +2,11 @@ import java.util.*; +import javafx.collections.*; + import com.quollwriter.*; -import org.jdom.*; +import org.dom4j.*; import org.josql.utils.*; @@ -21,7 +23,7 @@ public class IdeaType extends NamedObject private String sortBy = null; private String iconType = null; - private List ideas = new ArrayList (); + private ObservableSet ideas = FXCollections.observableSet (new LinkedHashSet<> ()); private Project proj = null; public IdeaType() @@ -82,7 +84,7 @@ public void addIdea (Idea i) { return; - + } i.setType (this); @@ -105,19 +107,9 @@ public int getIdeaCount () } - public List getIdeas () + public ObservableSet getIdeas () { - if (this.sortBy == null) - { - - this.sortBy = IdeaType.SORT_BY_RATING; - - } - - Collections.sort (this.ideas, - new IdeaTypeComparator (this.sortBy)); - return this.ideas; } @@ -130,6 +122,7 @@ public void setIdeas (List ideas) } */ + @Override public String toString () { @@ -137,6 +130,7 @@ public String toString () } + @Override public Set getAllNamedChildObjects () { @@ -144,6 +138,7 @@ public Set getAllNamedChildObjects () } + @Override public void getChanges (NamedObject old, Element root) { diff --git a/src/main/java/com/quollwriter/data/ImageUserConfigurableObjectTypeField.java b/src/main/java/com/quollwriter/data/ImageUserConfigurableObjectTypeField.java new file mode 100644 index 00000000..83d80cb8 --- /dev/null +++ b/src/main/java/com/quollwriter/data/ImageUserConfigurableObjectTypeField.java @@ -0,0 +1,69 @@ +package com.quollwriter.data; + +import java.util.*; + +import com.quollwriter.ui.fx.*; +import com.quollwriter.ui.fx.viewers.*; +import com.quollwriter.ui.fx.userobjects.*; + +public class ImageUserConfigurableObjectTypeField extends UserConfigurableObjectTypeField +{ + + protected ImageUserConfigurableObjectTypeField (Type type) + { + + super (type); + + } + + public ImageUserConfigurableObjectTypeField () + { + + super (Type.image); + + } + + @Override + public com.quollwriter.ui.userobjects.UserConfigurableObjectFieldViewEditHandler getViewEditHandler (UserConfigurableObject obj, + UserConfigurableObjectField field, + com.quollwriter.ui.AbstractProjectViewer viewer) + { + + return new com.quollwriter.ui.userobjects.ImageUserConfigurableObjectFieldViewEditHandler (this, + obj, + field, + viewer); + + } + + @Override + public UserConfigurableObjectFieldViewEditHandler getViewEditHandler2 (UserConfigurableObject obj, + UserConfigurableObjectField field, + IPropertyBinder binder, + AbstractProjectViewer viewer) + { + + return new ImageUserConfigurableObjectFieldViewEditHandler (this, + obj, + field, + viewer); + + } + + @Override + public UserConfigurableObjectTypeFieldConfigHandler getConfigHandler2 () + { + + return new ImageUserConfigurableObjectTypeFieldConfigHandler (this); + + } + + @Override + public com.quollwriter.ui.userobjects.UserConfigurableObjectTypeFieldConfigHandler getConfigHandler () + { + + return new com.quollwriter.ui.userobjects.ImageUserConfigurableObjectTypeFieldConfigHandler (this); + + } + +} diff --git a/src/com/quollwriter/data/LegacyAsset.java b/src/main/java/com/quollwriter/data/LegacyAsset.java similarity index 83% rename from src/com/quollwriter/data/LegacyAsset.java rename to src/main/java/com/quollwriter/data/LegacyAsset.java index b9edca05..a75390c4 100644 --- a/src/com/quollwriter/data/LegacyAsset.java +++ b/src/main/java/com/quollwriter/data/LegacyAsset.java @@ -2,19 +2,18 @@ import java.util.*; -import org.jdom.*; import org.josql.*; import com.quollwriter.*; public abstract class LegacyAsset extends Asset { - + public static final String NAME_LEGACY_FIELD_ID = "name"; public static final String DESCRIPTION_LEGACY_FIELD_ID = "description"; public static final String ALIASES_LEGACY_FIELD_ID = "aliases"; - - public static Map supportedLegacyTypes = new LinkedHashMap (); + + public static Map supportedLegacyTypes = new LinkedHashMap (); static { @@ -31,26 +30,26 @@ public abstract class LegacyAsset extends Asset ResearchItem.class); } - + public LegacyAsset (String objType) { - + super (Environment.getUserConfigurableObjectType (objType)); - + } - + @Override public void fillToStringProperties (Map props) { super.fillToStringProperties (props); - + this.addToStringProperties (props, "legacyAsset", - true); + true); + + } - } - public static Asset createLegacyAsset (UserConfigurableObjectType objectType) throws GeneralException { @@ -67,7 +66,7 @@ public static Asset createLegacyAsset (UserConfigurableObjectType objectType) try { - return (Asset) cl.newInstance (); + return (Asset) cl.getDeclaredConstructor ().newInstance (); } catch (Exception e) { @@ -81,95 +80,105 @@ public static Asset createLegacyAsset (UserConfigurableObjectType objectType) } } - + public boolean isFieldSupported (String id) { - + if (id.equals (ALIASES_LEGACY_FIELD_ID)) { - + return true; - + } - + return false; - + } @Override public void setAliases (String a) { - + this.setAliases (new StringWithMarkup (a)); - + } - + public void setAliases (StringWithMarkup a) { - + if (this.isFieldSupported (ALIASES_LEGACY_FIELD_ID)) { - + UserConfigurableObjectField f = this.getLegacyField (ALIASES_LEGACY_FIELD_ID); - + if (f == null) { - + UserConfigurableObjectTypeField type = this.getLegacyTypeField (ALIASES_LEGACY_FIELD_ID); - + if (type == null) { return; } - + f = new UserConfigurableObjectField (type); - + this.addField (f); - + + } + + try + { + + f.setValue (JSONEncoder.encode (a)); + + } catch (Exception e) { + + Environment.logError ("Unable to encode: " + a, + e); + } - - f.setValue (a); } - + super.setAliases (a.getText ()); - + } public UserConfigurableObjectTypeField getLegacyTypeField (String id) { - + if (this.userConfigObjType == null) { - + throw new IllegalStateException ("No configurable object type set"); - + } - + return this.userConfigObjType.getLegacyField (id); - + } public UserConfigurableObjectField getLegacyField (String id) { - + for (UserConfigurableObjectField f : this.fields) { - + if ((f.getLegacyFieldId () != null) && (f.getLegacyFieldId ().equals (id)) ) { - + return f; - + } - + } - + return null; - + } - -} \ No newline at end of file + +} diff --git a/src/com/quollwriter/data/LegacyUserConfigurableObject.java b/src/main/java/com/quollwriter/data/LegacyUserConfigurableObject.java similarity index 99% rename from src/com/quollwriter/data/LegacyUserConfigurableObject.java rename to src/main/java/com/quollwriter/data/LegacyUserConfigurableObject.java index 41cf099f..29bfc0e2 100644 --- a/src/com/quollwriter/data/LegacyUserConfigurableObject.java +++ b/src/main/java/com/quollwriter/data/LegacyUserConfigurableObject.java @@ -2,7 +2,6 @@ import java.util.*; -import org.jdom.*; import org.josql.*; import com.quollwriter.*; diff --git a/src/com/quollwriter/data/Link.java b/src/main/java/com/quollwriter/data/Link.java similarity index 95% rename from src/com/quollwriter/data/Link.java rename to src/main/java/com/quollwriter/data/Link.java index 4f6f9e7f..0a07a7bf 100644 --- a/src/com/quollwriter/data/Link.java +++ b/src/main/java/com/quollwriter/data/Link.java @@ -2,7 +2,7 @@ import java.util.*; -import org.jdom.*; +import org.dom4j.*; public class Link extends NamedObject @@ -31,12 +31,14 @@ public Link(NamedObject obj1, } + @Override public void getChanges (NamedObject old, Element root) { } + @Override public Set getAllNamedChildObjects () { @@ -72,6 +74,7 @@ public void setObject2 (NamedObject o) } + @Override public String toString () { @@ -100,6 +103,7 @@ public NamedObject getOtherObject (NamedObject o) } + @Override public boolean equals (Object o) { @@ -126,6 +130,7 @@ public boolean equals (Object o) } + @Override public int hashCode () { diff --git a/src/main/java/com/quollwriter/data/LinkedToUserConfigurableObjectTypeField.java b/src/main/java/com/quollwriter/data/LinkedToUserConfigurableObjectTypeField.java new file mode 100644 index 00000000..52c2809b --- /dev/null +++ b/src/main/java/com/quollwriter/data/LinkedToUserConfigurableObjectTypeField.java @@ -0,0 +1,67 @@ +package com.quollwriter.data; + +import java.util.*; + +import com.quollwriter.ui.fx.viewers.*; +import com.quollwriter.ui.fx.*; +import com.quollwriter.ui.fx.userobjects.*; + +public class LinkedToUserConfigurableObjectTypeField extends UserConfigurableObjectTypeField +{ + + protected LinkedToUserConfigurableObjectTypeField (Type type) + { + + super (type); + + } + + public LinkedToUserConfigurableObjectTypeField () + { + + super (Type.linkedto); + + } + + @Override + public com.quollwriter.ui.userobjects.UserConfigurableObjectFieldViewEditHandler getViewEditHandler (UserConfigurableObject obj, + UserConfigurableObjectField field, + com.quollwriter.ui.AbstractProjectViewer viewer) + { + + return null; + + } + + @Override + public UserConfigurableObjectFieldViewEditHandler getViewEditHandler2 (UserConfigurableObject obj, + UserConfigurableObjectField field, + IPropertyBinder binder, + AbstractProjectViewer viewer) + { + + return new LinkedToUserConfigurableObjectFieldViewEditHandler (this, + obj, + field, + binder, + viewer); + + } + + @Override + public com.quollwriter.ui.userobjects.UserConfigurableObjectTypeFieldConfigHandler getConfigHandler () + { + + return null; + + } + + @Override + public UserConfigurableObjectTypeFieldConfigHandler getConfigHandler2 () + { + + return new LinkedToUserConfigurableObjectTypeFieldConfigHandler (this); + + } + +} diff --git a/src/com/quollwriter/data/Location.java b/src/main/java/com/quollwriter/data/Location.java similarity index 89% rename from src/com/quollwriter/data/Location.java rename to src/main/java/com/quollwriter/data/Location.java index 9bd299bf..5c05a95e 100644 --- a/src/com/quollwriter/data/Location.java +++ b/src/main/java/com/quollwriter/data/Location.java @@ -1,6 +1,6 @@ package com.quollwriter.data; -import org.jdom.*; +import org.dom4j.*; public class Location extends LegacyAsset { @@ -11,13 +11,14 @@ public Location () { super (Location.OBJECT_TYPE); - + } + @Override public void getChanges (NamedObject old, Element root) { } - + } diff --git a/src/main/java/com/quollwriter/data/MultiTextUserConfigurableObjectTypeField.java b/src/main/java/com/quollwriter/data/MultiTextUserConfigurableObjectTypeField.java new file mode 100644 index 00000000..2e3f14cb --- /dev/null +++ b/src/main/java/com/quollwriter/data/MultiTextUserConfigurableObjectTypeField.java @@ -0,0 +1,95 @@ +package com.quollwriter.data; + +import java.awt.Dimension; + +import java.util.Map; +import java.util.Set; +import java.util.LinkedHashSet; + +import com.quollwriter.ui.fx.*; +import com.quollwriter.ui.fx.viewers.*; +import com.quollwriter.ui.fx.userobjects.*; + +public class MultiTextUserConfigurableObjectTypeField extends UserConfigurableObjectTypeField +{ + + public MultiTextUserConfigurableObjectTypeField () + { + + super (Type.multitext); + + } + + protected MultiTextUserConfigurableObjectTypeField (Type type) + { + + super (type); + + } + + @Override + public com.quollwriter.ui.userobjects.UserConfigurableObjectFieldViewEditHandler getViewEditHandler (UserConfigurableObject obj, + UserConfigurableObjectField field, + com.quollwriter.ui.AbstractProjectViewer viewer) + { + + return new com.quollwriter.ui.userobjects.MultiTextUserConfigurableObjectFieldViewEditHandler (this, + obj, + field, + viewer); + + } + + @Override + public UserConfigurableObjectFieldViewEditHandler getViewEditHandler2 (UserConfigurableObject obj, + UserConfigurableObjectField field, + IPropertyBinder binder, + AbstractProjectViewer viewer) + { + + return new MultiTextUserConfigurableObjectFieldViewEditHandler (this, + obj, + field, + viewer); + + } + + @Override + public com.quollwriter.ui.userobjects.UserConfigurableObjectTypeFieldConfigHandler getConfigHandler () + { + + return new com.quollwriter.ui.userobjects.MultiTextUserConfigurableObjectTypeFieldConfigHandler (this); + + } + + @Override + public UserConfigurableObjectTypeFieldConfigHandler getConfigHandler2 () + { + + return new MultiTextUserConfigurableObjectTypeFieldConfigHandler (this); + + } + + public void setDisplayAsBullets (boolean v) + { + + this.setDefinitionValue ("displayAsBullets", v); + + } + + public boolean isDisplayAsBullets () + { + + return this.getBooleanDefinitionValue ("displayAsBullets"); + + } + + @Override + public boolean isSearchable () + { + + return true; + + } + +} diff --git a/src/main/java/com/quollwriter/data/NamedObject.java b/src/main/java/com/quollwriter/data/NamedObject.java new file mode 100644 index 00000000..fde52660 --- /dev/null +++ b/src/main/java/com/quollwriter/data/NamedObject.java @@ -0,0 +1,1042 @@ +package com.quollwriter.data; + +import java.io.*; +import java.nio.file.*; +import java.util.*; + +import javafx.collections.*; +import javafx.beans.property.*; + +import com.quollwriter.*; + +import com.quollwriter.data.comparators.*; + +import org.dom4j.*; +import org.dom4j.tree.*; + +public abstract class NamedObject extends DataObject +{ + + public static final String NAME = "name"; + public static final String LAST_MODIFIED = "lastModified"; + public static final String DESCRIPTION = "description"; + public static final String ALIASES = "aliases"; + public static final String TAG = "tag"; + + private StringProperty nameProp = null; + private String name = null; + private Date lastModified = null; + private StringWithMarkup description = null; + private ObjectProperty descriptionProp = null; + private ObservableSet links = null; + private ObservableSet notes = FXCollections.observableSet (new TreeSet<> (new ChapterItemSorter ())); + private String aliases = null; + private ObservableSet files = FXCollections.observableSet (new LinkedHashSet<> ()); + private Set tags = new LinkedHashSet<> (); + + public NamedObject (String objType, + String name) + { + + super (objType); + + this.nameProp = new SimpleStringProperty (); + this.descriptionProp = new SimpleObjectProperty<> (); + this.links = FXCollections.observableSet (new HashSet<> ()); + + if (name != null) + { + + this.setName (name); + + } + + this.notes.addListener ((SetChangeListener) ev -> + { + + if (ev.wasRemoved ()) + { + + Note n = ev.getElementRemoved (); + + n.dispose (); + + } + + }); + + } + + public NamedObject (String objType) + { + + this (objType, + null); + + } + + public StringProperty nameProperty () + { + + return this.nameProp; + + } + + public void merge (T other) + { + + String od = other.getDescriptionText (); + + String td = this.getDescriptionText (); + + if ((td == null) + && + (od != null) + ) + { + + this.setDescription (other.getDescription ()); + + } + + if ((td != null) + && + (od != null) + ) + { + + td = td.trim (); + od = od.trim (); + + if ((!td.equalsIgnoreCase (od)) + && + (!td.toLowerCase ().contains (od.toLowerCase ())) + ) + { + + String nd = td + "\n\n" + od; + + this.setDescription (new StringWithMarkup (nd, + this.getDescription ().getMarkup ())); + + } + + } + + Set taliases = new LinkedHashSet (this.getAliasesAsList ()); + + taliases.addAll (other.getAliasesAsList ()); + + if (taliases.size () > 0) + { + + StringBuilder b = new StringBuilder (); + + int i = 0; + + for (String a : taliases) + { + + b.append (a); + + if (i < taliases.size () - 1) + { + + b.append (","); + + } + + i++; + + } + + this.setAliases (b.toString ()); + + } + + } + + @Override + public void fillToStringProperties (Map props) + { + + super.fillToStringProperties (props); + + this.addToStringProperties (props, + "name", + this.name); + this.addToStringProperties (props, + "lastModified", + this.lastModified); + this.addToStringProperties (props, + "links", + this.links.size ()); + this.addToStringProperties (props, + "notes", + this.notes.size ()); + this.addToStringProperties (props, + "tags", + this.tags); + + } + + public synchronized void reindex () + { + + /* + TODO Is this needed? + Set nnotes = new TreeSet (new ChapterItemSorter ()); + + nnotes.addAll (this.notes); + + this.notes = nnotes; + + for (Note n : this.notes) + { + + n.reindex (); + + } + */ + + } + + public boolean contains (String s) + { + + if (s == null) + { + + return false; + + } + + s = s.trim ().toLowerCase (); + + if (s.length () == 0) + { + + return false; + + } + + if (this.name.toLowerCase ().indexOf (s) != -1) + { + + return true; + + } + + if ((this.description != null) + && + (this.description.getText () != null) + ) + { + + if (this.description.getText ().toLowerCase ().indexOf (s) != -1) + { + + return true; + + } + + } + + if (this.aliases != null) + { + + if (this.aliases.toLowerCase ().indexOf (s) != -1) + { + + return true; + + } + + } + + return false; + + } + + public Note getNoteAt (int pos) + { + + for (Note n : this.notes) + { + + if (n.getPosition () == pos) + { + + return n; + + } + + } + + return null; + + } + + public Set getNotesForType (String t) + { + + Set notes = new TreeSet (new ChapterItemSorter ()); + + for (Note n : this.notes) + { + + if (n.getType ().equals (t)) + { + + notes.add (n); + + } + + } + + return notes; + + } + + public Set getNotesAt (int pos) + { + + Set notes = new TreeSet (new ChapterItemSorter ()); + + for (Note n : this.notes) + { + + if (n.getPosition () == pos) + { + + notes.add (n); + + } + + } + + return notes; + + } + + public DataObject getObjectForReference (ObjectReference r) + { + + if (r.equals (this.getObjectReference ())) + { + + return this; + + } + + DataObject d = null; + + for (Note n : this.notes) + { + + d = n.getObjectForReference (r); + + if (d != null) + { + + break; + + } + + } + + return d; + + } + + public abstract Set getAllNamedChildObjects (); + + public ObservableSet getFiles () + { + + return this.files; + + } + + public void setFiles (Set files) + { + + this.files.clear (); + this.files.addAll (files); + + } + + public void addFile (Path f) + { + + this.files.add (f); + + } + + public void removeFile (Path f) + { + + this.files.remove (f); + + } + + public void addNote (Note n) + { + + n.setObject (this); + + n.setParent (this); + + this.notes.add (n); + + } + + public void removeNote (Note n) + { + + this.notes.remove (n); + + } + + public ObservableSet getNotes () + { + + return this.notes; + + } + + public Set getAllNames () + { + + Set l = new HashSet (); + + l.add (this.name); + + l.addAll (this.getAliasesAsList ()); + + return l; + + } + + public List getAliasesAsList () + { + + List l = new ArrayList (); + + if (this.aliases != null) + { + + StringTokenizer t = new StringTokenizer (this.aliases, + ",;" + String.valueOf ('\n')); + + while (t.hasMoreTokens ()) + { + + l.add (t.nextToken ().trim ()); + + } + + } + + return l; + + } + + public String getAliases () + { + + return this.aliases; + + } + + public void setAliases (String a) + { + + String oldAliases = this.aliases; + + this.aliases = a; + + this.firePropertyChangedEvent (NamedObject.ALIASES, + oldAliases, + this.aliases); + + } + + public void setLinks (Set others) + { + + this.removeAllLinks (); + + for (NamedObject o : others) + { + + if (o == null) + { + + continue; + + } + + if (this.equals (o)) + { + + continue; + + } + + this.addLink (new Link (this, o)); + + } + + } + + public Link getLinkFor (NamedObject o) + { + + for (Link l : this.links) + { + + if (l.getOtherObject (this).equals (o)) + { + + return l; + + } + + } + + return null; + + } + + public void removeAllLinks () + { + + new HashSet<> (this.links).stream () + .forEach (l -> this.removeLink (l)); + + } + + public void removeLink (Link l) + { + + if (!this.links.contains (l)) + { + + return; + + } + + this.links.remove (l); + + l.getOtherObject (this).removeLink (l); + + } + + public void addLink (Link l) + { + + if (this.links.contains (l)) + { + + return; + + } + + this.links.add (l); + + l.getOtherObject (this).addLink (l); + + } + + public Set getOtherObjectsInLinks () + { + + Set s = new TreeSet (NamedObjectSorter.getInstance ()); + + Iterator it = this.links.iterator (); + + while (it.hasNext ()) + { + + Link l = it.next (); + + s.add (l.getOtherObject (this)); + + } + + return s; + + } + + public void addLinkTo (NamedObject o) + { + + if (this == o) + { + + return; + + } + + this.addLink (new Link (this, + o)); + + } + + public ObservableSet getLinks () + { + + return this.links; + + } + + public void removeLinkFor (NamedObject n) + { + + Link rem = null; + Iterator iter = this.links.iterator (); + + while (iter.hasNext ()) + { + + Link l = iter.next (); + + if (l.getOtherObject (this) == n) + { + + rem = l; + + break; + + } + + } + + if (rem != null) + { + + this.removeLink (rem); + + } + + } + + public Date getLastModified () + { + + if (this.lastModified == null) + { + + return this.getDateCreated (); + + } + + return this.lastModified; + + } + + public String getDescriptionText () + { + + if (this.description != null) + { + + return this.description.getText (); + + } + + return null; + + } + + public StringWithMarkup getDescription () + { + + return this.description; + + } + + public ObjectProperty descriptionProperty () + { + + return this.descriptionProp; + + } + + public void setDescription (StringWithMarkup d) + { + + StringWithMarkup oldDesc = this.description; + + this.description = d; + + this.descriptionProp.setValue (d); + + this.setLastModified (new Date ()); + + this.firePropertyChangedEvent (NamedObject.DESCRIPTION, + oldDesc, + this.description); + + } + + public void setName (String n) + { + + /* + TODO Add this, currently causes problems with editors. + if (n == null) + { + + throw new IllegalArgumentException ("Name cannot be null."); + + } + */ + + String oldName = this.name; + + this.name = n; +/* +TODO Remove, isn't working. + if (this.name == null) + { + + this.name = "#ERROR:[NO NAME]"; + + } +*/ + this.nameProp.setValue (this.name); + + this.setLastModified (new Date ()); + + this.firePropertyChangedEvent (NamedObject.NAME, + oldName, + this.name); + + } + + public String getName () + { + + return this.name; + + } + + public void setLastModified (Date d) + { + + Date oldDate = this.lastModified; + + this.lastModified = d; + + if (oldDate == null) + { + + oldDate = new Date (); + oldDate.setTime (0); + + } + + this.firePropertyChangedEvent (NamedObject.LAST_MODIFIED, + oldDate, + this.lastModified); + + } + + public abstract void getChanges (NamedObject old, + Element root); + + protected void addFieldChangeElement (Element changesEl, + String fieldName, + String oldValue, + String newValue) + { + + if (NamedObject.areDifferent (oldValue, + newValue)) + { + + Element fieldEl = new DefaultElement ("field"); + + changesEl.add (fieldEl); + + fieldEl.addAttribute ("name", + fieldName); + + Element oldEl = new DefaultElement ("old"); + Element newEl = new DefaultElement ("new"); + + oldEl.add (new DefaultCDATA ((oldValue != null) ? oldValue : (null + ""))); + newEl.add (new DefaultCDATA ((newValue != null) ? (newValue + "") : (null + ""))); + + fieldEl.add (oldEl); + fieldEl.add (newEl); + + } + + } + + protected void addFieldChangeElement (Element changesEl, + String fieldName, + StringWithMarkup oldValue, + StringWithMarkup newValue) + { + + String ot = (oldValue != null ? oldValue.getText () : null); + String nt = (newValue != null ? newValue.getText () : null); + + if (NamedObject.areDifferent (ot, + nt)) + { + + Element fieldEl = new DefaultElement ("field"); + + changesEl.add (fieldEl); + + fieldEl.addAttribute ("name", + fieldName); + + Element oldEl = new DefaultElement ("old"); + Element newEl = new DefaultElement ("new"); + + oldEl.add (new DefaultCDATA ((ot != null) ? (ot + "") : (null + ""))); + newEl.add (new DefaultCDATA ((nt != null) ? (nt + "") : (null + ""))); + + fieldEl.add (oldEl); + fieldEl.add (newEl); + + } + + } + + protected void addFieldChangeElement (Element changesEl, + String fieldName, + Date oldValue, + Date newValue) + { + + if (NamedObject.areDifferent (oldValue, + newValue)) + { + + Element fieldEl = new DefaultElement ("field"); + + changesEl.add (fieldEl); + + fieldEl.addAttribute ("name", + fieldName); + + Element oldEl = new DefaultElement ("old"); + Element newEl = new DefaultElement ("new"); + + oldEl.add (new DefaultCDATA ((oldValue != null) ? (oldValue.getTime () + "") : (null + ""))); + newEl.add (new DefaultCDATA ((newValue != null) ? (newValue.getTime () + "") : (null + ""))); + + fieldEl.add (oldEl); + fieldEl.add (newEl); + + } + + } + + public Element getChanges (NamedObject old) + { + + Element root = new DefaultElement ("changes"); + + this.addFieldChangeElement (root, + "name", + ((old != null) ? old.getName () : null), + this.name); + + this.addFieldChangeElement (root, + "aliases", + ((old != null) ? old.getAliases () : null), + this.aliases); + + this.addFieldChangeElement (root, + "description", + ((old != null) ? old.getDescription () : null), + this.description); + + this.getChanges (old, + root); + + if (root.content ().size () > 0) + { + + return root; + + } + + return null; + + } + + public void addTag (Tag t) + { + + if (t == null) + { + + return; + + } + + this.tags.add (t); + + this.updateTags (); + + this.getProject ().addTagToObject (t, + this); + + this.firePropertyChangedEvent (NamedObject.TAG, + null, + t); + + } + + public void removeTag (Tag t) + { + + if (t == null) + { + + return; + + } + + this.tags.remove (t); + + this.updateTags (); + + this.getProject ().removeTagFromObject (t, + this); + + this.firePropertyChangedEvent (NamedObject.TAG, + t, + null); + + } + + public Set getTags () + { + + return this.tags; + + } + + public boolean hasTag (Tag t) + { + + if (t == null) + { + + return false; + + } + + return this.tags.contains (t); + + } + + private void updateTags () + { + + Set tagKeys = new LinkedHashSet<> (); + + for (Tag t : this.tags) + { + + tagKeys.add (t.getKey ().toString ()); + + } + + try + { + + this.setProperty (Constants.TAGS_PROPERTY_NAME, + Utils.joinStrings (tagKeys, + ";")); + + } catch (Exception e) { + + Environment.logError ("Unable to updated tags to: " + + tagKeys + + " for: " + + this, + e); + + } + + } + + @Override + public void setPropertiesAsString (String s) + throws Exception + { + + super.setPropertiesAsString (s); + + Set tagKeys = new LinkedHashSet (Utils.splitString (this.getProperty (Constants.TAGS_PROPERTY_NAME), + ";")); + + for (String k : tagKeys) + { + + try + { + + Tag t = Environment.getTagByKey (Long.parseLong (k)); + + if (t != null) + { + + this.tags.add (t); + + } + + } catch (Exception e) { + + // Ignore. + + } + + } + + } + + public static boolean areDifferent (Comparable o, + Comparable n) + { + + if ((o == null) && + (n == null)) + { + + return false; + + } + + if ((o != null) && + (n == null)) + { + + return true; + + } + + if ((o == null) && + (n != null)) + { + + return true; + + } + + return o.compareTo (n) != 0; + + } + +} diff --git a/src/com/quollwriter/data/NamedObjectNameWrapper.java b/src/main/java/com/quollwriter/data/NamedObjectNameWrapper.java similarity index 89% rename from src/com/quollwriter/data/NamedObjectNameWrapper.java rename to src/main/java/com/quollwriter/data/NamedObjectNameWrapper.java index 4b276303..ded238da 100644 --- a/src/com/quollwriter/data/NamedObjectNameWrapper.java +++ b/src/main/java/com/quollwriter/data/NamedObjectNameWrapper.java @@ -32,7 +32,7 @@ public static void addTo (NamedObject n, if (nitems == null) { - nitems = new ArrayList (); + nitems = new ArrayList<> (); m.put (i.name.toLowerCase (), nitems); @@ -48,19 +48,19 @@ public static void addTo (NamedObject n, public static List getForAllNames (NamedObject n) { - List ret = new ArrayList (); + List ret = new ArrayList<> (); for (String name : n.getAllNames ()) { if (name != null) { - + ret.add (new NamedObjectNameWrapper (name, n)); } - + } return ret; diff --git a/src/com/quollwriter/data/Note.java b/src/main/java/com/quollwriter/data/Note.java similarity index 86% rename from src/com/quollwriter/data/Note.java rename to src/main/java/com/quollwriter/data/Note.java index 6d4f2afc..35a4d5a1 100644 --- a/src/com/quollwriter/data/Note.java +++ b/src/main/java/com/quollwriter/data/Note.java @@ -2,7 +2,9 @@ import java.util.*; -import org.jdom.*; +import javafx.beans.property.*; + +import org.dom4j.*; import com.quollwriter.text.*; @@ -18,7 +20,7 @@ public class Note extends ChapterItem private Date due = null; private String type = null; private NamedObject object = null; - private Date dealtWith = null; + private ObjectProperty dealtWithProp = new SimpleObjectProperty (); public Note() { @@ -66,37 +68,45 @@ public void fillToStringProperties (Map props) this.object); this.addToStringProperties (props, "dealtWith", - this.dealtWith); + this.dealtWithProp.getValue ()); + + } + + public ObjectProperty dealtWithProperty () + { + + return this.dealtWithProp; } public boolean isDealtWith () { - return this.dealtWith != null; + return this.dealtWithProp.getValue () != null; } public Date getDealtWith () { - return this.dealtWith; + return this.dealtWithProp.getValue (); } public void setDealtWith (Date d) { - Date oldd = this.dealtWith; + Date oldd = this.dealtWithProp.getValue (); - this.dealtWith = d; + this.dealtWithProp.setValue (d); this.firePropertyChangedEvent (Note.DEALT_WITH, oldd, - this.dealtWith); + this.dealtWithProp.getValue ()); } + @Override public void getChanges (NamedObject old, Element root) { diff --git a/src/main/java/com/quollwriter/data/NumberUserConfigurableObjectTypeField.java b/src/main/java/com/quollwriter/data/NumberUserConfigurableObjectTypeField.java new file mode 100644 index 00000000..6d4aa994 --- /dev/null +++ b/src/main/java/com/quollwriter/data/NumberUserConfigurableObjectTypeField.java @@ -0,0 +1,108 @@ +package com.quollwriter.data; + +import java.util.*; + +import java.math.*; + +import com.quollwriter.*; +import com.quollwriter.ui.fx.*; +import com.quollwriter.ui.fx.userobjects.*; +import com.quollwriter.ui.fx.viewers.*; + +public class NumberUserConfigurableObjectTypeField extends UserConfigurableObjectTypeField +{ + + public static final String MAX = "max"; + public static final String MIN = "min"; + + public NumberUserConfigurableObjectTypeField () + { + + super (Type.number); + + } + + @Override + public boolean isSortable () + { + + return true; + + } + + @Override + public com.quollwriter.ui.userobjects.UserConfigurableObjectFieldViewEditHandler getViewEditHandler (UserConfigurableObject obj, + UserConfigurableObjectField field, + com.quollwriter.ui.AbstractProjectViewer viewer) + { + + return new com.quollwriter.ui.userobjects.NumberUserConfigurableObjectFieldViewEditHandler (this, + obj, + field, + viewer); + + } + + @Override + public UserConfigurableObjectFieldViewEditHandler getViewEditHandler2 (UserConfigurableObject obj, + UserConfigurableObjectField field, + IPropertyBinder binder, + AbstractProjectViewer viewer) + { + + return new NumberUserConfigurableObjectFieldViewEditHandler (this, + obj, + field, + viewer); + + } + + @Override + public com.quollwriter.ui.userobjects.UserConfigurableObjectTypeFieldConfigHandler getConfigHandler () + { + + return new com.quollwriter.ui.userobjects.NumberUserConfigurableObjectTypeFieldConfigHandler (this); + + } + + @Override + public UserConfigurableObjectTypeFieldConfigHandler getConfigHandler2 () + { + + return new NumberUserConfigurableObjectTypeFieldConfigHandler (this); + + } + + public Double getMinimum () + throws GeneralException + { + + return this.getDoubleDefinitionValue (MIN); + + } + + public void setMinimum (Double v) + { + + this.setDefinitionValue (MIN, + (v != null ? Environment.formatNumber (v) : null)); + + } + + public Double getMaximum () + throws GeneralException + { + + return this.getDoubleDefinitionValue (MAX); + + } + + public void setMaximum (Double v) + { + + this.setDefinitionValue (MAX, + (v != null ? Environment.formatNumber (v) : null)); + + } + +} diff --git a/src/main/java/com/quollwriter/data/ObjectDescriptionUserConfigurableObjectTypeField.java b/src/main/java/com/quollwriter/data/ObjectDescriptionUserConfigurableObjectTypeField.java new file mode 100644 index 00000000..08b53f22 --- /dev/null +++ b/src/main/java/com/quollwriter/data/ObjectDescriptionUserConfigurableObjectTypeField.java @@ -0,0 +1,95 @@ +package com.quollwriter.data; + +import com.quollwriter.ui.fx.*; +import com.quollwriter.ui.fx.userobjects.*; +import com.quollwriter.ui.fx.viewers.*; + +/** + * Models a text user configurable object field. + */ +public class ObjectDescriptionUserConfigurableObjectTypeField extends MultiTextUserConfigurableObjectTypeField +{ + + public ObjectDescriptionUserConfigurableObjectTypeField () + { + + super (Type.objectdesc); + + this.setDefinitionValue ("isObjectDesc", true); + + } + + @Override + public boolean canDelete () + { + + return true; + + } + + @Override + public com.quollwriter.ui.userobjects.UserConfigurableObjectTypeFieldConfigHandler getConfigHandler () + { + + return new com.quollwriter.ui.userobjects.ObjectDescriptionUserConfigurableObjectTypeFieldConfigHandler (this); + + } + + @Override + public UserConfigurableObjectTypeFieldConfigHandler getConfigHandler2 () + { + + return new ObjectDescriptionUserConfigurableObjectTypeFieldConfigHandler (this); + + } + + @Override + public com.quollwriter.ui.userobjects.UserConfigurableObjectFieldViewEditHandler getViewEditHandler (UserConfigurableObject obj, + UserConfigurableObjectField field, + com.quollwriter.ui.AbstractProjectViewer viewer) + { + + return new com.quollwriter.ui.userobjects.ObjectDescriptionUserConfigurableObjectFieldViewEditHandler (this, + obj, + field, + viewer); + + } + + @Override + public ObjectDescriptionUserConfigurableObjectFieldViewEditHandler getViewEditHandler2 (UserConfigurableObject obj, + UserConfigurableObjectField field, + IPropertyBinder binder, + AbstractProjectViewer viewer) + { + + return new ObjectDescriptionUserConfigurableObjectFieldViewEditHandler (this, + obj, + field, + viewer); + + } + + @Override + public boolean isSearchable () + { + + return true; + + } + + @Override + public void setNameField (boolean v) + { + + } + + @Override + public boolean isNameField () + { + + return false; + + } + +} diff --git a/src/main/java/com/quollwriter/data/ObjectImageUserConfigurableObjectTypeField.java b/src/main/java/com/quollwriter/data/ObjectImageUserConfigurableObjectTypeField.java new file mode 100644 index 00000000..a6a34f8a --- /dev/null +++ b/src/main/java/com/quollwriter/data/ObjectImageUserConfigurableObjectTypeField.java @@ -0,0 +1,73 @@ +package com.quollwriter.data; + +import java.util.Map; +import java.util.Set; +import java.util.LinkedHashSet; + +import javax.swing.*; + +import com.quollwriter.ui.fx.*; +import com.quollwriter.ui.fx.userobjects.*; +import com.quollwriter.ui.fx.viewers.*; + +public class ObjectImageUserConfigurableObjectTypeField extends ImageUserConfigurableObjectTypeField +{ + + public ObjectImageUserConfigurableObjectTypeField () + { + + super (Type.objectimage); + + } + + @Override + public com.quollwriter.ui.userobjects.UserConfigurableObjectFieldViewEditHandler getViewEditHandler (UserConfigurableObject obj, + UserConfigurableObjectField field, + com.quollwriter.ui.AbstractProjectViewer viewer) + { + + return new com.quollwriter.ui.userobjects.ObjectImageUserConfigurableObjectFieldViewEditHandler (this, + obj, + field, + viewer); + + } + + @Override + public UserConfigurableObjectFieldViewEditHandler getViewEditHandler2 (UserConfigurableObject obj, + UserConfigurableObjectField field, + IPropertyBinder binder, + AbstractProjectViewer viewer) + { + + return new ObjectImageUserConfigurableObjectFieldViewEditHandler (this, + obj, + field, + viewer); + + } + + public boolean isObjectImage () + { + + return true; + + } + + @Override + public com.quollwriter.ui.userobjects.UserConfigurableObjectTypeFieldConfigHandler getConfigHandler () + { + + return new com.quollwriter.ui.userobjects.ObjectImageUserConfigurableObjectTypeFieldConfigHandler (this); + + } + + @Override + public UserConfigurableObjectTypeFieldConfigHandler getConfigHandler2 () + { + + return new ObjectImageUserConfigurableObjectTypeFieldConfigHandler (this); + + } + +} diff --git a/src/main/java/com/quollwriter/data/ObjectNameUserConfigurableObjectTypeField.java b/src/main/java/com/quollwriter/data/ObjectNameUserConfigurableObjectTypeField.java new file mode 100644 index 00000000..fc9dd016 --- /dev/null +++ b/src/main/java/com/quollwriter/data/ObjectNameUserConfigurableObjectTypeField.java @@ -0,0 +1,104 @@ +package com.quollwriter.data; + +import com.quollwriter.ui.fx.viewers.*; +import com.quollwriter.ui.fx.userobjects.*; + +/** + * Models a text user configurable object field. + */ +public class ObjectNameUserConfigurableObjectTypeField extends UserConfigurableObjectTypeField +{ + + public ObjectNameUserConfigurableObjectTypeField () + { + + super (Type.objectname); + + } + + @Override + public boolean isSortable () + { + + return true; + + } + + @Override + public boolean canDelete () + { + + return false; + + } + + @Override + public UserConfigurableObjectTypeFieldConfigHandler getConfigHandler2 () + { + + return new ObjectNameUserConfigurableObjectTypeFieldConfigHandler (this); + + } + + @Override + public ObjectNameUserConfigurableObjectFieldViewEditHandler getViewEditHandler2 (UserConfigurableObject obj, + UserConfigurableObjectField field, + IPropertyBinder binder, + AbstractProjectViewer viewer) + { + + return new ObjectNameUserConfigurableObjectFieldViewEditHandler (this, + obj, + field, + viewer); + + } + + @Override + // TODO Remove + public com.quollwriter.ui.userobjects.UserConfigurableObjectTypeFieldConfigHandler getConfigHandler () + { + + return new com.quollwriter.ui.userobjects.ObjectNameUserConfigurableObjectTypeFieldConfigHandler (this); + + } + + @Override + // TODO Remove + public com.quollwriter.ui.userobjects.UserConfigurableObjectFieldViewEditHandler getViewEditHandler (UserConfigurableObject obj, + UserConfigurableObjectField field, + com.quollwriter.ui.AbstractProjectViewer viewer) + { + + return new com.quollwriter.ui.userobjects.ObjectNameUserConfigurableObjectFieldViewEditHandler (this, + obj, + field, + viewer); + + } + + @Override + public boolean isSearchable () + { + + return true; + + } + + @Override + public void setNameField (boolean v) + { + + // Ignore. + + } + + @Override + public boolean isNameField () + { + + return true; + + } + +} diff --git a/src/com/quollwriter/data/ObjectReference.java b/src/main/java/com/quollwriter/data/ObjectReference.java similarity index 100% rename from src/com/quollwriter/data/ObjectReference.java rename to src/main/java/com/quollwriter/data/ObjectReference.java diff --git a/src/main/java/com/quollwriter/data/OutlineItem.java b/src/main/java/com/quollwriter/data/OutlineItem.java new file mode 100644 index 00000000..6c8bc538 --- /dev/null +++ b/src/main/java/com/quollwriter/data/OutlineItem.java @@ -0,0 +1,158 @@ +package com.quollwriter.data; + +import java.text.*; +import java.util.*; + +import org.dom4j.*; + +import com.quollwriter.*; +import com.quollwriter.text.*; + +public class OutlineItem extends ChapterItem +{ + + public static final String OBJECT_TYPE = "outlineitem"; + + protected Scene scene = null; + // private Scene scene = null; + + public OutlineItem() + { + + super (OutlineItem.OBJECT_TYPE); + + } + + public OutlineItem(int at, + Chapter c) + { + + super (OutlineItem.OBJECT_TYPE, + at, + c); + + } + + public OutlineItem(int at, + Scene s) + { + + super (OutlineItem.OBJECT_TYPE, + at, + s.getChapter ()); + + this.scene = s; + + } + + @Override + public void dispose () + { + + this.scene = null; + super.dispose (); + + } + + + @Override + public void getChanges (NamedObject old, + Element root) + { + + } + + public Scene getScene () + { + + return this.scene; + + } + + public void setScene (Scene s) + { + + if ((this.scene != null) + && + (this.scene.equals (s)) + ) + { + + return; + + } + + if (s == null) + { + + if (this.scene != null) + { + + this.scene.removeOutlineItem (this); + + } + + } + + //s.addOutlineItem (this); + + this.scene = s; + this.setParent (s); + + } + + @Override + public void setPosition (int i) + { + + super.setPosition (i); + + } + + @Override + public void setDescription (StringWithMarkup d) + { + + // Legacy data check, can't control the order of calls that hibernate makes so ensure that it + // doesn't overwrite the description. + if ((this.getName () != null) && + (d == null)) + { + + return; + + } + + if (d != null) + { + + String t = d.getText (); + + TextIterator ti = new TextIterator (t); + + if (ti.getSentenceCount () > 0) + { + + this.setName (ti.getFirstSentence ().getText ()); + + } + + } + + super.setDescription (d); + + } + + @Override + public void fillToStringProperties (Map props) + { + + super.fillToStringProperties (props); + + this.addToStringProperties (props, + "scene", + this.scene); + + } + +} diff --git a/src/com/quollwriter/data/Positionable.java b/src/main/java/com/quollwriter/data/Positionable.java similarity index 100% rename from src/com/quollwriter/data/Positionable.java rename to src/main/java/com/quollwriter/data/Positionable.java diff --git a/src/main/java/com/quollwriter/data/Project.java b/src/main/java/com/quollwriter/data/Project.java new file mode 100644 index 00000000..c0fee4bf --- /dev/null +++ b/src/main/java/com/quollwriter/data/Project.java @@ -0,0 +1,2608 @@ +package com.quollwriter.data; + +import java.io.*; +import java.nio.file.*; + +import java.util.*; +import java.util.stream.*; + +import javafx.collections.*; +import javafx.beans.property.*; +import javafx.beans.value.*; + +import com.quollwriter.*; +import com.quollwriter.editors.*; +import com.quollwriter.data.editors.*; +import com.quollwriter.data.comparators.*; + +import com.quollwriter.events.*; + +import org.dom4j.*; +import org.dom4j.tree.*; + +public class Project extends NamedObject +{ + + public class XMLConstants + { + + public static final String projects = "projects"; + public static final String directory = "directory"; + public static final String name = "name"; + public static final String lastEdited = "lastEdited"; + public static final String encrypted = "encrypted"; + public static final String noCredentials = "noCredentials"; + public static final String type = "type"; + public static final String id = "id"; + public static final String forEditor = "forEditor"; + public static final String editDueDate = "editDueDate"; + + } + + public static final String LAST_EDITED = "lastEdited"; + public static final String PROJECT_DIRECTORY = "projectDirectory"; + public static final String BACKUP_DIRECTORY = "backupDirectory"; + + public static final String OBJECT_TYPE = "project"; + public static final String WORDCOUNTS_OBJECT_TYPE = "wordcounts"; + + // TODO: Change these to be an enum + public static final String NORMAL_PROJECT_TYPE = "normal"; + public static final String WARMUPS_PROJECT_TYPE = "warmups"; + public static final String EDITOR_PROJECT_TYPE = "editor"; + + public static final String BOOK_ADDED = "book_added"; + + private List books = new ArrayList<> (); + private int lastBookId = 0; + //private File projectDirectory = null; + private ObjectProperty backupDirectoryProp = null; + private ObjectProperty projectDirectoryProp = null; + //private File backupDirectory = null; + //private Date lastEdited = null; + private boolean backup = false; + private boolean encrypted = false; + private String backupVersion = null; + /* + private List characters = new ArrayList (); + private List locations = new ArrayList (); + private List objects = new ArrayList (); + private List researchItems = new ArrayList (); + */ + private ObservableSet ideaTypes = FXCollections.observableSet (new LinkedHashSet<> ()); + + private ObservableMap> assets = FXCollections.observableMap (new HashMap<> ()); + private String filePassword = null; + private boolean noCredentials = false; + private String type = Project.NORMAL_PROJECT_TYPE; + //private String editorsProjectId = null; + //private EditorProject editorProject = null; + + // TODO: Need a new object to encapsulate this stuff + //private EditorEditor forEditor = null; + private ObservableSet projectEditors = FXCollections.observableSet (new LinkedHashSet<> ()); + private ObjectProperty projVerProp = new SimpleObjectProperty<> (); + + private Map> taggedObjects = new HashMap<> (); + + private StringProperty toolbarLocationProp = null; + private ObjectProperty lastEditedProp = null; + private SimpleIntegerProperty chapterCountProp = null; + private IntegerProperty backupsToKeepCountProp = null; + private IntegerProperty autoBackupsTimeProp = null; + private BooleanProperty autoBackupsEnabledProp = null; + + public Project (Element pEl) + throws Exception + { + + this (); + + String name = DOM4JUtils.childElementContent (pEl, + XMLConstants.name); + String type = pEl.attributeValue (XMLConstants.type); + + String id = pEl.attributeValue (XMLConstants.id); + + if (id != null) + { + + this.setId (id); + + } + + String directory = DOM4JUtils.childElementContent (pEl, + XMLConstants.directory); + + boolean encrypted = DOM4JUtils.attributeValueAsBoolean (pEl, + XMLConstants.encrypted, + false); + + boolean noCredentials = false; + + if (pEl.attribute (XMLConstants.noCredentials) != null) + { + + noCredentials = DOM4JUtils.attributeValueAsBoolean (pEl, + XMLConstants.noCredentials); + + } + + String d = pEl.attributeValue (XMLConstants.lastEdited); + + File dir = new File (directory); + + this.setName (name); + + this.setProjectDirectory (dir); + this.setEncrypted (encrypted); + this.setNoCredentials (noCredentials); + + if (type != null) + { + + this.setType (type); + + if (this.isEditorProject ()) + { + + this.projVerProp.setValue (new ProjectVersion ()); + + String dueDate = pEl.attributeValue (XMLConstants.editDueDate); + + if (dueDate != null) + { + + // TODO: Fix this otherwise I will go to hell... + this.projVerProp.getValue ().setDueDate (new Date (Long.parseLong (dueDate))); + + } + + String editorEmail = DOM4JUtils.childElementContent (pEl, + XMLConstants.forEditor); + + if (editorEmail == null) + { + + throw new GeneralException ("Expected to find a child element: " + + XMLConstants.forEditor + + ", indicating who the project is being edited for."); + + } + + // Get the editor. + EditorEditor ed = EditorsEnvironment.getEditorByEmail (editorEmail); + + // If we are in debug mode then allow a null editor through. This is to allow + // testing of the send/receive cycle without having to resort to handling two + // different accounts or having per user projects.xml files. + if ((!Environment.isDebugModeEnabled ()) + && + (ed == null) + ) + { + + throw new GeneralException ("Expected to find editor with email: " + + editorEmail); + + } else { + + ed = new EditorEditor (); + ed.setKey (Long.valueOf (0)); + ed.setEmail (editorEmail); + + } + + this.setForEditor (editorEmail); + + //this.forEditor = ed; + + } + + } + + if (!d.equals ("")) + { + + try + { + + this.setLastEdited (new Date (Long.parseLong (d))); + + } catch (Exception e) + { + + // Ignore it. + + } + + } + + } + + public Project() + { + + super (Project.OBJECT_TYPE); + + this.init (); + + } + + public Project(String name) + { + + super (Project.OBJECT_TYPE, + name); + + this.init (); + + } + + private void init () + { + + this.projectDirectoryProp = new SimpleObjectProperty<> (); + this.backupDirectoryProp = new SimpleObjectProperty<> (); + this.chapterCountProp = new SimpleIntegerProperty (); + + this.addSetChangeListener (Environment.getUserConfigurableObjectTypes (), + ev -> + { + + if (ev.wasAdded ()) + { + + this.assets.put (ev.getElementAdded (), + FXCollections.observableSet (new LinkedHashSet<> ())); + + } + + if (ev.wasRemoved ()) + { + + this.assets.remove (ev.getElementRemoved ()); + + } + + }); + + Environment.getUserConfigurableObjectTypes ().stream () + .forEach (t -> + { + + this.assets.put (t, + FXCollections.observableSet (new LinkedHashSet<> ())); + + }); + + this.addSetChangeListener (Environment.getAllTags (), + ev -> + { + + Tag t = ev.getElementRemoved (); + + if (t != null) + { + + this.taggedObjects.remove (t); + + } + + }); + + this.lastEditedProp = new SimpleObjectProperty<> (); + + } + + public void setBackupsToKeepCount (int c) + { + + this.backupsToKeepCountProperty ().setValue (c); + + } + + public int getBackupsToKeepCount () + { + + return this.backupsToKeepCountProperty ().getValue (); + + } + + public IntegerProperty backupsToKeepCountProperty () + { + + if (this.backupsToKeepCountProp == null) + { + + this.backupsToKeepCountProp = new SimpleIntegerProperty (); + + com.gentlyweb.properties.AbstractProperty p = this.getProperties ().getPropertyObj (Constants.BACKUPS_TO_KEEP_COUNT_PROPERTY_NAME); + + if (p != null) + { + + // Has the property, try and use it. + if (p instanceof com.gentlyweb.properties.IntegerProperty) + { + + this.backupsToKeepCountProp.setValue (((com.gentlyweb.properties.IntegerProperty) p).getInteger ()); + + } else { + + com.gentlyweb.properties.StringProperty sp = (com.gentlyweb.properties.StringProperty) p; + + String v = sp.getValue (); + + int iv = -1; + + // Pre 2.6.5 + if (!v.equals ("All")) + { + + try + { + + iv = Integer.parseInt (v); + + } catch (Exception e) { + + // Ignore. + + } + + } + + this.backupsToKeepCountProp.setValue (iv); + + } + + } else { + + this.backupsToKeepCountProp.setValue (UserProperties.getBackupsToKeepCount ()); + + } + + this.backupsToKeepCountProp.addListener ((pr, oldv, newv) -> + { + + try + { + + this.setProperty (Constants.BACKUPS_TO_KEEP_COUNT_PROPERTY_NAME, + newv.intValue ()); + + } catch (Exception e) { + + Environment.logError ("Unable to set property to: " + + newv, + e); + + } + + }); + + } + + return this.backupsToKeepCountProp; + + } + + public int getAutoBackupsTime () + { + + return this.autoBackupsTimeProperty ().getValue (); + + } + + public void setAutoBackupsTime (long t) + { + + this.autoBackupsTimeProperty ().setValue ((int) t); + + } + + public IntegerProperty autoBackupsTimeProperty () + { + + if (this.autoBackupsTimeProp == null) + { + + this.autoBackupsTimeProp = new SimpleIntegerProperty (); + + com.gentlyweb.properties.AbstractProperty p = this.getProperties ().getPropertyObj (Constants.AUTO_SNAPSHOTS_TIME_PROPERTY_NAME); + + if (p != null) + { + + // Has the property, try and use it. + if (p instanceof com.gentlyweb.properties.IntegerProperty) + { + + this.autoBackupsTimeProp.setValue (((com.gentlyweb.properties.IntegerProperty) p).getInteger ()); + + } else { + + this.autoBackupsTimeProp.setValue (Utils.getTimeAsMillis (this.getProperty (Constants.AUTO_SNAPSHOTS_TIME_PROPERTY_NAME))); + + } + + } else { + + this.autoBackupsTimeProp.setValue (UserProperties.getAutoBackupsTime ()); + + } + + this.autoBackupsTimeProp.addListener ((pr, oldv, newv) -> + { + + try + { + + this.setProperty (Constants.AUTO_SNAPSHOTS_TIME_PROPERTY_NAME, + newv.intValue ()); + + } catch (Exception e) { + + Environment.logError ("Unable to update property to: " + + newv, + e); + + } + + }); + + } + + return this.autoBackupsTimeProp; + + } + + public boolean isAutoBackupsEnabled () + { + + return this.autoBackupsEnabledProperty ().getValue (); + + } + + public void setAutoBackupsEnabled (boolean v) + { + + this.autoBackupsEnabledProperty ().setValue (v); + + } + + public BooleanProperty autoBackupsEnabledProperty () + { + + if (this.autoBackupsEnabledProp == null) + { + + this.autoBackupsEnabledProp = new SimpleBooleanProperty (); + + boolean p = this.getPropertyAsBoolean (Constants.AUTO_SNAPSHOTS_ENABLED_PROPERTY_NAME); + + this.autoBackupsEnabledProp.setValue (p); + + this.autoBackupsEnabledProp.addListener ((pr, oldv, newv) -> + { + + try + { + + this.setProperty (Constants.AUTO_SNAPSHOTS_ENABLED_PROPERTY_NAME, + newv); + + } catch (Exception e) { + + Environment.logError ("Unable to update property to: " + + newv, + e); + + } + + }); + + } + + return this.autoBackupsEnabledProp; + + } + + + public StringProperty toolbarLocationProperty () + { + + if (this.toolbarLocationProp == null) + { + + this.toolbarLocationProp = new SimpleStringProperty (); + this.toolbarLocationProp.setValue (this.getProperty (Constants.TOOLBAR_LOCATION_PROPERTY_NAME)); + + } + + return this.toolbarLocationProp; + + } + + public ProjectEditor getProjectEditor (EditorEditor ed) + { + + if (this.projectEditors == null) + { + + return null; + + } + + for (ProjectEditor pe : this.projectEditors) + { + + if (pe.getEditor () == ed) + { + + return pe; + + } + + } + + return null; + + } + + public void addProjectEditor (ProjectEditor pe) + { + + this.projectEditors.add (pe); + + } + + public void removeProjectEditor (ProjectEditor pe) + { + + this.projectEditors.remove (pe); + + } + + public boolean isProjectEditor (EditorEditor ed) + { + + for (ProjectEditor pe : this.projectEditors) + { + + if (pe.getEditor () == ed) + { + + return true; + + } + + } + + return false; + + } + + public ObservableSet getProjectEditors () + { + + return this.projectEditors; + + } + + public void setProjectEditors (Collection eds) + { + + if (eds == null) + { + + return; + + } + + this.projectEditors.clear (); + this.projectEditors.addAll (eds); + + } + + public void setForEditor (String editorEmail) //EditorEditor ed) + { + +/* + if ((this.forEditor != null) + && + (ed == null) + ) + { + + throw new IllegalArgumentException ("Cannot remove forEditor once it has been set."); + + } + + if ((this.forEditor != null) + && + (!this.forEditor.getEmail ().equals (ed.getEmail ())) + ) + { + + throw new IllegalArgumentException ("Cannot change the forEditor once it has been set."); + + } + + this.forEditor = ed; +*/ + try + { + + this.setProperty (Constants.FOR_EDITOR_EMAIL_PROPERTY_NAME, + editorEmail); + //this.forEditor.getEmail ()); + + } catch (Exception e) { + + // Not really the correct type of exception to throw but it shouldn't be + // checked or handled "properly" either since it should always happen, this + // is just the weird edge case when something terrible goes wrong. + throw new IllegalArgumentException ("Unable to set the for editor", + e); + + } + + } + + public String getEditResponseMessage () + { + + return this.getProperty (Constants.EDITOR_RESPONSE_MESSAGE_PROPERTY_NAME); + + } + + public void setEditResponseMessage (String m) + { + + try + { + + this.setProperty (Constants.EDITOR_RESPONSE_MESSAGE_PROPERTY_NAME, + m); + + } catch (Exception e) { + + Environment.logError ("Unable to set response message: " + + m, + e); + + } + + } + + public void setProjectVersion (ProjectVersion pv) + { + + this.projVerProp.setValue (pv); + + } + + public ProjectVersion getProjectVersion () + { + + return this.projVerProp.getValue (); + + } + + public ObjectProperty projectVersionProperty () + { + + return this.projVerProp; + + } + + public EditorEditor getForEditor () + { + + if (this.isEditorProject ()) + { + + // Get the editor email. + String edEmail = this.getProperty (Constants.FOR_EDITOR_EMAIL_PROPERTY_NAME); + + if (edEmail == null) + { + + // This is a strange situation, what to do? + return null; + + } + + return EditorsEnvironment.getEditorByEmail (edEmail); + + } + + return null; + + //return this.forEditor; + + } + + public boolean isEditorProject () + { + + return this.type.equals (Project.EDITOR_PROJECT_TYPE); + + } + + public boolean isWarmupsProject () + { + + return this.type.equals (Project.WARMUPS_PROJECT_TYPE); + + } + + public boolean isNormalProject () + { + + return this.type.equals (Project.NORMAL_PROJECT_TYPE); + + } + + private void updateChapterCount () + { + + int c = 0; + + if (this.books != null) + { + + for (Book b : this.books) + { + + c += b.getChapters ().size (); + + } + + } + + this.chapterCountProp.setValue (c); + + } + + public int getChapterCount () + { + + return this.chapterCountProp.getValue (); + + } + + public IntegerProperty chapterCountProperty () + { + + return this.chapterCountProp; + + } + + public ReadabilityIndices getAllProjectReadabilityIndices () + { + + ReadabilityIndices ri = new ReadabilityIndices (); + + if (this.books == null) + { + + return ri; + + } + + for (Book b : this.books) + { + + for (Chapter c : b.getChapters ()) + { + + ri.add (c.getChapterText ()); + } + + } + + return ri; + + } + + public int getEditedWordCount () + { + + if (this.books == null) + { + + return 0; + + } + + final StringBuilder buf = new StringBuilder (); + + int editComplete = 0; + + for (Book b : this.books) + { + + for (Chapter c : b.getChapters ()) + { + + if (c.getEditPosition () > 0) + { + + if (buf.length () > 0) + { + + buf.append (" "); + + } + + String t = c.getChapterText (); + + if (t == null) + { + + continue; + + } + + if (c.getEditPosition () <= t.length ()) + { + + buf.append (t.substring (0, + c.getEditPosition ())); + + } + + } + + } + + } + + if (buf.length () > 0) + { + + ChapterCounts allc = new ChapterCounts (buf.toString ()); + + return allc.getWordCount (); + + } + + return 0; + + } + + public int getWordCount () + { + + int c = 0; + + if (this.books == null) + { + + return c; + + } + + for (Book b : this.books) + { + + c += b.getChapterWordCount (); + + } + + return c; + + } + /* + public void setEditorProject (EditorProject p) + { + + this.editorProject = p; + + if (p != null) + { + + p.setProject (this); + + } + + } + + public EditorProject getEditorProject () + { + + return this.editorProject; + + } + */ + /* + public void setEditorsProjectId (String id) + { + + this.editorsProjectId = id; + + } + + public String getEditorsProjectId () + { + + return this.editorsProjectId; + + } + */ + + public String getType () + { + + return this.type; + + } + + public void setType (String t) + { + + this.type = t; + + } + + @Override + public void getChanges (NamedObject old, + Element root) + { + + } + + public NamedObject getObjectById (Class ofType, + String id) + { + + Set objs = this.getAllNamedChildObjects (ofType); + + for (NamedObject o : objs) + { + + if (o.getId ().equals (id)) + { + + return o; + + } + + } + + return null; + + } + + public static Set getObjectsContaining (String s, + Project p) + { + + Set ret = new TreeSet (NamedObjectSorter.getInstance ()); + + for (NamedObject n : p.getAllNamedChildObjects ()) + { + + if (n.contains (s)) + { + + ret.add (n); + + } + + } + + return ret; + + } + + public Set getAssetsContaining (String s) + { + + Set ret = new TreeSet<> (NamedObjectSorter.getInstance ()); + + for (NamedObject n : this.getAllNamedChildObjects (Asset.class)) + { + + if (n.contains (s)) + { + + ret.add ((Asset) n); + + } + + } + + return ret; + + } + + public Set getAssetsContaining (String s, + UserConfigurableObjectType limitTo) + { + + Set ret = new TreeSet<> (NamedObjectSorter.getInstance ()); + + if (limitTo != null) + { + + if (!limitTo.isAssetObjectType ()) + { + + return ret; + + } + + } + + for (NamedObject n : this.getAllNamedChildObjects (limitTo)) + { + + if (n.contains (s)) + { + + ret.add ((Asset) n); + + } + + } + + return ret; + + } + + public Set getNotesContaining (String s) + { + + Set ret = new TreeSet (NamedObjectSorter.getInstance ()); + + for (NamedObject n : this.getAllNamedChildObjects (Note.class)) + { + + if (n.contains (s)) + { + + ret.add ((Note) n); + + } + + } + + return ret; + + } + + public Set getOutlineItemsContaining (String s) + { + + Set ret = new TreeSet (NamedObjectSorter.getInstance ()); + + for (NamedObject n : this.getAllNamedChildObjects (OutlineItem.class)) + { + + if (n.contains (s)) + { + + ret.add ((OutlineItem) n); + + } + + } + + return ret; + + } + + public Set getScenesContaining (String s) + { + + Set ret = new TreeSet (NamedObjectSorter.getInstance ()); + + for (NamedObject n : this.getAllNamedChildObjects (Scene.class)) + { + + if (n.contains (s)) + { + + ret.add ((Scene) n); + + } + + } + + return ret; + + } + + public ObservableSet getAllObjectsWithTag (Tag tag) + { + + ObservableSet objs = this.taggedObjects.get (tag); + + if (objs != null) + { + + return objs; + + } + + objs = FXCollections.observableSet (this.getAllNamedChildObjects ().stream () + .filter (o -> o.hasTag (tag)) + .collect (Collectors.toSet ())); + + this.taggedObjects.put (tag, + objs); + + return objs; + + } + + public Set getAllNamedChildObjects (UserConfigurableObjectType withType) + { + + Set ret = this.getAllNamedChildObjects (); + + Iterator iter = ret.iterator (); + + while (iter.hasNext ()) + { + + NamedObject o = iter.next (); + + if (!(o instanceof UserConfigurableObject)) + { + + iter.remove (); + + continue; + + } + + UserConfigurableObject uo = (UserConfigurableObject) o; + + if (!uo.getUserConfigurableObjectType ().equals (withType)) + { + + iter.remove (); + + } + + } + + return ret; + + } + + public Set getAllNamedChildObjects (Class ofType) + { + + Set ret = this.getAllNamedChildObjects (); + + Iterator iter = ret.iterator (); + + while (iter.hasNext ()) + { + + if (!ofType.isAssignableFrom (iter.next ().getClass ())) + { + + iter.remove (); + + } + + } + + return ret; + + } + + public Set getAllNamedChildObjects () + { + + Set ret = new TreeSet (NamedObjectSorter.getInstance ()); + + for (Book b : this.books) + { + + // TODO Is this correct? YOu can't do anything with a book so probably... + //ret.add (b); + + ret.addAll (b.getAllNamedChildObjects ()); + + } + + for (UserConfigurableObjectType t : this.assets.keySet ()) + { + + Set as = this.assets.get (t); + + for (Asset a : as) + { + + ret.add (a); + + ret.addAll (a.getAllNamedChildObjects ()); + + } + + } + + for (IdeaType it : this.ideaTypes) + { + + ret.add (it); + + ret.addAll (it.getAllNamedChildObjects ()); + + } + + return ret; + + } + + public boolean hasObject (DataObject d) + { + + if (d instanceof IdeaType) + { + + return this.getIdeaType (d.getKey ()) != null; + + } + + if (d instanceof Chapter) + { + + Chapter c = (Chapter) d; + + if (c.getBook () == null) + { + + return false; + + } + + return c.getBook ().getChapterByKey (d.getKey ()) != null; + + } + + if (d instanceof Asset) + { + + Asset a = (Asset) d; + + Set as = this.assets.get (a.getUserConfigurableObjectType ()); + + if (as != null) + { + + for (Asset _a : as) + { + + if (_a == a) + { + + return true; + + } + + } + + } + + return false; + + } + + return false; + + } + + public void removeObject (DataObject d) + { + + if (d instanceof IdeaType) + { + + this.getIdeaTypes ().remove (d); + + } + + if (d instanceof Asset) + { + + Asset a = (Asset) d; + + Set as = this.assets.get (a.getUserConfigurableObjectType ()); + + if (as != null) + { + + as.remove (a); + + } + + } + + if (d instanceof NamedObject) + { + + NamedObject n = (NamedObject) d; + + for (Tag t : new ArrayList<> (n.getTags ())) + { + + this.removeTagFromObject (t, + n); + + } + + } + + } + + public boolean hasAsset (Asset a) + { + + return this.getAssetByName (a.getName (), + a.getUserConfigurableObjectType ()) != null; + + } + + public Set getAllNamedObjectsByName (String n) + { + + Set ret = new LinkedHashSet (); + + Set objs = this.getAllNamedChildObjects (); + + for (NamedObject o : objs) + { + + Set names = o.getAllNames (); + + for (String name : names) + { + + if (n.equalsIgnoreCase (name)) + { + + ret.add (o); + + } + + } + + } + + return ret; + + } + + public Set getAllAssetsByName (String n, + UserConfigurableObjectType type) + { + + Set assets = new LinkedHashSet<> (); + + if (type != null) + { + + Asset as = this.getAssetByName (n, + type); + + if (as != null) + { + + assets.add (as); + + } + + return assets; + + } + + for (UserConfigurableObjectType t : this.assets.keySet ()) + { + + Asset as = this.getAssetByName (n, + t); + + if (as != null) + { + + assets.add (as); + + } + + } + + return assets; + + } + + public Asset getAssetByName (String n, + UserConfigurableObjectType type) + { + + Set as = this.assets.get (type); + + if (as == null) + { + + return null; + + } + + for (Asset a : as) + { + + Set names = a.getAllNames (); + + for (String name : names) + { + + if (n.equalsIgnoreCase (name)) + { + + return a; + + } + + } + + } + + return null; + + } + + private Asset getAssetByName_Int (List assets, + String n) + { + + n = n.toLowerCase (); + + for (Asset a : assets) + { + + if (a.getName ().toLowerCase ().equals (n)) + { + + return a; + + } + + } + + return null; + + } + + private Set getAllAssetsByName_Int (List assets, + String n) + { + + Set matched = new LinkedHashSet (); + + n = n.toLowerCase (); + + for (Asset a : assets) + { + + if (a.getName ().equalsIgnoreCase (n)) + { + + matched.add (a); + + continue; + + } + + List aliases = a.getAliasesAsList (); + + if (aliases != null) + { + + for (String al : aliases) + { + + if (al.equalsIgnoreCase (n)) + { + + matched.add (a); + + continue; + + } + + } + + } + + } + + return matched; + + } + + public Set getAssetTypes () + { + + return this.assets.keySet (); + + } + + public ObservableSet getAssets (UserConfigurableObjectType type) + { + + return this.assets.get (type); + + } + + public ObservableMap> getAssets () + { + + return this.assets; + + } + +/* + public Set getAllCharactersByName (String n) + { + + return (Set) this.getAllAssetsByName_Int (this.characters, + n); + + } + + public Set getAllLocationsByName (String n) + { + + return (Set) this.getAllAssetsByName_Int (this.locations, + n); + + } + + public Set getAllQObjectsByName (String n) + { + + return (Set) this.getAllAssetsByName_Int (this.objects, + n); + + } + + public Set getAllResearchItemsByName (String n) + { + + return (Set) this.getAllAssetsByName_Int (this.researchItems, + n); + + } +*/ +/* + public QCharacter getCharacterByName (String n) + { + + return (QCharacter) this.getAssetByName_Int (this.characters, + n); + + } + + public Location getLocationByName (String n) + { + + return (Location) this.getAssetByName_Int (this.locations, + n); + + } + + public QObject getQObjectByName (String n) + { + + return (QObject) this.getAssetByName_Int (this.objects, + n); + + } + + public ResearchItem getResearchItemByName (String n) + { + + return (ResearchItem) this.getAssetByName_Int (this.researchItems, + n); + + } +*/ + public boolean isNoCredentials () + { + + return this.noCredentials; + + } + + public void setNoCredentials (boolean v) + { + + this.noCredentials = v; + + } + + public void setFilePassword (String p) + { + + this.filePassword = p; + this.setEncrypted (p != null); + + } + + public String getFilePassword () + { + + return this.filePassword; + + } + + public boolean isEncrypted () + { + + return this.encrypted; + + } + + public void setEncrypted (boolean v) + { + + this.encrypted = v; + + } + + public Date getLastEdited () + { + + return this.lastEditedProp.getValue (); + + } + + public ObjectProperty lastEditedProperty () + { + + return this.lastEditedProp; + + } + + public void setLastEdited (Date d) + { + + Date oldDate = this.lastEditedProp.getValue (); + + this.lastEditedProp.setValue (d); + + this.firePropertyChangedEvent (Project.LAST_EDITED, + oldDate, + this.lastEditedProp.getValue ()); + + } + + public ObjectProperty projectDirectoryProperty () + { + + return this.projectDirectoryProp; + + } + + public File getProjectDirectory () + { + + return this.projectDirectoryProp.getValue (); + + } + + public void setProjectDirectory (File dir) + { + + File oldDir = this.projectDirectoryProp.getValue (); + + this.projectDirectoryProp.setValue (dir); + + this.firePropertyChangedEvent (Project.PROJECT_DIRECTORY, + oldDir, + this.projectDirectoryProp.getValue ()); + + } + + // TODO Remove + public void saveToFilesDirectory (File file, + String fileName) + throws GeneralException + { + + if ((file == null) + || + (!file.exists ()) + || + (file.isDirectory ()) + ) + { + + return; + + } + + File dir = this.getFilesDirectory (); + + dir.mkdirs (); + + try + { + + Utils.createQuollWriterDirFile (dir); + + } catch (Exception e) { + + throw new GeneralException ("Unable to create dir: " + dir, + e); + + } + + File f = new File (dir, + fileName); + + try + { + + Files.copy (file.toPath (), + f.toPath ()); + + } catch (Exception e) { + + throw new GeneralException ("Unable to copy file: " + file + " to: " + f, + e); + + } + + } + + public void saveToFilesDirectory (Path file, + String fileName) + throws GeneralException + { + + if ((file == null) + || + (Files.notExists (file)) + || + (Files.isDirectory (file)) + ) + { + + return; + + } + + Path dir = this.getFilesDirectory ().toPath (); + + try + { + + Files.createDirectories (dir); + + } catch (Exception e) { + + throw new GeneralException ("Unable to create dirs for: " + dir, + e); + + } + + Utils.createQuollWriterDirFile (dir); + + Path f = dir.resolve (fileName); + + try + { + + Files.copy (file, + f, + StandardCopyOption.REPLACE_EXISTING); + + } catch (Exception e) { + + throw new GeneralException ("Unable to copy file: " + file + " to: " + f, + e); + + } + + } + + public void deleteFile (String fileName) + { + + this.getFile (fileName).delete (); + + } + + public File getFile (String fileName) + { + + return new File (this.getFilesDirectory (), + fileName); + + } + + public File getFilesDirectory () + { + + return new File (this.projectDirectoryProp.getValue (), + Constants.PROJECT_FILES_DIR_NAME); + + } + + public File getBackupDirectory () + { + + File d = this.backupDirectoryProp.getValue (); + + if (d == null) + { + + d = new File (this.getProjectDirectory (), + "versions"); + this.backupDirectoryProp.setValue (d); + + } + + return this.backupDirectoryProp.getValue (); + + } + + public ObjectProperty backupDirectoryProperty () + { + + return this.backupDirectoryProp; + + } + + public void setBackupDirectory (File dir) + { + + File oldDir = this.backupDirectoryProp.getValue (); + + this.backupDirectoryProp.setValue (dir); + + this.firePropertyChangedEvent (Project.BACKUP_DIRECTORY, + oldDir, + this.backupDirectoryProp.getValue ()); + + } +/* + public List getCharacters () + { + + return this.characters; + + } + + public List getLocations () + { + + return this.locations; + + } + + public List getQObjects () + { + + return this.objects; + + } +*/ + public ObservableSet getIdeaTypes () + { + + return this.ideaTypes; + + } + + public void addIdeaType (IdeaType it) + { + + if (this.ideaTypes.contains (it)) + { + + return; + + } + + this.ideaTypes.add (it); + + it.setProject (this); + + } + + public void removeIdeaType (IdeaType it) + { + + this.ideaTypes.remove (it); + it.setProject (null); + + } + + public void addAsset (Asset a) + { + + Set as = this.assets.get (a.getUserConfigurableObjectType ()); + + if (as == null) + { + + throw new IllegalArgumentException ("Unable to find user config type: " + + a.getUserConfigurableObjectType ()); + + } + + a.setProject (this); + + as.add (a); + + } + + @Override + public void fillToStringProperties (Map props) + { + + super.fillToStringProperties (props); + + this.addToStringProperties (props, + "type", + this.type); + + this.addToStringProperties (props, + "projectDir", + (this.projectDirectoryProp.getValue () != null ? this.projectDirectoryProp.getValue ().getPath () : "Not set")); + this.addToStringProperties (props, + "backupDir", + (this.backupDirectoryProp.getValue () != null ? this.backupDirectoryProp.getValue ().getPath () : "Not set")); + this.addToStringProperties (props, + "filesDir", + (this.getFilesDirectory () != null ? this.getFilesDirectory ().getPath () : "Not set")); + + this.addToStringProperties (props, + "lastEdited", + this.lastEditedProp.getValue ()); + this.addToStringProperties (props, + "encrypted", + this.encrypted); + + for (UserConfigurableObjectType t : this.assets.keySet ()) + { + + Set as = this.assets.get (t); + + this.addToStringProperties (props, + t.getObjectTypeId (), + as.size ()); + + } + + this.addToStringProperties (props, + "ideaTypes", + this.ideaTypes.size ()); + + EditorEditor ed = this.getForEditor (); + + if (ed != null) + { + + this.addToStringProperties (props, + "forEditor", + ed.getEmail ()); + + } + + if (this.projectEditors != null) + { + + this.addToStringProperties (props, + "projectEditors", + this.projectEditors.size ()); + + } + + this.addToStringProperties (props, + "projectVersion", + this.projVerProp.getValue ()); + + } + + public int getBookIndex (Book b) + { + + return this.books.indexOf (b) + 1; + + } + + public List getBooks () + { + + return this.books; + + } + + public Chapter getChapterByKey (long k) + { + + for (Book b : this.books) + { + + Chapter c = b.getChapterByKey (k); + + if (c != null) + { + + return c; + + } + + } + + return null; + + } + + public Book getBook (int i) + { + + return (Book) this.books.get (i); + + } +/* + public QCharacter getCharacter (Long key) + { + + for (QCharacter c : this.characters) + { + + if (c.getKey ().equals (key)) + { + + return c; + + } + + } + + return null; + + } + */ +/* + public ResearchItem getResearchItem (Long key) + { + + for (ResearchItem r : this.researchItems) + { + + if (r.getKey ().equals (key)) + { + + return r; + + } + + } + + return null; + + } +*/ + public IdeaType getIdeaType (Long key) + { + + for (IdeaType i : this.ideaTypes) + { + + if (i.getKey () == key) + { + + return i; + + } + + } + + return null; + + } + /* + public QObject getQObject (Long key) + { + + for (QObject o : this.objects) + { + + if (o.getKey ().equals (key)) + { + + return o; + + } + + } + + return null; + + } + */ +/* + public Location getLocation (Long key) + { + + + for (Location l : this.locations) + { + + if (l.getKey ().equals (key)) + { + + return l; + + } + + } + + return null; + + } +*/ + public Book getBook (Long key) + { + + for (Book b : this.books) + { + + if (b.getKey ().equals (key)) + { + + return b; + + } + + } + + return null; + + } + + public DataObject getObjectForReference (ObjectReference r) + { + + if (r == null) + { + + return null; + + } + + DataObject d = super.getObjectForReference (r); + + if (d != null) + { + + return d; + + } + /* + if (r.getObjectType ().equals (Project.WORDCOUNTS_OBJECT_TYPE)) + { + + WordCount w = new WordCount (); + w.setKey (r.getKey ()); + w.setObjectType (Project.WORDCOUNTS_OBJECT_TYPE); + + return w; + + } + */ + + if (r.getObjectType ().equals (Chapter.INFORMATION_OBJECT_TYPE)) + { + + r = new ObjectReference (Chapter.OBJECT_TYPE, + r.getKey (), + null); + + } + + for (UserConfigurableObjectType t : this.assets.keySet ()) + { + + Set as = this.assets.get (t); + + for (Asset a : as) + { + + d = a.getObjectForReference (r); + + if (d != null) + { + + return d; + + } + + } + + } + /* + for (QCharacter c : this.characters) + { + + d = c.getObjectForReference (r); + + if (d != null) + { + + return d; + + } + + } + + for (Location l : this.locations) + { + + d = l.getObjectForReference (r); + + if (d != null) + { + + return d; + + } + + } + + for (QObject q : this.objects) + { + + d = q.getObjectForReference (r); + + if (d != null) + { + + return d; + + } + + } + + for (ResearchItem i : this.researchItems) + { + + d = i.getObjectForReference (r); + + if (d != null) + { + + return d; + + } + + } +*/ + for (Book b : this.books) + { + + d = b.getObjectForReference (r); + + if (d != null) + { + + return d; + + } + + } + + for (IdeaType it : this.ideaTypes) + { + + d = it.getObjectForReference (r); + + if (d != null) + { + + return d; + + } + + } + + return null; + + } + + public void addBook (Book b) + { + + if (this.books.contains (b)) + { + + return; + + } + + b.setProject (this); + + this.books.add (b); + + b.getChapters ().addListener ((ListChangeListener) ch -> + { + + this.updateChapterCount (); + + }); + + this.firePropertyChangedEvent (Project.BOOK_ADDED, + null, + b); + + } + + public int hashCode () + { + + int hash = 7; + hash = (31 * hash) + ((null == this.projectDirectoryProp.getValue ()) ? 0 : this.projectDirectoryProp.getValue ().hashCode ()); + + return hash; + + } + + public boolean equals (Object o) + { + + if (o == null) + { + + return false; + + } + + if (!(o instanceof Project)) + { + + return false; + + } + + Project po = (Project) o; + + if (this.projectDirectoryProp.getValue () == null) + { + + return false; + + } + + return this.projectDirectoryProp.getValue ().equals (po.projectDirectoryProp.getValue ()); + + } + + public Element getAsElement () + { + + Element pEl = new DefaultElement (Project.OBJECT_TYPE); + + Element nEl = new DefaultElement (Environment.XMLConstants.name); + pEl.add (nEl); + nEl.add (new DefaultCDATA (this.getName ())); + + if (this.getType () == null) + { + + this.setType (Project.NORMAL_PROJECT_TYPE); + + } + + pEl.addAttribute (XMLConstants.type, + this.getType ()); + + if (this.getId () != null) + { + + pEl.addAttribute (XMLConstants.id, + this.getId ()); + + } + + Element dEl = new DefaultElement (XMLConstants.directory); + pEl.add (dEl); + dEl.add (new DefaultCDATA (this.getProjectDirectory ().getPath ())); + + EditorEditor ed = this.getForEditor (); + + if (ed != null) + { + + Element fEl = new DefaultElement (XMLConstants.forEditor); + pEl.add (fEl); + fEl.add (new DefaultCDATA (ed.getEmail ())); + + } + + if ((this.isEditorProject ()) + && + (this.projVerProp.getValue () != null) + ) + { + + Date d = this.projVerProp.getValue ().getDueDate (); + + if (d != null) + { + + pEl.addAttribute (XMLConstants.editDueDate, + d.getTime () + ""); + + } + + } + + Date lastEdited = this.getLastEdited (); + + if (lastEdited != null) + { + + pEl.addAttribute (XMLConstants.lastEdited, + String.valueOf (lastEdited.getTime ())); + + } + + pEl.addAttribute (XMLConstants.encrypted, + Boolean.valueOf (this.isEncrypted ()).toString ()); + + if (this.isNoCredentials ()) + { + + pEl.addAttribute (XMLConstants.noCredentials, + Boolean.valueOf (this.isNoCredentials ()).toString ()); + + } +/* + if (this.editorsProjectId != null) + { + + pEl.setAttribute (XMLConstants.editorsProjectId, + this.editorsProjectId); + + } + */ + return pEl; + + } + + public String getLanguageCodeForSpellCheckLanguage () + { + + String lang = this.getProperty (Constants.SPELL_CHECK_LANGUAGE_PROPERTY_NAME); + + if (lang == null) + { + + lang = "en"; + + return lang; + + } + + if ((lang.equals ("English")) + || + (lang.equals ("US English")) + || + (lang.equals ("UK English")) + ) + { + + lang = "en"; + + } + + if (lang.equals ("Czech")) + { + + lang = "cs"; + + } + + if (lang.equals ("Dutch")) + { + + lang = "nl"; + + } + + if (lang.equals ("French")) + { + + lang = "fr"; + + } + + if (lang.equals ("German")) + { + + lang = "de"; + + } + + if (lang.equals ("Italian")) + { + + lang = "it"; + + } + + if (lang.equals ("Polish")) + { + + lang = "pl"; + + } + + if (lang.equals ("Russian")) + { + + lang = "ru"; + + } + + if (lang.equals ("Spanish")) + { + + lang = "es"; + + } + + return lang; + + } + + public void addTagToObject (Tag tag, + NamedObject n) + { + + Set objs = this.taggedObjects.get (tag); + + if (objs == null) + { + + objs = new HashSet<> (); + + this.taggedObjects.put (tag, + FXCollections.observableSet (objs)); + + } + + this.taggedObjects.get (tag).add (n); + + } + + public void removeTagFromObject (Tag tag, + NamedObject n) + { + + Set objs = this.taggedObjects.get (tag); + + if (objs != null) + { + + objs.remove (n); + + } + + } + +} diff --git a/src/main/java/com/quollwriter/data/ProjectInfo.java b/src/main/java/com/quollwriter/data/ProjectInfo.java new file mode 100644 index 00000000..3b9cb24a --- /dev/null +++ b/src/main/java/com/quollwriter/data/ProjectInfo.java @@ -0,0 +1,896 @@ +package com.quollwriter.data; + +import java.io.*; +import java.nio.file.*; +import java.nio.file.attribute.*; +import java.util.*; +import java.util.stream.*; + +import javafx.beans.property.*; +import javafx.collections.*; + +import org.dom4j.*; + +import com.quollwriter.events.*; +import com.quollwriter.*; +import com.quollwriter.data.editors.*; + +public class ProjectInfo extends NamedObject implements PropertyChangedListener +{ + + public static final String STATUS_PROP_NAME = "status"; + public static final String LAST_EDITED_PROP_NAME = "lastEdited"; + + public enum Statistic + { + + wordCount ("wordCount"), + chapterCount ("chapterCount"), + gunningFogIndex ("gunningFogIndex"), + fleschReadingEase ("fleschReadingEase"), + fleschKincaidGradeLevel ("fleschKincaidGradeLevel"), + editedWordCount ("editedWordCount"); + + private String type = null; + + Statistic (String type) + { + + this.type = type; + + } + + public String getType () + { + + return this.type; + + } + + } + + public static final String OBJECT_TYPE = "projectinfo"; + + private EditorEditor forEditor = null; + private ObjectProperty projectDirectoryProp = null; + private boolean noCredentials = false; + private String type = Project.NORMAL_PROJECT_TYPE; + private File icon = null; + private Path filesDirectory = null; + private ObservableMap statistics = null; + private boolean encrypted = false; + private Project project = null; + private String filePassword = null; + private boolean opening = false; + private ObjectProperty backupDirPathProp = null; + private ObservableSet backupPaths = null; + + private StringProperty statusProp = null; + private ObjectProperty lastEditedProp = null; + private IPropertyBinder binder = null; + + public ProjectInfo () + { + + super (OBJECT_TYPE); + + this.statistics = FXCollections.observableMap (new HashMap<> ()); + + final ProjectInfo _this = this; + this.binder = new PropertyBinder (); + + this.statusProp = new SimpleStringProperty (this, STATUS_PROP_NAME); + this.statusProp.addListener ((p, oldv, newv) -> + { + + _this.firePropertyChangedEvent (STATUS_PROP_NAME, + oldv, + newv); + + }); + + this.lastEditedProp = new SimpleObjectProperty<> (this, LAST_EDITED_PROP_NAME); + this.lastEditedProp.addListener ((p, oldv, newv) -> + { + + _this.firePropertyChangedEvent (LAST_EDITED_PROP_NAME, + oldv, + newv); + + }); + + this.backupDirPathProp = new SimpleObjectProperty<> (); + this.projectDirectoryProp = new SimpleObjectProperty<> (); + + this.backupPaths = FXCollections.observableSet (new TreeSet<> ((p1, p2) -> + { + + try + { + + FileTime l1 = null; + FileTime l2 = null; + + if (Files.exists (p1)) + { + + l1 = Files.getLastModifiedTime (p1); + + } + + if (Files.exists (p2)) + { + + l2 = Files.getLastModifiedTime (p2); + + } + + if ((l1 == null) + && + (l2 == null) + ) + { + + return 0; + + } + + int ret = 0; + + if (l1 == null) + { + + ret = 1; + + } + + if (l2 == null) + { + + ret = -1; + + } + + if ((l1 != null) + && + (l2 != null) + ) + { + + ret = l1.compareTo (l2); + + } + + return -1 * ret;//Files.getLastModifiedTime (p1).compareTo (Files.getLastModifiedTime (p2)); + + } catch (Exception e) { + + throw new RuntimeException (e); + + } + + })); + + this.binder.addChangeListener (this.backupDirPathProp, + (oldv, newv, pr) -> + { + + this.initBackupPaths (); + + }); + + } + + public ProjectInfo (Project from) + { + + this (); + + this.setId (from.getId ()); + + this.setProject (from); + + //this.project.addPropertyChangedListener (this); + + } + + public void dispose () + { + + this.binder.dispose (); + this.project = null; + this.projectDirectoryProp = null; + this.backupDirPathProp = null; + + if (this.backupPaths != null) + { + + this.backupPaths.clear (); + + } + + this.backupPaths = null; + + } + + private void initBackupPaths () + { + + this.backupPaths.clear (); + + try + { + + Path p = this.getBackupDirPath (); + + if ((p != null) + && + (Files.exists (p)) + ) + { + + try + { + + List ps = new ArrayList<> (); + + // Need this to auto close the underlying resources. + try (Stream ls = Files.list (p)) + { + + this.backupPaths.addAll (ls.filter (path -> + { + + try + { + + return Utils.isBackupFile (path); + + } catch (Exception e) { + + // Ignore this for now, producing too many errors that I can't do anything about. + /* + Environment.logError ("Unable to determine if path: " + path + " is a backup file.", + e); + */ + return false; + + } + + }) + .collect (Collectors.toList ())); + + } + + } catch (Exception e) { + + throw new GeneralException ("Unable to get backup paths from: " + p, + e); + + } + + } + + } catch (Exception e) { + + Environment.logError ("Unable to init backup paths", + e); + + } + + } + + public ObservableSet getBackupPaths () + { + + return this.backupPaths; + + } + + public void addBackupPath (Path p) + { + + com.quollwriter.ui.fx.UIUtils.runLater (() -> + { + + this.getBackupPaths ().add (p); + + }); + + } + + public void removeBackupPath (Path p) + { + + com.quollwriter.ui.fx.UIUtils.runLater (() -> + { + + this.getBackupPaths ().remove (p); + + }); + + } + + public synchronized void setOpening (boolean v) + { + + this.opening = v; + + } + + public synchronized boolean isOpening () + { + + if (this.opening) + { + + if (Environment.getProjectViewer (this.project) != null) + { + + this.opening = false; + + } + + } + + return this.opening; + + } + + @Override + public void fillToStringProperties (Map props) + { + + super.fillToStringProperties (props); + + this.addToStringProperties (props, + "type", + this.type); + this.addToStringProperties (props, + "status", + this.statusProp.getValue ()); + this.addToStringProperties (props, + "icon", + (this.icon != null ? this.icon.getPath () : "Not set")); + + this.addToStringProperties (props, + "projectDir", + (this.projectDirectoryProp.getValue () != null ? this.projectDirectoryProp.getValue ().toString () : "Not set")); + this.addToStringProperties (props, + "backupDir", + (this.backupDirPathProp.getValue () != null ? this.backupDirPathProp.getValue ().toString () : "Not set")); + this.addToStringProperties (props, + "filesDir", + (this.filesDirectory != null ? this.filesDirectory.toString () : "Not set")); + this.addToStringProperties (props, + "lastEdited", + this.lastEditedProp.getValue ()); + this.addToStringProperties (props, + "encrypted", + this.encrypted); + this.addToStringProperties (props, + "noCredentials", + this.noCredentials); + + if (this.forEditor != null) + { + + this.addToStringProperties (props, + "forEditor", + this.forEditor.getEmail ()); + + } + + this.addToStringProperties (props, + "statistics", + this.statistics); + + } + + public ObservableMap getStatistics () + { + + return this.statistics; + + } + + public void setStatistics (Map stats) + { + + this.statistics.clear (); + this.statistics.putAll (stats); + + } + + private void saveInfo () + { + + try + { + + Environment.updateProjectInfo (this); + + } catch (Exception e) { + + Environment.logError ("Unable to update project info for project: " + + this.project, + e); + + } + + } + + @Override + public void propertyChanged (PropertyChangedEvent ev) + { + + this.update (); + + try + { + + Environment.updateProjectInfo (this); + + } catch (Exception e) { + + Environment.logError ("Unable to update project info for project: " + + this.project, + e); + + } + + } + + public void setProject (Project p) + { + + if (!p.getId ().equals (this.getId ())) + { + + throw new IllegalArgumentException ("Project does not have same id as this project info."); + + } + + if (this.project != null) + { + + //this.project.removePropertyChangedListener (this); + + } + + this.project = p; + + this.type = p.getType (); + this.encrypted = p.isEncrypted (); + this.noCredentials = p.isNoCredentials (); + this.forEditor = p.getForEditor (); + this.filePassword = p.getFilePassword (); + this.setName (p.getName ()); + + //this.project.addPropertyChangedListener (this); + + this.binder.addChangeListener (this.project.nameProperty (), + (pr, oldv, newv) -> + { + + this.setName (newv); + this.saveInfo (); + + }); + + this.setProjectDirectory (this.project.getProjectDirectory ().toPath ()); + + this.binder.addChangeListener (this.project.projectDirectoryProperty (), + (pr, oldv, newv) -> + { + + this.setProjectDirectory (newv.toPath ()); + this.setFilesDirectory (this.project.getFilesDirectory ().toPath ()); + this.saveInfo (); + + }); + + this.setBackupDirPath (this.project.getBackupDirectory ().toPath ()); + + this.binder.addChangeListener (this.project.backupDirectoryProperty (), + (pr, oldv, newv) -> + { + + this.setBackupDirPath (newv.toPath ()); + + if (this.backupPaths != null) + { + + this.backupPaths.clear (); + + } + + try + { + + // Repopulate. + this.getBackupPaths (); + + } catch (Exception e) { + + Environment.logError ("Unable to init backup paths", + e); + + } + + this.saveInfo (); + + }); + + this.setLastEdited (this.project.getLastEdited ()); + + this.binder.addChangeListener (this.project.lastEditedProperty (), + (pr, oldv, newv) -> + { + + this.setLastEdited (newv); + this.saveInfo (); + + }); + + // TODO Need to deal with the RI. + + this.addStatistic (Statistic.chapterCount, + this.project.getChapterCount ()); + + this.binder.addChangeListener (this.project.chapterCountProperty (), + (pr, oldv, newv) -> + { + + this.addStatistic (Statistic.chapterCount, + newv); + this.saveInfo (); + + }); + + /* + It would be expensive to try and keep this up to date. + this.binder.addChangeListener (this.project.editedWordCountProperty (), + (pr, oldv, newv) -> + { + + this.addStatistic (Statistic.editedWordCount, + newv); + this.saveInfo (); + + }); +*/ + this.addStatistic (Statistic.editedWordCount, + this.project.getEditedWordCount ()); + ReadabilityIndices ri = this.project.getAllProjectReadabilityIndices (); + + this.addStatistic (Statistic.wordCount, + ri.getWordCount ()); + this.addStatistic (Statistic.gunningFogIndex, + ri.getGunningFogIndex ()); + this.addStatistic (Statistic.fleschReadingEase, + ri.getFleschReadingEase ()); + this.addStatistic (Statistic.fleschKincaidGradeLevel, + ri.getFleschKincaidGradeLevel ()); + + } + + public String getFilePassword () + { + + return this.filePassword; + + } + + public void setFilePassword (String p) + { + + this.filePassword = p; + + } + + private void update () + { + + this.setProjectDirectory (this.project.getProjectDirectory ().toPath ()); + this.setBackupDirPath (this.project.getBackupDirectory ().toPath ()); + this.setFilesDirectory (this.project.getFilesDirectory ().toPath ()); + this.setName (this.project.getName ()); + this.setLastEdited (this.project.getLastEdited ()); + + ReadabilityIndices ri = this.project.getAllProjectReadabilityIndices (); + + this.addStatistic (Statistic.chapterCount, + this.project.getChapterCount ()); + this.addStatistic (Statistic.wordCount, + ri.getWordCount ()); + + this.addStatistic (Statistic.gunningFogIndex, + ri.getGunningFogIndex ()); + this.addStatistic (Statistic.fleschReadingEase, + ri.getFleschReadingEase ()); + this.addStatistic (Statistic.fleschKincaidGradeLevel, + ri.getFleschKincaidGradeLevel ()); + this.addStatistic (Statistic.editedWordCount, + this.project.getEditedWordCount ()); + + } + + public void addStatistic (Statistic s, + Object value) + { + + this.statistics.put (s, + value); + + } + + private int getNumberStatistic (Statistic s) + { + + Object o = this.statistics.get (s); + + if (o == null) + { + + return 0; + + } + + if (!(o instanceof Number)) + { + + return 0; + + } + + return ((Number) o).intValue (); + + } + + public int getEditedWordCount () + { + + return this.getNumberStatistic (Statistic.editedWordCount); + + } + + public int getFleschKincaidGradeLevel () + { + + return this.getNumberStatistic (Statistic.fleschKincaidGradeLevel); + + } + + public int getFleschReadingEase () + { + + return this.getNumberStatistic (Statistic.fleschReadingEase); + + } + + public int getGunningFogIndex () + { + + return this.getNumberStatistic (Statistic.gunningFogIndex); + + } + + public int getChapterCount () + { + + return this.getNumberStatistic (Statistic.chapterCount); + + } + + public int getWordCount () + { + + return this.getNumberStatistic (Statistic.wordCount); + + } + + @Override + public Set getAllNamedChildObjects () + { + + return new TreeSet (); + + } + + @Override + public void getChanges (NamedObject old, + Element root) + { + + } + + public String getStatus () + { + + return this.statusProp.getValue (); + + } + + public void setStatus (String s) + { + + this.statusProp.unbind (); + + StringProperty p = UserProperties.getProjectStatus (s); + + this.statusProp.bind (p); + + } + + public StringProperty statusProperty () + { + + return this.statusProp; + + } + + public void setIcon (File ic) + { + + this.icon = ic; + + } + + public File getIcon () + { + + return this.icon; + + } + + public boolean isNoCredentials () + { + + return this.noCredentials; + + } + + public void setNoCredentials (boolean v) + { + + this.noCredentials = v; + + } + + public boolean isEncrypted () + { + + return this.encrypted; + + } + + public void setEncrypted (boolean v) + { + + this.encrypted = v; + + } + + public String getType () + { + + return this.type; + + } + + public void setType (String t) + { + + this.type = t; + + } + + public ObjectProperty lastEditedProperty () + { + + return this.lastEditedProp; + + } + + public void setLastEdited (Date d) + { + + this.lastEditedProp.setValue (d); + + } + + public Date getLastEdited () + { + + return this.lastEditedProp.getValue (); + + } + + public void setProjectDirectory (Path f) + { + + this.projectDirectoryProp.setValue (f); + + } + + public Path getProjectDirectory () + { + + return this.projectDirectoryProp.getValue (); + + } + + public ObjectProperty backupDirPathProperty () + { + + return this.backupDirPathProp; + + } + + public Path getBackupDirPath () + { + + return this.backupDirPathProp.getValue (); + + } + + public void setBackupDirPath (Path f) + { + + this.backupDirPathProp.setValue (f); + + this.initBackupPaths (); + + } + + public Path getFilesDirectory () + { + + return this.filesDirectory; + + } + + public void setFilesDirectory (Path f) + { + + this.filesDirectory = f; + + } + + public void setForEditor (EditorEditor ed) + { + + this.forEditor = ed; + + } + + public EditorEditor getForEditor () + { + + return this.forEditor; + + } + + public boolean isEditorProject () + { + + return this.type.equals (Project.EDITOR_PROJECT_TYPE); + + } + + public boolean isWarmupsProject () + { + + return this.type.equals (Project.WARMUPS_PROJECT_TYPE); + + } + + public boolean isNormalProject () + { + + return this.type.equals (Project.NORMAL_PROJECT_TYPE); + + } + +} diff --git a/src/com/quollwriter/data/ProjectVersion.java b/src/main/java/com/quollwriter/data/ProjectVersion.java similarity index 81% rename from src/com/quollwriter/data/ProjectVersion.java rename to src/main/java/com/quollwriter/data/ProjectVersion.java index 6593656f..8327a5f0 100644 --- a/src/com/quollwriter/data/ProjectVersion.java +++ b/src/main/java/com/quollwriter/data/ProjectVersion.java @@ -2,55 +2,57 @@ import java.util.*; -import org.jdom.*; +import org.dom4j.*; public class ProjectVersion extends NamedObject { - + public static final String OBJECT_TYPE = "projectversion"; - + private Date due = null; - + public ProjectVersion () { - + super (ProjectVersion.OBJECT_TYPE); - + } - + public ProjectVersion (String name) { - + super (ProjectVersion.OBJECT_TYPE, name); - + } - + public Date getDueDate () { - + return this.due; - + } - + public void setDueDate (Date d) { - + this.due = d; - + } - + + @Override public Set getAllNamedChildObjects () { - + return null; - + } - + + @Override public void getChanges (NamedObject old, Element root) { - + } - -} \ No newline at end of file + +} diff --git a/src/main/java/com/quollwriter/data/Prompt.java b/src/main/java/com/quollwriter/data/Prompt.java new file mode 100644 index 00000000..5bf1bdfb --- /dev/null +++ b/src/main/java/com/quollwriter/data/Prompt.java @@ -0,0 +1,211 @@ +package com.quollwriter.data; + +import org.dom4j.*; +import org.dom4j.tree.*; + +import com.quollwriter.*; + +public class Prompt +{ + + public static final String USER_PROMPT_ID_PREFIX = "user-"; + + public class XMLConstants + { + + public static final String root = "prompt"; + public static final String id = "id"; + public static final String text = "text"; + public static final String author = "author"; + public static final String url = "url"; + public static final String storyName = "storyName"; + + } + + private String id = null; + private String text = null; + private String author = null; + private String url = null; + private String storyName = null; + + public Prompt(String text) + { + + this.text = text; + this.id = Prompt.USER_PROMPT_ID_PREFIX + System.currentTimeMillis (); + + } + + public Prompt(String id, + String author, + String storyName, + String url, + String text) + { + + this.id = id; + this.author = author; + this.url = url; + this.text = text; + this.storyName = storyName; + + } + + public Prompt(Element root) + throws GeneralException + { + + this.id = root.attributeValue (XMLConstants.id); + + this.text = root.element (XMLConstants.text).getTextTrim (); + + this.author = DOM4JUtils.childElementContent (root, + XMLConstants.author, + false, + null); + + this.storyName = DOM4JUtils.childElementContent (root, + XMLConstants.storyName, + false, + null); + + this.url = DOM4JUtils.childElementContent (root, + XMLConstants.url, + false, + null); + + } + + @Override + public String toString () + { + + return "prompt(id: " + this.id + ", author: " + author + ", " + url + ", storyName: " + this.storyName + ")"; + + } + + public boolean isUserPrompt () + { + + return Prompt.isUserPrompt (this.id); + + } + + public static boolean isUserPrompt (String id) + { + + return id.startsWith (Prompt.USER_PROMPT_ID_PREFIX); + + } + + public Element getAsElement () + { + + Element root = new DefaultElement (XMLConstants.root); + + if (this.id != null) + { + + root.addAttribute (XMLConstants.id, + this.id); + + } + + if (this.author != null) + { + + Element auth = new DefaultElement (XMLConstants.author); + root.add (auth); + auth.add (new DefaultCDATA (this.author)); + + } + + if (this.storyName != null) + { + + Element st = new DefaultElement (XMLConstants.storyName); + root.add (st); + st.add (new DefaultCDATA (this.storyName)); + + } + + if (this.url != null) + { + + Element url = new DefaultElement (XMLConstants.url); + root.add (url); + url.add (new DefaultCDATA (this.url)); + + } + + Element text = new DefaultElement (XMLConstants.text); + root.add (text); + text.add (new DefaultCDATA (this.text)); + + return root; + + } + + public void setAuthor (String a) + { + + this.author = a; + + } + + public void setURL (String u) + { + + this.url = u; + + } + + public void setStoryName (String n) + { + + this.storyName = n; + + } + + public String getURL () + { + + return this.url; + + } + + public String getAuthor () + { + + return this.author; + + } + + public String getStoryName () + { + + return this.storyName; + + } + + public void setText (String t) + { + + this.text = t; + + } + + public String getText () + { + + return this.text; + + } + + public String getId () + { + + return this.id; + + } +} diff --git a/src/main/java/com/quollwriter/data/PromptWebsite.java b/src/main/java/com/quollwriter/data/PromptWebsite.java new file mode 100644 index 00000000..ae5cd7b1 --- /dev/null +++ b/src/main/java/com/quollwriter/data/PromptWebsite.java @@ -0,0 +1,58 @@ +package com.quollwriter.data; + +import org.dom4j.*; + +import com.quollwriter.*; + +public class PromptWebsite +{ + + public class XMLConstants + { + + public static final String root = "site"; + public static final String count = "count"; + public static final String name = "name"; + public static final String url = "url"; + + } + + private String count = null; + private String name = null; + private String url = null; + + public PromptWebsite (Element root) + throws GeneralException + { + + this.count = DOM4JUtils.attributeValue (root, + XMLConstants.count); + this.name = DOM4JUtils.attributeValue (root, + XMLConstants.name); + this.url = DOM4JUtils.childElementContent (root, + XMLConstants.url); + + } + + public String getURL () + { + + return this.url; + + } + + public String getCount () + { + + return this.count; + + } + + public String getName () + { + + return this.name; + + } + +} diff --git a/src/main/java/com/quollwriter/data/Prompts.java b/src/main/java/com/quollwriter/data/Prompts.java new file mode 100644 index 00000000..ad2026ab --- /dev/null +++ b/src/main/java/com/quollwriter/data/Prompts.java @@ -0,0 +1,407 @@ +package com.quollwriter.data; + +import java.io.*; +import java.nio.file.*; + +import java.util.*; + +import com.quollwriter.*; + +import org.dom4j.*; + + +public class Prompts +{ + + private static Map excludes = new HashMap<> (); + private static List promptIds = new ArrayList<> (); + private static int pos = 0; + + public class XMLConstants + { + + public static final String root = "prompts"; + + } + + private static Path getExcludesFilePath () + { + + return Environment.getUserPath (Constants.PROMPTS_EXCLUDE_FILE); + + } + + private static Path getUserPromptsDirPath () + { + + return Environment.getUserPath (Constants.USER_PROMPTS_DIR); + + } + + private static Path getUserPromptFilePath (Prompt p) + { + + return Prompts.getUserPromptFilePath (p.getId ()); + + } + + private static Path getUserPromptFilePath (String id) + { + + return Prompts.getUserPromptsDirPath ().resolve (id + ".txt"); + + } + + public static void init () + throws Exception + { + + // Get the exclude list. + // TODO Change to use paths. + File f = Prompts.getExcludesFilePath ().toFile (); + + if (f.exists ()) + { + + BufferedReader b = new BufferedReader (new FileReader (f)); + + try + { + + String l = b.readLine (); + + while (l != null) + { + + Prompts.excludes.put (l.trim (), + ""); + + l = b.readLine (); + + } + + } finally + { + + b.close (); + + } + + } + + // Get the default prompts file. + BufferedReader b = new BufferedReader (new InputStreamReader (Utils.getResourceStream (Constants.DEFAULT_PROMPT_IDS_FILE))); + + try + { + + String l = null; + + while ((l = b.readLine ()) != null) + { + + String id = l.trim (); + + if (Prompts.excludes.containsKey (id)) + { + + continue; + + } + + Prompts.promptIds.add (id); + + } + + } finally + { + + b.close (); + + } + + // Load the user prompts. + Path p = Prompts.getUserPromptsDirPath (); + + if ((Files.exists (p)) + && + (Files.isDirectory (p)) + ) + { + + // TODO Use a walk/stream. + File[] files = p.toFile ().listFiles (); + + if (files != null) + { + + for (int i = 0; i < files.length; i++) + { + + if ((files[i].isFile ()) && + (files[i].getName ().endsWith (".txt"))) + { + + String id = files[i].getName ().substring (0, + files[i].getName ().length () - 4); + + if (Prompts.excludes.containsKey (id)) + { + + continue; + + } + + // This is one, use the name as the id. + Prompts.promptIds.add (id); + + } + + } + + } + + } + + } + + public static void shuffle () + { + + Collections.shuffle (Prompts.promptIds); + + } + + public static Prompt getPromptById (String id) + throws Exception + { + + if (id == null) + { + + return null; + + } + + Element root = null; + + if (Prompt.isUserPrompt (id)) + { + + Path f = Prompts.getUserPromptFilePath (id); + + root = DOM4JUtils.fileAsElement (f); + + } else + { + + String xml = Utils.getResourceFileAsString (Constants.PROMPTS_DIR + id + ".txt"); + + if (xml == null) + { + + Environment.logError ("Unable to get prompt from resource file: " + + Constants.PROMPTS_DIR + id + ".txt"); + + return null; + + } + + root = DOM4JUtils.stringAsElement (xml); + + } + + Prompt p = new Prompt (root); + + return p; + + } + + public static Prompt addUserPrompt (String text) + throws Exception + { + + // Add a new one. + Prompt p = new Prompt (text); + + // Get the prompts file. + Path f = Prompts.getUserPromptFilePath (p); + + Files.createDirectories (f.getParent ()); + + if (Files.exists (f)) + { + + throw new GeneralException ("A user prompt with id: " + + p.getId () + + " already exists at: " + + f); + + } + + DOM4JUtils.writeToFile (p.getAsElement (), + f, + true); + + return p; + + } + + public static Prompt previous () + { + + try + { + + Prompts.pos--; + + if (Prompts.pos < 0) + { + + Prompts.pos = Prompts.promptIds.size () - 1; + + } + + return Prompts.current (); + + } catch (Exception e) + { + + return null; + + } + + } + + public static Prompt next () + { + + try + { + + Prompts.pos++; + + if (Prompts.pos >= Prompts.promptIds.size ()) + { + + Prompts.pos = 0; + + } + + return Prompts.current (); + + } catch (Exception e) + { + Environment.logError ("Unable to get prompt: " + Prompts.getCurrentId (), + e); + + return null; + + } + + } + + public static Prompt current () + throws Exception + { + + String id = Prompts.getCurrentId (); + + return Prompts.getPromptById (id); + + } + + public static String getCurrentId () + { + + return Prompts.promptIds.get (Prompts.pos); + + } + + public static void excludeCurrent () + { + + Prompts.excludes.put (Prompts.getCurrentId (), + ""); + + Prompts.promptIds.remove (Prompts.getCurrentId ()); + + // Write out the exclude list. + // TODO Change to use a path. + File f = Prompts.getExcludesFilePath ().toFile (); + + try + { + + PrintWriter pw = new PrintWriter (new FileWriter (f)); + + Iterator iter = Prompts.excludes.keySet ().iterator (); + + while (iter.hasNext ()) + { + + String id = (String) iter.next (); + + pw.println (id); + + } + + pw.flush (); + pw.close (); + + } catch (Exception e) + { + + Environment.logError ("Unable to save prompts exclude file to: " + + f, + e); + + } + + } + + public static List getPromptWebsites () + { + + List ws = new ArrayList<> (); + + try + { + + String xml = Utils.getResourceFileAsString (Constants.PROMPT_WEBSITES_FILE); + + Element root = DOM4JUtils.stringAsElement (xml); + + for (Element el : root.elements (PromptWebsite.XMLConstants.root)) + { + + try + { + + PromptWebsite w = new PromptWebsite (el); + + ws.add (w); + + } catch (Exception e) + { + + Environment.logError ("Unable to load prompt website: " + + DOM4JUtils.getPath (el), + e); + + } + + } + + } catch (Exception e) + { + + Environment.logError ("Unable to load prompt websites", + e); + + } + + return ws; + + } +} diff --git a/src/main/java/com/quollwriter/data/PropertyBinder.java b/src/main/java/com/quollwriter/data/PropertyBinder.java new file mode 100644 index 00000000..7f985f5d --- /dev/null +++ b/src/main/java/com/quollwriter/data/PropertyBinder.java @@ -0,0 +1,303 @@ +package com.quollwriter.data; + +import java.util.*; + +import javafx.scene.*; +import javafx.beans.value.*; +import javafx.collections.*; + +public class PropertyBinder implements IPropertyBinder +{ + + private Map> changeListeners = new HashMap<> (); + + private List handles = new ArrayList<> (); + + public PropertyBinder () + { + + } + + @Override + public IPropertyBinder getBinder () + { + + return this; + + } + + @Override + public ListenerHandle addChangeListener (ObservableValue value, + ChangeListener listener) + { + + if (value == null) + { + + return null; + + } + + ChangeListenerHandle h = new ChangeListenerHandle<> (this, + value, + listener); + + this.handles.add (h); + + return h; + + } + + @Override + public ListenerHandle addMapChangeListener (ObservableMap map, + MapChangeListener listener) + { + + if (map == null) + { + + return null; + + } + + MapChangeListenerHandle h = new MapChangeListenerHandle<> (this, + map, + listener); + + this.handles.add (h); + + return h; + + } + + @Override + public ListenerHandle addSetChangeListener (ObservableSet set, + SetChangeListener listener) + { + + if (set == null) + { + + return null; + + } + + SetChangeListenerHandle h = new SetChangeListenerHandle<> (this, + set, + listener); + + this.handles.add (h); + + return h; + + } + + @Override + public IPropertyBinder.ListenerHandle addListChangeListener (ObservableList list, + ListChangeListener listener) + { + + if (list == null) + { + + return null; + + } + + ListChangeListenerHandle h = new ListChangeListenerHandle (this, + list, + listener); + + this.handles.add (h); + + return h; + + } + + @Override + public void dispose () + { + + new ArrayList<> (this.handles).stream () + .forEach (h -> h.dispose ()); + + for (ObservableValue v : this.changeListeners.keySet ()) + { + + for (ChangeListener l : this.changeListeners.get (v)) + { + + v.removeListener (l); + + } + + } + + this.changeListeners.clear (); + + } + + void removeHandle (ListenerHandle h) + { + + this.handles.remove (h); + + } + + public abstract class AbstractListenerHandle implements IPropertyBinder.ListenerHandle + { + + protected PropertyBinder binder = null; + + public AbstractListenerHandle (PropertyBinder binder) + { + + this.binder = binder; + + } + + public IPropertyBinder getBinder () + { + + return this.binder; + + } + + public void dispose () + { + + this.binder.removeHandle (this); + + } + + } + + public class SetChangeListenerHandle extends AbstractListenerHandle + { + + private ObservableSet set = null; + private SetChangeListener listener = null; + + public SetChangeListenerHandle (PropertyBinder binder, + ObservableSet set, + SetChangeListener listener) + { + + super (binder); + + this.set = set; + this.listener = listener; + + this.set.addListener (this.listener); + + } + + @Override + public void dispose () + { + + this.set.removeListener (this.listener); + + super.dispose (); + + } + + } + + public class MapChangeListenerHandle extends AbstractListenerHandle + { + + private ObservableMap map = null; + private MapChangeListener listener = null; + + public MapChangeListenerHandle (PropertyBinder binder, + ObservableMap map, + MapChangeListener listener) + { + + super (binder); + + this.map = map; + this.listener = listener; + + this.map.addListener (this.listener); + + } + + @Override + public void dispose () + { + + this.map.removeListener (this.listener); + + super.dispose (); + + } + + } + + public class ListChangeListenerHandle extends AbstractListenerHandle + { + + private ObservableList list = null; + private ListChangeListener listener = null; + + public ListChangeListenerHandle (PropertyBinder binder, + ObservableList list, + ListChangeListener listener) + { + + super (binder); + + this.list = list; + this.listener = listener; + + this.list.addListener (this.listener); + + } + + @Override + public void dispose () + { + + this.list.removeListener (this.listener); + + super.dispose (); + + } + + } + + public class ChangeListenerHandle extends AbstractListenerHandle + { + + private ObservableValue list = null; + private ChangeListener listener = null; + + public ChangeListenerHandle (PropertyBinder binder, + ObservableValue list, + ChangeListener listener) + { + + super (binder); + + this.list = list; + this.listener = listener; + + this.list.addListener (this.listener); + + } + + @Override + public void dispose () + { + + this.list.removeListener (this.listener); + + super.dispose (); + + } + + } + +} diff --git a/src/com/quollwriter/data/QCharacter.java b/src/main/java/com/quollwriter/data/QCharacter.java similarity index 91% rename from src/com/quollwriter/data/QCharacter.java rename to src/main/java/com/quollwriter/data/QCharacter.java index d67bbeb5..e61a91b7 100644 --- a/src/com/quollwriter/data/QCharacter.java +++ b/src/main/java/com/quollwriter/data/QCharacter.java @@ -2,7 +2,7 @@ import java.util.*; -import org.jdom.*; +import org.dom4j.*; public class QCharacter extends LegacyAsset @@ -17,6 +17,7 @@ public QCharacter() } + @Override public void getChanges (NamedObject old, Element root) { diff --git a/src/com/quollwriter/data/QObject.java b/src/main/java/com/quollwriter/data/QObject.java similarity index 77% rename from src/com/quollwriter/data/QObject.java rename to src/main/java/com/quollwriter/data/QObject.java index d02986b4..be71799c 100644 --- a/src/com/quollwriter/data/QObject.java +++ b/src/main/java/com/quollwriter/data/QObject.java @@ -2,7 +2,9 @@ import java.util.*; -import org.jdom.*; +import org.dom4j.*; + +import com.quollwriter.*; public class QObject extends LegacyAsset { @@ -12,7 +14,7 @@ public class QObject extends LegacyAsset public static final String OBJECT_TYPE = "object"; public static final String TYPE = "type"; - + private String type = null; public QObject () @@ -33,41 +35,52 @@ public void setType (String t) { String oldType = this.type; - + UserConfigurableObjectField f = this.getLegacyField (TYPE_LEGACY_FIELD_ID); - + if (f == null) { - - UserConfigurableObjectTypeField type = this.getLegacyTypeField (TYPE_LEGACY_FIELD_ID); - + + UserConfigurableObjectTypeField type = this.getLegacyTypeField (TYPE_LEGACY_FIELD_ID); + // May not have the field. if (type == null) { - + return; - + } - + f = new UserConfigurableObjectField (type); - + this.addField (f); - + } - - Set vals = new LinkedHashSet (); + + Set vals = new LinkedHashSet<> (); vals.add (t); - - f.setValue (vals); - + + try + { + + f.setValue (JSONEncoder.encode (vals)); + + } catch (Exception e) { + + Environment.logError ("Unable to encode: " + vals, + e); + + } + this.type = t; this.firePropertyChangedEvent (TYPE, oldType, - this.type); - + this.type); + } + @Override public void getChanges (NamedObject old, Element root) { diff --git a/src/main/java/com/quollwriter/data/ReadabilityIndices.java b/src/main/java/com/quollwriter/data/ReadabilityIndices.java new file mode 100644 index 00000000..02507df9 --- /dev/null +++ b/src/main/java/com/quollwriter/data/ReadabilityIndices.java @@ -0,0 +1,234 @@ +package com.quollwriter.data; + +import java.text.*; + +import java.util.*; + +import javafx.beans.property.*; + +import com.quollwriter.*; + +import com.quollwriter.text.*; + +import com.quollwriter.ui.fx.UIUtils; + +public class ReadabilityIndices +{ + + public float syllableCount = 0; + public float wordCount = 0; + public float sentenceCount = 0; + public float threeSyllableWordCount = 0; + private float fkgl = 0; + private float fre = 0; + private float gfi = 0; + private FloatProperty fkglProp = new SimpleFloatProperty (this.fkgl); + private FloatProperty freProp = new SimpleFloatProperty (this.fre); + private FloatProperty gfiProp = new SimpleFloatProperty (this.gfi); + + public ReadabilityIndices () + { + + } + + ReadabilityIndices (float wordCount, + float sentenceCount, + float threeSyllableWordCount, + float syllableCount) + { + + this.wordCount = wordCount; + this.sentenceCount = sentenceCount; + this.threeSyllableWordCount = threeSyllableWordCount; + this.syllableCount = syllableCount; + this.update (); + + } + + public void add (ReadabilityIndices ri) + { + + this.sentenceCount += ri.sentenceCount; + this.wordCount += ri.wordCount; + this.syllableCount += ri.syllableCount; + this.threeSyllableWordCount += ri.threeSyllableWordCount; + + this.update (); + + } + + public void add (String str) + { + + if ((str != null) + && + (str.length () > 0) + ) + { + + TextIterator ti = new TextIterator (str); + this.wordCount += ti.getWordCount (); + this.syllableCount += ti.getSyllableCount (); + this.threeSyllableWordCount += ti.getThreeSyllableWordCount (); + this.sentenceCount += ti.getSentenceCount (); + + } + + this.update (); + +/* + SentenceIterator si = new SentenceIterator (str); + + String s = si.next (); + + while (s != null) + { + + this.sentenceCount++; + + List words = null; + + words = TextUtilities.getAsWords (s); + + words = TextUtilities.stripPunctuation (words); + + this.wordCount += words.size (); + + for (String w : words) + { + + int cc = TextUtilities.getSyllableCountForWord (w); + + if (cc > 2) + { + + this.threeSyllableWordCount++; + + } + + this.syllableCount += cc; + + } + + s = si.next (); + + } + + // Turn off the cache, it may have used quite a bit of memory. + // Shouldn't be needed anymore. + //Environment.setSynonymProviderUseCache (true); + */ + } + + public void updateFrom (ReadabilityIndices ri) + { + + this.wordCount = ri.getWordCount (); + this.sentenceCount = ri.sentenceCount; + this.syllableCount = ri.syllableCount; + this.threeSyllableWordCount = ri.threeSyllableWordCount; + + this.update (); + + } + + private void update () + { + + if (this.wordCount <= 0) + { + + this.fkgl = 0; + this.fre = 0; + this.gfi = 0; + + } else { + + this.fkgl = (0.39f * (this.wordCount / this.sentenceCount)) + (11.8f * (this.syllableCount / this.wordCount)) - 15.59f; + this.fre = (206.835f - (1.015f * (this.wordCount / this.sentenceCount)) - (84.6f * (this.syllableCount / this.wordCount))); + this.gfi = (0.4f * ((this.wordCount / this.sentenceCount) + ((this.threeSyllableWordCount / this.wordCount) * 100f))) - 0.5f; + + } + + UIUtils.runLater (() -> + { + + this.fkglProp.setValue (this.fkgl); + this.freProp.setValue (this.fre); + this.gfiProp.setValue (this.gfi); + + }); + + } + + public int getSentenceCount () + { + + return (int) this.sentenceCount; + + } + + public int getWordCount () + { + + return (int) this.wordCount; + + } + + public int getSyllableCount () + { + + return (int) this.syllableCount; + + } + + public int getThreeSyllableWordCount () + { + + return (int) this.threeSyllableWordCount; + + } + + public FloatProperty fleschKindcaidGradeLevelProperty () + { + + return this.fkglProp; + + } + + public FloatProperty fleschReadingEaseProperty () + { + + return this.freProp; + + } + + public FloatProperty gunningFogIndexProperty () + { + + return this.gfiProp; + + } + + public float getFleschKincaidGradeLevel () + { + + return this.fkgl; + + } + + public float getFleschReadingEase () + { + + return this.fre; + + } + + public float getGunningFogIndex () + { + + return this.gfi; + + } + +} diff --git a/src/com/quollwriter/data/ResearchItem.java b/src/main/java/com/quollwriter/data/ResearchItem.java similarity index 83% rename from src/com/quollwriter/data/ResearchItem.java rename to src/main/java/com/quollwriter/data/ResearchItem.java index 8a854608..b46b7b8a 100644 --- a/src/com/quollwriter/data/ResearchItem.java +++ b/src/main/java/com/quollwriter/data/ResearchItem.java @@ -1,6 +1,6 @@ package com.quollwriter.data; -import org.jdom.*; +import org.dom4j.*; public class ResearchItem extends LegacyAsset @@ -11,7 +11,7 @@ public class ResearchItem extends LegacyAsset public static final String OBJECT_TYPE = "researchitem"; public static final String URL = "url"; - + private String url = null; public ResearchItem () @@ -32,37 +32,38 @@ public void setUrl (String url) { String oldUrl = this.url; - + UserConfigurableObjectField f = this.getLegacyField (WEB_PAGE_LEGACY_FIELD_ID); - + if (f == null) { - - UserConfigurableObjectTypeField type = this.getLegacyTypeField (WEB_PAGE_LEGACY_FIELD_ID); - + + UserConfigurableObjectTypeField type = this.getLegacyTypeField (WEB_PAGE_LEGACY_FIELD_ID); + if (type == null) { - + return; - + } - + f = new UserConfigurableObjectField (type); - + this.addField (f); - + } - + f.setValue (url); - + this.url = url; this.firePropertyChangedEvent (URL, oldUrl, - this.url); - + this.url); + } + @Override public void getChanges (NamedObject old, Element root) { diff --git a/src/main/java/com/quollwriter/data/Scene.java b/src/main/java/com/quollwriter/data/Scene.java new file mode 100644 index 00000000..0d6895dc --- /dev/null +++ b/src/main/java/com/quollwriter/data/Scene.java @@ -0,0 +1,382 @@ +package com.quollwriter.data; + +import java.text.*; + +import java.util.*; +import java.util.stream.*; + +import javafx.collections.*; +import javafx.beans.property.*; + +import org.reactfx.*; + +import com.quollwriter.data.comparators.*; + +import com.quollwriter.*; +import com.quollwriter.text.*; + +public class Scene extends ChapterItem +{ + + public static final String OBJECT_TYPE = "scene"; + + private ObservableSet outlineItems = FXCollections.observableSet (new TreeSet<> (new ChapterItemSorter ())); + private EventSource> outlineItemsEventSource = new EventSource<> (); + private EventSource outlineItemsPositionEventSource = new EventSource<> (); + + public Scene() + { + + super (Scene.OBJECT_TYPE); + + this._init (); + + } + + public Scene(int at, + Chapter c) + { + + super (Scene.OBJECT_TYPE, + at, + c); + + this._init (); + + } + + private void _init () + { + + this.outlineItems.addListener ((SetChangeListener) ev -> + { + + if (ev.wasAdded ()) + { + + OutlineItem it = ev.getElementAdded (); + + this.outlineItemsEventSource.push (new CollectionEvent (this.outlineItems, + it, + CollectionEvent.Type.add)); + + it.addChangeListener (it.positionProperty (), + (pr, oldv, newv) -> + { + + this.outlineItemsPositionEventSource.push (new ChapterItem.ChapterItemEvent (it, + ChapterItem.ChapterItemEvent.Type.positionchange, + pr, + oldv.intValue (), + newv.intValue ())); + + }); + + } + + if (ev.wasRemoved ()) + { + + OutlineItem it = ev.getElementRemoved (); + + it.dispose (); + + this.outlineItemsEventSource.push (new CollectionEvent (this.outlineItems, + it, + CollectionEvent.Type.remove)); + + } + + }); + + } + + public EventStream outlineItemsPositionEvents () + { + + return this.outlineItemsPositionEventSource; + + } + + public EventStream> outlineItemsEvents () + { + + return this.outlineItemsEventSource; + + } + + @Override + public void fillToStringProperties (Map props) + { + + super.fillToStringProperties (props); + + this.addToStringProperties (props, + "outlineItems", + this.outlineItems.size ()); + + } + + public Set getChapterItemsWithPositionGreaterThan (int pos) + { + + Set items = new TreeSet<> (new ChapterItemSorter ()); + + for (OutlineItem it : this.outlineItems) + { + + if (it.getPosition () > pos) + { + + items.add (it); + + } + + } + + return items; + + } + + @Override + public void getChanges (NamedObject old, + org.dom4j.Element root) + { + + } + + public List getOutlineItemsAt (int pos) + { + + List its = new ArrayList<> (); + + for (OutlineItem it : this.getOutlineItems ()) + { + + if (it.getPosition () == pos) + { + + its.add (it); + + } + + } + + return its; + + } + + public OutlineItem getOutlineItemAt (int pos) + { + + for (OutlineItem it : this.outlineItems) + { + + if (it.getPosition () == pos) + { + + return it; + + } + + } + + return null; + + } + + public DataObject getObjectForReference (ObjectReference r) + { + + DataObject d = super.getObjectForReference (r); + + if (d != null) + { + + return d; + + } + + for (OutlineItem i : this.outlineItems) + { + + d = i.getObjectForReference (r); + + if (d != null) + { + + return d; + + } + + } + + return null; + + } + + public ObservableSet getOutlineItems () + { + + return this.outlineItems; +/* + TreeSet t = new TreeSet (new ChapterItemSorter ()); + + t.addAll (this.outlineItems); + + return t; +*/ + //return new TreeSet (this.outlineItems); + + } + + public void setChapter (Chapter c) + { + + // Handle our outline items first. + for (OutlineItem it : this.outlineItems) + { + + it.setChapter (c); + + } + + super.setChapter (c); + + this.setParent (c); + + } + + public void removeOutlineItem (OutlineItem i) + { + + this.outlineItems.remove (i); + + i.dispose (); + + } + + public void addOutlineItem (OutlineItem i) + { + + if (!i.getChapter ().equals (this.getChapter ())) + { + + throw new IllegalStateException ("Chapters differ."); + + } + + for (OutlineItem _i : this.outlineItems) + { + + if (_i.equals (i)) + { + + return; + + } + + } + + Scene s = i.getScene (); + + if (s != null) + { + + if (!s.equals (this)) + { + + s.removeOutlineItem (i); + + } + + } else + { + + this.getChapter ().removeOutlineItem (i); + + } + + i.setScene (this); + + this.outlineItems.add (i); + + } + + public void setDescription (StringWithMarkup d) + { + + // Legacy data check, can't control the order of calls that hibernate makes so ensure that it + // doesn't overwrite the description. + if ((this.getName () != null) && + (d == null)) + { + + return; + + } + + if (d != null) + { + + String t = d.getText (); + + // Take the first sentence and use that as the "name". + Paragraph p = new Paragraph (t, + 0); + + if (p.getSentenceCount () > 0) + { + + this.setName (p.getFirstSentence ().getText ()); + + } + + } + + super.setDescription (d); + + } + + public void shiftPositionBy (int p) + { + + super.shiftPositionBy (p); + + for (OutlineItem i : this.getOutlineItems ()) + { + + i.shiftPositionBy (p); + + } + + } + + public int getLength () + { + + Scene next = this.getChapter ().getNextScene (this); + + if (next != this) + { + + return next.getPosition () - this.getPosition (); + + } + + return -1; + + } + + @Override + public void dispose () + { + + this.outlineItems.stream () + .forEach (o -> o.dispose ()); + + super.dispose (); + + } + +} diff --git a/src/main/java/com/quollwriter/data/SelectUserConfigurableObjectTypeField.java b/src/main/java/com/quollwriter/data/SelectUserConfigurableObjectTypeField.java new file mode 100644 index 00000000..ff63ec4b --- /dev/null +++ b/src/main/java/com/quollwriter/data/SelectUserConfigurableObjectTypeField.java @@ -0,0 +1,117 @@ +package com.quollwriter.data; + +import java.util.Map; +import java.util.Set; +import java.util.LinkedHashSet; +import java.util.StringTokenizer; +import java.util.List; +import java.util.ArrayList; +import java.util.Collection; + +import java.math.*; + +import com.quollwriter.ui.fx.*; +import com.quollwriter.ui.fx.viewers.*; +import com.quollwriter.ui.fx.userobjects.*; + +public class SelectUserConfigurableObjectTypeField extends UserConfigurableObjectTypeField +{ + + public static final String ITEMS = "items"; + public static final String ALLOWMULTI = "allowmulti"; + + public SelectUserConfigurableObjectTypeField () + { + + super (Type.select); + + } + + @Override + public boolean isSortable () + { + + return true; + + } + + @Override + public com.quollwriter.ui.userobjects.UserConfigurableObjectFieldViewEditHandler getViewEditHandler (UserConfigurableObject obj, + UserConfigurableObjectField field, + com.quollwriter.ui.AbstractProjectViewer viewer) + { + + return new com.quollwriter.ui.userobjects.SelectUserConfigurableObjectFieldViewEditHandler (this, + obj, + field, + viewer); + + } + + @Override + public UserConfigurableObjectFieldViewEditHandler getViewEditHandler2 (UserConfigurableObject obj, + UserConfigurableObjectField field, + IPropertyBinder binder, + AbstractProjectViewer viewer) + { + + return new SelectUserConfigurableObjectFieldViewEditHandler (this, + obj, + field, + viewer); + + } + + @Override + public com.quollwriter.ui.userobjects.UserConfigurableObjectTypeFieldConfigHandler getConfigHandler () + { + + return new com.quollwriter.ui.userobjects.SelectUserConfigurableObjectTypeFieldConfigHandler (this); + + } + + @Override + public UserConfigurableObjectTypeFieldConfigHandler getConfigHandler2 () + { + + return new SelectUserConfigurableObjectTypeFieldConfigHandler (this); + + } + + public void setItems (Collection its) + { + + this.setDefinitionValue (ITEMS, new ArrayList<> (its)); + + } + + public Collection getItems () + { + + return (Collection) this.getDefinitionValue (ITEMS); + + } + + @Override + public boolean isSearchable () + { + + return true; + + } + + public boolean isAllowMulti () + { + + return this.getBooleanDefinitionValue (ALLOWMULTI); + + } + + public void setAllowMulti (boolean v) + { + + this.setDefinitionValue (ALLOWMULTI, v); + + } + +} diff --git a/src/com/quollwriter/data/SelectableDataObject.java b/src/main/java/com/quollwriter/data/SelectableDataObject.java similarity index 100% rename from src/com/quollwriter/data/SelectableDataObject.java rename to src/main/java/com/quollwriter/data/SelectableDataObject.java diff --git a/src/com/quollwriter/data/Session.java b/src/main/java/com/quollwriter/data/Session.java similarity index 100% rename from src/com/quollwriter/data/Session.java rename to src/main/java/com/quollwriter/data/Session.java diff --git a/src/com/quollwriter/data/Tag.java b/src/main/java/com/quollwriter/data/Tag.java similarity index 84% rename from src/com/quollwriter/data/Tag.java rename to src/main/java/com/quollwriter/data/Tag.java index 062190ae..4795e4c9 100644 --- a/src/com/quollwriter/data/Tag.java +++ b/src/main/java/com/quollwriter/data/Tag.java @@ -2,33 +2,33 @@ import java.util.*; -import org.jdom.*; +import org.dom4j.*; public class Tag extends NamedObject { - + public static final String OBJECT_TYPE = "tag"; - + public Tag () { - + super (OBJECT_TYPE); - + } - + @Override public Set getAllNamedChildObjects () { - + return null; - + } @Override public void getChanges (NamedObject old, Element root) { - + } -} \ No newline at end of file +} diff --git a/src/com/quollwriter/data/TargetsData.java b/src/main/java/com/quollwriter/data/TargetsData.java similarity index 84% rename from src/com/quollwriter/data/TargetsData.java rename to src/main/java/com/quollwriter/data/TargetsData.java index 27d86b36..eacba2cf 100644 --- a/src/com/quollwriter/data/TargetsData.java +++ b/src/main/java/com/quollwriter/data/TargetsData.java @@ -9,10 +9,10 @@ public class TargetsData { - + public enum Target { - + myDailyWriting ("myDailyWriting"), mySessionWriting ("mySessionWriting"), myWeeklyWriting ("myWeeklyWriting"), @@ -20,287 +20,287 @@ public enum Target maxChapterCount ("maxChapterCount"), readabilityGF ("readabilityGF"), readabilityFK ("readabilityFK"); - + private String type = null; - + Target (String type) { - + this.type = type; - + } - + public String getType () { - + return this.type; - + } - + } - - private Map targets = new HashMap (); + + private Map targets = new HashMap<> (); private Properties props = null; private boolean targetShowMessageWhenMaxChapterCountExceeded = false; private boolean targetShowMessageWhenSessionTargetReached = false; - + public TargetsData (Properties props) { - + this.props = props; - + this.init (); - + } - + private void init () { - + int val = this.props.getPropertyAsInt (Constants.TARGET_DAILY_WRITING_PROPERTY_NAME); - + if (val < 0) { - + // Get the default. val = Environment.getDefaultUserTargets ().getMyDailyWriting (); - + } - + this.targets.put (Target.myDailyWriting, val); val = this.props.getPropertyAsInt (Constants.TARGET_SESSION_WRITING_PROPERTY_NAME); - + if (val < 0) { - + // Get the default. val = Environment.getDefaultUserTargets ().getMySessionWriting (); - + } - + this.targets.put (Target.mySessionWriting, val); val = this.props.getPropertyAsInt (Constants.TARGET_WEEKLY_WRITING_PROPERTY_NAME); - + if (val < 0) { - + // Get the default. val = Environment.getDefaultUserTargets ().getMyWeeklyWriting (); - + } - + this.targets.put (Target.myWeeklyWriting, val); val = this.props.getPropertyAsInt (Constants.TARGET_MONTHLY_WRITING_PROPERTY_NAME); - + if (val < 0) { - + // Get the default. val = Environment.getDefaultUserTargets ().getMyMonthlyWriting (); - + } this.targets.put (Target.myMonthlyWriting, val); val = this.props.getPropertyAsInt (Constants.TARGET_READABILITY_FK_PROPERTY_NAME); - + if (val < 0) { - + // Get the default. val = Environment.getDefaultUserTargets ().getReadabilityFK (); - + } - + this.targets.put (Target.readabilityFK, val); - + val = this.props.getPropertyAsInt (Constants.TARGET_READABILITY_GF_PROPERTY_NAME); - + if (val < 0) { - + // Get the default. val = Environment.getDefaultUserTargets ().getReadabilityGF (); - + } - + this.targets.put (Target.readabilityGF, val); val = this.props.getPropertyAsInt (Constants.TARGET_MAX_CHAPTER_COUNT_PROPERTY_NAME); - + if (val < 0) { - + // Get the default. val = Environment.getDefaultUserTargets ().getMaxChapterCount (); - + } - + this.targets.put (Target.maxChapterCount, val); - this.targetShowMessageWhenMaxChapterCountExceeded = this.props.getPropertyAsBoolean (Constants.TARGET_SHOW_MESSAGE_WHEN_MAX_CHAPTER_COUNT_EXCEEDED_PROPERTY_NAME); - - this.targetShowMessageWhenSessionTargetReached = this.props.getPropertyAsBoolean (Constants.TARGET_SHOW_MESSAGE_WHEN_SESSION_TARGET_REACHED_PROPERTY_NAME); + this.targetShowMessageWhenMaxChapterCountExceeded = this.props.getPropertyAsBoolean (Constants.TARGET_SHOW_MESSAGE_WHEN_MAX_CHAPTER_COUNT_EXCEEDED_PROPERTY_NAME); + + this.targetShowMessageWhenSessionTargetReached = this.props.getPropertyAsBoolean (Constants.TARGET_SHOW_MESSAGE_WHEN_SESSION_TARGET_REACHED_PROPERTY_NAME); } - + public void setMaxChapterCount (int v) { - + this.updateIntTarget (Target.maxChapterCount, Constants.TARGET_MAX_CHAPTER_COUNT_PROPERTY_NAME, v); - + } - + public int getMaxChapterCount () { - + return this.getTargetAsInt (Target.maxChapterCount); } public void setReadabilityGF (int v) { - + this.updateIntTarget (Target.readabilityGF, Constants.TARGET_READABILITY_GF_PROPERTY_NAME, v); - + } - + public boolean isShowMessageWhenSessionTargetReached () { - + return this.targetShowMessageWhenSessionTargetReached; - + } - + public void setShowMessageWhenSessionTargetReached (boolean v) { - + this.targetShowMessageWhenSessionTargetReached = v; - + this.props.setProperty (Constants.TARGET_SHOW_MESSAGE_WHEN_SESSION_TARGET_REACHED_PROPERTY_NAME, new BooleanProperty (Constants.TARGET_SHOW_MESSAGE_WHEN_SESSION_TARGET_REACHED_PROPERTY_NAME, - v)); - + v)); + } public void setShowMessageWhenMaxChapterCountExceeded (boolean v) { - + this.targetShowMessageWhenMaxChapterCountExceeded = v; - + this.props.setProperty (Constants.TARGET_SHOW_MESSAGE_WHEN_MAX_CHAPTER_COUNT_EXCEEDED_PROPERTY_NAME, new BooleanProperty (Constants.TARGET_SHOW_MESSAGE_WHEN_MAX_CHAPTER_COUNT_EXCEEDED_PROPERTY_NAME, - v)); - + v)); + } - + public boolean isShowMessageWhenMaxChapterCountExceeded () { - + return this.targetShowMessageWhenMaxChapterCountExceeded; - + } - + public int getReadabilityGF () { - + return this.getTargetAsInt (Target.readabilityGF); } - + public void setReadabilityFK (int v) { - + this.updateIntTarget (Target.readabilityFK, Constants.TARGET_READABILITY_FK_PROPERTY_NAME, v); - + } - + public int getReadabilityFK () { - + return this.getTargetAsInt (Target.readabilityFK); } - + public void setMyDailyWriting (int c) { - + this.updateIntTarget (Target.myDailyWriting, Constants.TARGET_DAILY_WRITING_PROPERTY_NAME, c); - + } - + public int getMyDailyWriting () { - + return this.getTargetAsInt (Target.myDailyWriting); - + } - + public int getMySessionWriting () { - + return this.getTargetAsInt (Target.mySessionWriting); - + } public void setMySessionWriting (int c) { - + this.updateIntTarget (Target.mySessionWriting, Constants.TARGET_SESSION_WRITING_PROPERTY_NAME, c); - + } public int getMyWeeklyWriting () { - + return this.getTargetAsInt (Target.myWeeklyWriting); - + } public void setMyWeeklyWriting (int c) { - + this.updateIntTarget (Target.myWeeklyWriting, Constants.TARGET_WEEKLY_WRITING_PROPERTY_NAME, c); - + } public int getMyMonthlyWriting () { - + return this.getTargetAsInt (Target.myMonthlyWriting); - + } - + public void setMyMonthlyWriting (int c) { - + this.updateIntTarget (Target.myMonthlyWriting, Constants.TARGET_MONTHLY_WRITING_PROPERTY_NAME, c); - + } - + public void updateIntTarget (Target t, String propName, int value) @@ -311,24 +311,24 @@ public void updateIntTarget (Target t, this.props.setProperty (propName, new IntegerProperty (propName, - this.targets.get (t).intValue ())); - + this.targets.get (t).intValue ())); + } - + public int getTargetAsInt (Target t) { - + Number n = this.targets.get (t); - + if (n == null) { - + return 0; - + } - + return n.intValue (); - + } - -} \ No newline at end of file + +} diff --git a/src/main/java/com/quollwriter/data/TextUserConfigurableObjectTypeField.java b/src/main/java/com/quollwriter/data/TextUserConfigurableObjectTypeField.java new file mode 100644 index 00000000..918fc3e9 --- /dev/null +++ b/src/main/java/com/quollwriter/data/TextUserConfigurableObjectTypeField.java @@ -0,0 +1,79 @@ +package com.quollwriter.data; + +import com.quollwriter.ui.fx.*; +import com.quollwriter.ui.fx.viewers.*; +import com.quollwriter.ui.fx.userobjects.*; + +/** + * Models a text user configurable object field. + */ +public class TextUserConfigurableObjectTypeField extends UserConfigurableObjectTypeField +{ + + public TextUserConfigurableObjectTypeField () + { + + super (Type.text); + + } + + @Override + public boolean isSortable () + { + + return true; + + } + + @Override + public com.quollwriter.ui.userobjects.UserConfigurableObjectTypeFieldConfigHandler getConfigHandler () + { + + return new com.quollwriter.ui.userobjects.TextUserConfigurableObjectTypeFieldConfigHandler (this); + + } + + @Override + public UserConfigurableObjectTypeFieldConfigHandler getConfigHandler2 () + { + + return new TextUserConfigurableObjectTypeFieldConfigHandler (this); + + } + + @Override + public com.quollwriter.ui.userobjects.UserConfigurableObjectFieldViewEditHandler getViewEditHandler (UserConfigurableObject obj, + UserConfigurableObjectField field, + com.quollwriter.ui.AbstractProjectViewer viewer) + { + + return new com.quollwriter.ui.userobjects.TextUserConfigurableObjectFieldViewEditHandler (this, + obj, + field, + viewer); + + } + + @Override + public UserConfigurableObjectFieldViewEditHandler getViewEditHandler2 (UserConfigurableObject obj, + UserConfigurableObjectField field, + IPropertyBinder binder, + AbstractProjectViewer viewer) + { + + return new TextUserConfigurableObjectFieldViewEditHandler (this, + obj, + field, + viewer); + + } + + @Override + public boolean isSearchable () + { + + return true; + + } + +} diff --git a/src/main/java/com/quollwriter/data/UserConfigurableObject.java b/src/main/java/com/quollwriter/data/UserConfigurableObject.java new file mode 100644 index 00000000..8b46de04 --- /dev/null +++ b/src/main/java/com/quollwriter/data/UserConfigurableObject.java @@ -0,0 +1,334 @@ +package com.quollwriter.data; + +import java.util.*; + +import javafx.beans.property.*; + +import org.dom4j.*; +import org.josql.*; + +import com.quollwriter.*; +import com.quollwriter.ui.fx.*; +import com.quollwriter.ui.fx.viewers.*; +import com.quollwriter.ui.fx.userobjects.*; + +public class UserConfigurableObject extends NamedObject +{ + + protected UserConfigurableObjectType userConfigObjType = null; + protected Set fields = new LinkedHashSet<> (); + + public UserConfigurableObject (UserConfigurableObjectType objType) + { + + super (objType.getObjectTypeId ()); + + this.userConfigObjType = objType; + + } + + @Override + public void fillToStringProperties (Map props) + { + + super.fillToStringProperties (props); + + this.addToStringProperties (props, + "userConfigObjType", + this.userConfigObjType); + this.addToStringProperties (props, + "fields", + this.fields.size ()); + + } + + @Override + public Set getAllNames () + { + + Set l = new HashSet (); + + l.add (this.getName ()); + + // Find all name fields and add to the list. + for (UserConfigurableObjectField f : this.fields) + { + + l.addAll (f.getNames ()); + + } + + return l; + + } + + @Override + public Set getAllNamedChildObjects () + { + + return new LinkedHashSet (this.fields); + + } + + @Override + public void getChanges (NamedObject old, + Element root) + { + + } +/* +TODO Remove + public ObjectNameUserConfigurableObjectFieldViewEditHandler getPrimaryNameViewEditHandler (com.quollwriter.ui.ProjectViewer viewer) + { + + return (ObjectNameUserConfigurableObjectFieldViewEditHandler) this.getPrimaryNameTypeField ().getViewEditHandler (this, + null, + viewer); + + } +*/ +/* +TODO Remove + public ObjectDescriptionUserConfigurableObjectFieldViewEditHandler getObjectDescriptionViewEditHandler (com.quollwriter.ui.ProjectViewer viewer) + { + + if (this.getObjectDescriptionTypeField () == null) + { + + return null; + + } + + return (ObjectDescriptionUserConfigurableObjectFieldViewEditHandler) this.getObjectDescriptionTypeField ().getViewEditHandler (this, + null, + viewer); + + } +*/ + + public Object getValueForField (UserConfigurableObjectTypeField f) + { + + for (UserConfigurableObjectField field : this.fields) + { + + if (field.getUserConfigurableObjectTypeField () == f) + { + + return field.getUserConfigurableObjectTypeField ().getViewEditHandler (this, + field, + null).getFieldValue (); + + } + + } + + return null; + + } + + public void removeField (UserConfigurableObjectField f) + { + + if (this.userConfigObjType == null) + { + + throw new IllegalStateException ("No configurable object type set"); + + } + + if (f.isPrimaryNameField ()) + { + + throw new IllegalStateException ("Cannot remove primary name field."); + + } + + this.fields.remove (f); + + } + + public void addField (UserConfigurableObjectField f) + { + + if (this.userConfigObjType == null) + { + + throw new IllegalStateException ("No configurable object type set"); + + } + + f.setParent (this); + + this.fields.add (f); + + } + + public ObjectNameUserConfigurableObjectTypeField getPrimaryNameTypeField () + { + + if (this.userConfigObjType == null) + { + + throw new IllegalStateException ("No configurable object type set"); + + } + + return this.userConfigObjType.getPrimaryNameField (); + + } + + public ObjectDescriptionUserConfigurableObjectTypeField getObjectDescriptionTypeField () + { + + if (this.userConfigObjType == null) + { + + throw new IllegalStateException ("No configurable object type set"); + + } + + return this.userConfigObjType.getObjectDescriptionField (); + + } + + public ObjectImageUserConfigurableObjectTypeField getObjectImageTypeField () + { + + if (this.userConfigObjType == null) + { + + throw new IllegalStateException ("No configurable object type set"); + + } + + return this.userConfigObjType.getObjectImageField (); + + } + + public Set getFields () + { + + return this.fields; + + } + + public String getObjectTypeName () + { + + return this.userConfigObjType.getObjectTypeName (); + + } + + public StringProperty objectTypeNameProperty () + { + + return this.userConfigObjType.objectTypeNameProperty (); + + } + + public String getObjectTypePluralName () + { + + return this.userConfigObjType.getObjectTypeNamePlural (); + + } + + public StringProperty objectTypeNamePluralProperty () + { + + return this.userConfigObjType.objectTypeNamePluralProperty (); + + } + + public UserConfigurableObjectType getUserConfigurableObjectType () + { + + return this.userConfigObjType; + + } + + public void setUserConfigurableObjectType (UserConfigurableObjectType t) + { + + this.userConfigObjType = t; + + } + + public Set getViewEditHandlers (com.quollwriter.ui.ProjectViewer viewer) + { + + Map typeFieldMap = new HashMap<> (); + + for (UserConfigurableObjectField f : this.fields) + { + + typeFieldMap.put (f.getUserConfigurableObjectTypeField (), + f); + + } + + Set handlers = new LinkedHashSet<> (); + + for (UserConfigurableObjectTypeField tf : this.userConfigObjType.getConfigurableFields ()) + { + + UserConfigurableObjectField f = typeFieldMap.get (tf); + + com.quollwriter.ui.userobjects.UserConfigurableObjectFieldViewEditHandler h = tf.getViewEditHandler (this, + f, + viewer); + + handlers.add (h); + + } + + return handlers; + + } + + public UserConfigurableObjectField getField (UserConfigurableObjectTypeField t) + { + + return this.fields.stream () + .filter (f -> f.getUserConfigurableObjectTypeField ().equals (t)) + .findFirst () + .orElse (null); + + } + +/* +TODO Remove + public Set getViewEditHandlers2 (ProjectViewer viewer) + { + + Map typeFieldMap = new HashMap<> (); + + for (UserConfigurableObjectField f : this.fields) + { + + typeFieldMap.put (f.getUserConfigurableObjectTypeField (), + f); + + } + + Set handlers = new LinkedHashSet<> (); + + for (UserConfigurableObjectTypeField tf : this.userConfigObjType.getConfigurableFields ()) + { + + UserConfigurableObjectField f = typeFieldMap.get (tf); + + UserConfigurableObjectFieldViewEditHandler h = tf.getViewEditHandler2 (this, + f, + viewer); + + handlers.add (h); + + } + + return handlers; + + } +*/ +} diff --git a/src/main/java/com/quollwriter/data/UserConfigurableObjectField.java b/src/main/java/com/quollwriter/data/UserConfigurableObjectField.java new file mode 100644 index 00000000..bde75e51 --- /dev/null +++ b/src/main/java/com/quollwriter/data/UserConfigurableObjectField.java @@ -0,0 +1,222 @@ +package com.quollwriter.data; + +import java.util.*; + +import org.dom4j.*; + +import com.quollwriter.*; + +public class UserConfigurableObjectField extends NamedObject +{ + + private UserConfigurableObjectTypeField field = null; + private String value = null; + + public UserConfigurableObjectField (UserConfigurableObjectTypeField type) + { + + super (type.getUserConfigurableObjectType ().getObjectTypeId () + "objectfield"); + + this.field = type; + + } + + // TODO: Make this better...! + public Set getProjectFileNames () + { + + Set files = new LinkedHashSet (); + + if (this.value == null) + { + + return files; + + } + + if ((this.field instanceof ImageUserConfigurableObjectTypeField) + || + (this.field instanceof FileUserConfigurableObjectTypeField) + ) + { + + files.add (this.value); + + } + + return files; + + } + + public UserConfigurableObject getParentObject () + { + + return (UserConfigurableObject) this.getParent (); + + } + + @Override + public void fillToStringProperties (Map props) + { + + super.fillToStringProperties (props); + + this.addToStringProperties (props, + "value", + this.value); + + if (this.value != null) + { + + this.addToStringProperties (props, + "value", + this.value); + + } + + this.addToStringProperties (props, + "typeField", + this.field); + + } + + public Set getAllNamedChildObjects () + { + + return null; + + } + + public boolean isPrimaryNameField () + { + + return (this.field instanceof ObjectNameUserConfigurableObjectTypeField); + + } + + public boolean isNameField () + { + + return (this.field.isNameField () || this.isPrimaryNameField ()); + + } + + public boolean isLegacyField () + { + + return this.field.isLegacyField (); + + } + + public String getLegacyFieldId () + { + + return this.field.getLegacyFieldId (); + + } + + public UserConfigurableObjectTypeField getUserConfigurableObjectTypeField () + { + + return this.field; + + } + + @Override + public void getChanges (NamedObject old, + Element root) + { + + } + + public Set getNames () + { + + Set ret = new LinkedHashSet (); + + if ((this.isNameField ()) + && + (this.value != null) + ) + { + + String st = null; + + try + { + + StringWithMarkup sm = JSONDecoder.decodeToStringWithMarkup (this.value); + + st = sm.getText (); + + } catch (Exception e) { + + st = this.value; + + } + + if (st != null) + { + + StringTokenizer t = new StringTokenizer (st, + ";,"); + + while (t.hasMoreTokens ()) + { + + ret.add (t.nextToken ().trim ()); + + } + + } + + } + + return ret; + + } +/* + public String getValueAsString () + { + + if (this.value == null) + { + + return null; + + } + + try + { + + return this.field.getViewEditHandler (this.getParentObject (), + this, + null).valueToString (this.value); + + } catch (Exception e) { + + Environment.logError ("Unable to get value as string: " + + this.value, + e); + + return this.value.toString (); + + } + + } +*/ + public void setValue (String v) + { + + this.value = v; + + } + + public String getValue () + { + + return this.value; + + } + +} diff --git a/src/main/java/com/quollwriter/data/UserConfigurableObjectType.java b/src/main/java/com/quollwriter/data/UserConfigurableObjectType.java new file mode 100644 index 00000000..c454f892 --- /dev/null +++ b/src/main/java/com/quollwriter/data/UserConfigurableObjectType.java @@ -0,0 +1,1315 @@ +package com.quollwriter.data; + +import java.util.*; +import java.util.stream.*; + +import javafx.collections.*; +import javafx.beans.property.*; +import javafx.scene.image.*; + +import org.dom4j.*; + +import com.quollwriter.*; +import com.quollwriter.ui.fx.*; + +import static com.quollwriter.LanguageStrings.*; +import static com.quollwriter.Environment.getUIString; + +public class UserConfigurableObjectType extends NamedObject +{ + + public static final String ICON16 = "icon16"; + public static final String ICON24 = "icon24"; + public static final String OBJECT_TYPE_NAME_PLURAL = "objectTypeNamePlural"; + public static final String OBJECT_TYPE_NAME = "objectTypeName"; + public static final String OBJECT_TYPE = "userconfigobjtype"; + + private String objectTypeNamePlural = null; + private StringProperty objectTypeNamePluralProp = null; + private Image icon24x24 = null; + private Image icon16x16 = null; + private ObjectProperty icon16x16Prop = null; + private ObjectProperty icon24x24Prop = null; + private String layout = null; + private String userObjectType = null; + private boolean isAsset = false; + private javax.swing.KeyStroke createShortcutKeyStroke = null; + private boolean pluralNameSet = false; + private boolean singularNameSet = false; + private ObservableList sortableFieldsColumns = null; + private ObjectNameUserConfigurableObjectTypeField primaryNameField = null; + private ListChangeListener fieldsListener = null; + private boolean ignoreFieldsStateChanges = false; + + public UserConfigurableObjectType () + { + + super (OBJECT_TYPE); + + //this.fields = FXCollections.observableSet (new LinkedHashSet<> ()); + this.objectTypeNamePluralProp = new SimpleStringProperty (); + this.icon16x16Prop = new SimpleObjectProperty<> (); + this.icon24x24Prop = new SimpleObjectProperty<> (); + this.sortableFieldsColumns = FXCollections.observableList (new ArrayList<> ()); + + this.fieldsListener = ch -> + { + + while (ch.next ()) + { + + this.updateSortableFieldsState (); + + } + + }; + + this.sortableFieldsColumns.addListener ((ListChangeListener) ch -> + { + + while (ch.next ()) + { + + if (ch.wasRemoved ()) + { + + this.updateSortableFieldsState (); + + for (FieldsColumn rem : ch.getRemoved ()) + { + + rem.fields ().removeListener (this.fieldsListener); + + } + + } + + if (ch.wasAdded ()) + { + + this.updateSortableFieldsState (); + + for (FieldsColumn add : ch.getAddedSubList ()) + { + + add.fields ().addListener (this.fieldsListener); + add.showFieldLabelsProperty ().addListener ((pr, oldv, newv) -> + { + + this.updateSortableFieldsState (); + + }); + + add.titleProperty ().addListener ((pr, oldv, newv) -> + { + + this.updateSortableFieldsState (); + + }); + + } + + } + + } + + }); + + } + + public void updateSortableFieldsState () + { + + if (this.ignoreFieldsStateChanges) + { + + return; + + } + + try + { + + this.setProperty (Constants.USER_CONFIGURABLE_OBJECT_TYPE_SORTABLE_FIELDS_LAYOUT_PROPERTY_NAME, + this.getSortableFieldsState ().asString ()); + + Environment.updateUserConfigurableObjectType (this); + + } catch (Exception e) { + + Environment.logError ("Unable to set fields layout to: " + + this.getSortableFieldsState (), + e); + + } + + } + + @Override + public void fillToStringProperties (Map props) + { + + super.fillToStringProperties (props); + + this.addToStringProperties (props, + "objectTypeId", + this.getObjectTypeId ()); + this.addToStringProperties (props, + "objectTypeName", + this.getName ()); + this.addToStringProperties (props, + "objectTypeNamePlural", + this.getObjectTypeNamePlural ()); + this.addToStringProperties (props, + "isAsset", + this.isAssetObjectType ()); + this.addToStringProperties (props, + "layout", + this.getLayout ()); + this.addToStringProperties (props, + "createShortcutKey", + this.createShortcutKeyStroke); + this.addToStringProperties (props, + "fields", + this.getConfigurableFields ().size ()); + + } + + public FieldsColumn addNewColumn (Collection fields) + { + + FieldsColumn fc = new FieldsColumn (fields); + + this.sortableFieldsColumns.add (fc); + + return fc; + + } + + public State getSortableFieldsState () + { + + List cols = new ArrayList<> (); + + for (FieldsColumn c : this.sortableFieldsColumns) + { + + Map data = new HashMap (); + data.put ("title", + c.titleProperty ().getValue ()); + data.put ("showFieldLabels", + c.showFieldLabelsProperty ().getValue ()); + + data.put ("fields", + c.fields ().stream () + .map (f -> + { + + Map idata = new HashMap (); + idata.put ("id", + f.getObjectReference ().asString ()); + + return idata; + + }) + .collect (Collectors.toList ())); + + cols.add (data); + + } + + State state = new State (); + + state.set ("columns", + cols); + + return state; + + } + + public void setConfigurableFields (List fields) + throws Exception + { + + this.ignoreFieldsStateChanges = true; + + this.sortableFieldsColumns.stream () + .forEach (c -> c.fields ().clear ()); + + this.sortableFieldsColumns.clear (); + + for (UserConfigurableObjectTypeField f : fields) + { + + if (f.getType () == UserConfigurableObjectTypeField.Type.objectname) + { + + this.primaryNameField = (ObjectNameUserConfigurableObjectTypeField) f; + + } + + f.setUserConfigurableObjectType (this); + + } + + // Set the layout, we store it in the properties since it is "state". + String lt = this.getProperty (Constants.USER_CONFIGURABLE_OBJECT_TYPE_SORTABLE_FIELDS_LAYOUT_PROPERTY_NAME); + + if (lt == null) + { + + // Legacy... pre version 3. + + UserConfigurableObjectTypeField name = null; + UserConfigurableObjectTypeField image = null; + UserConfigurableObjectTypeField desc = null; + + for (UserConfigurableObjectTypeField f : fields) + { + + if (f.getType () == UserConfigurableObjectTypeField.Type.objectname) + { + + name = f; + } + + if (f.getType () == UserConfigurableObjectTypeField.Type.objectdesc) + { + + desc = f; + + } + + if (f.getType () == UserConfigurableObjectTypeField.Type.objectimage) + { + + image = f; + + } + + } + + if (this.layout == null) + { + + this.layout = Constants.ASSET_LAYOUT_0; + + } + + if (this.layout.equals (Constants.ASSET_LAYOUT_0)) + { + + // Create a single column. + FieldsColumn col = new FieldsColumn (); + fields.stream () + .forEach (f -> + { + + if (f == this.primaryNameField) + { + + return; + + } + + col.addField (f); + + }); + this.sortableFieldsColumns.add (col); + + } + + if ((this.layout.equals (Constants.ASSET_LAYOUT_1)) + || + (this.layout.equals (Constants.ASSET_LAYOUT_2)) + ) + { + + FieldsColumn left = new FieldsColumn (Arrays.asList (image, desc)); + left.setShowFieldLabels (false); + FieldsColumn right = new FieldsColumn (); + + // Put everything else into a single column. + for (UserConfigurableObjectTypeField f : fields) + { + + if ((f != name) + && + (f != image) + && + (f != desc) + ) + { + + right.addField (f); + + } + + } + + this.sortableFieldsColumns.add (left); + this.sortableFieldsColumns.add (right); + + } + + if (this.layout.equals (Constants.ASSET_LAYOUT_3)) + { + + // Create a two column layout. + FieldsColumn left = new FieldsColumn (); + FieldsColumn right = new FieldsColumn (); + + int c = 1; + + for (UserConfigurableObjectTypeField f : fields) + { + + if (c % 2 == 0) + { + + right.addField (f); + + } else { + + left.addField (f); + + } + + c++; + + } + + this.sortableFieldsColumns.add (left); + this.sortableFieldsColumns.add (right); + + } + + if (this.layout.equals (Constants.ASSET_LAYOUT_4)) + { + + FieldsColumn left = new FieldsColumn (); + FieldsColumn right = new FieldsColumn (Arrays.asList (image, desc)); + right.setShowFieldLabels (false); + + // Put everything else into a single column. + for (UserConfigurableObjectTypeField f : fields) + { + + if ((f != name) + && + (f != image) + && + (f != desc) + ) + { + + left.addField (f); + + } + + } + + this.sortableFieldsColumns.add (left); + this.sortableFieldsColumns.add (right); + + } + + if (this.layout.equals (Constants.ASSET_LAYOUT_5)) + { + + FieldsColumn left = new FieldsColumn (); + FieldsColumn right = new FieldsColumn (Arrays.asList (desc)); + right.setShowFieldLabels (false); + + // Put everything else into a single column. + for (UserConfigurableObjectTypeField f : fields) + { + + if ((f != name) + && + (f != image) + && + (f != desc) + ) + { + + left.addField (f); + + } + + } + + this.sortableFieldsColumns.add (left); + this.sortableFieldsColumns.add (right); + + } + + if (this.layout.equals (Constants.ASSET_LAYOUT_6)) + { + + FieldsColumn left = new FieldsColumn (Arrays.asList (desc)); + left.setShowFieldLabels (false); + FieldsColumn right = new FieldsColumn (); + + // Put everything else into a single column. + for (UserConfigurableObjectTypeField f : fields) + { + + if ((f != name) + && + (f != image) + && + (f != desc) + ) + { + + right.addField (f); + + } + + } + + this.sortableFieldsColumns.add (left); + this.sortableFieldsColumns.add (right); + + } + + if (this.layout.equals (Constants.ASSET_LAYOUT_7)) + { + + FieldsColumn left = new FieldsColumn (Arrays.asList (desc)); + FieldsColumn right = new FieldsColumn (); + right.addField (image); + + // Put everything else into a single column. + for (UserConfigurableObjectTypeField f : fields) + { + + if ((f != name) + && + (f != image) + && + (f != desc) + ) + { + + right.addField (f); + + } + + } + + this.sortableFieldsColumns.add (left); + this.sortableFieldsColumns.add (right); + + } + + if (this.layout.equals (Constants.ASSET_LAYOUT_8)) + { + + FieldsColumn left = new FieldsColumn (); + FieldsColumn right = new FieldsColumn (Arrays.asList (desc)); + + right.setShowFieldLabels (false); + left.addField (image); + + // Put everything else into a single column. + for (UserConfigurableObjectTypeField f : fields) + { + + if ((f != name) + && + (f != image) + && + (f != desc) + ) + { + + left.addField (f); + + } + + } + + this.sortableFieldsColumns.add (left); + this.sortableFieldsColumns.add (right); + + } + + this.setProperty (Constants.USER_CONFIGURABLE_OBJECT_TYPE_SORTABLE_FIELDS_LAYOUT_PROPERTY_NAME, + this.getSortableFieldsState ().asString ()); + + } else { + + Map _fields = new HashMap<> (); + + for (UserConfigurableObjectTypeField f : fields) + { + + _fields.put (f.getObjectReference ().asString (), + f); + + } + + State colState = new State (lt); + + List _cols = colState.getAsList ("columns", + Map.class); + + for (Map d : _cols) + { + + String title = (String) d.get ("title"); + + List fieldIds = (List) d.get ("fields"); + FieldsColumn col = new FieldsColumn (title); + if (d.containsKey ("showFieldLabels")) + { + + col.setShowFieldLabels ((Boolean) d.get ("showFieldLabels")); + + } + + this.sortableFieldsColumns.add (col); + + for (Object fid : fieldIds) + { + + if (fid == null) + { + + continue; + + } + + String fieldId = null; + + if (fid instanceof String) + { + + fieldId = fid.toString (); + + } + + if (fid instanceof Map) + { + + Map fieldData = (Map) fid; + + fieldId = fieldData.get ("id").toString (); + + } + + UserConfigurableObjectTypeField f = _fields.get (fieldId); + + if (f == null) + { + + continue; + + } + + col.addField (f); + + } + + } + + } + + this.ignoreFieldsStateChanges = false; + + } + + public Set getConfigurableFields () + { + + Set fields = new LinkedHashSet<> (); + + if (this.primaryNameField != null) + { + + fields.add (this.primaryNameField); + + } + + this.sortableFieldsColumns.stream () + .forEach (c -> fields.addAll (c.fields ())); + + return fields; + + } + + public ObservableList getSortableFieldsColumns () + { + + return this.sortableFieldsColumns; + + } + + public Set getSortableFields () + { + + Set sfs = new LinkedHashSet (); + + sfs.add (this.getPrimaryNameField ()); + for (UserConfigurableObjectTypeField f : this.getConfigurableFields ()) + { + + if (f.isSortable ()) + { + + sfs.add (f); + + } + + } + + return sfs; + + } + + public void setCreateShortcutKeyStroke (javax.swing.KeyStroke k) + { + + this.createShortcutKeyStroke = k; + + } + + public javax.swing.KeyStroke getCreateShortcutKeyStroke () + { + + return this.createShortcutKeyStroke; + + } + + public boolean isLegacyObjectType () + { + + return this.getUserObjectType () != null; + + } + + public String getUserObjectType () + { + + return this.userObjectType; + + } + + public void setUserObjectType (String t) + { + + this.userObjectType = t; + + } + + @Override + public Set getAllNamedChildObjects () + { + + return new LinkedHashSet<> (this.getConfigurableFields ()); + + } + + @Override + public void getChanges (NamedObject old, + Element root) + { + + } + + public String getLayout () + { + + return this.layout; + + } + + public void setLayout (String l) + { + + this.layout = l; + + } + +/* +TODO REmove + public void addConfigurableField (UserConfigurableObjectTypeField f) + { + + this.fields.add (f); + + f.setUserConfigurableObjectType (this); + + if (f.getOrder () == -1) + { + + f.setOrder (this.fields.size () - 1); + + } + + } +*/ +/* +TODO Remove + public void removeConfigurableField (UserConfigurableObjectTypeField f) + { + + if (f instanceof ObjectNameUserConfigurableObjectTypeField) + { + + throw new IllegalArgumentException ("Cant remove the object name field."); + + } + + this.fields.remove (f); + + f.setUserConfigurableObjectType (null); + + int i = 0; + + for (UserConfigurableObjectTypeField _f : this.fields) + { + + _f.setOrder (i); + + i++; + + } + + } + */ +/* + public void reorderFields () + { + + TreeMap s = new TreeMap (); + + for (UserConfigurableObjectTypeField f : this.fields) + { + + if (f.getOrder () == -1) + { + + throw new IllegalStateException ("Field must have an order value: " + + f); + + } + + s.put (f.getOrder (), + f); + + } + + this.fields = new LinkedHashSet (s.values ()); + + } +*/ + public UserConfigurableObjectTypeField getLegacyField (String id) + { + + for (FieldsColumn fc : this.sortableFieldsColumns) + { + + UserConfigurableObjectTypeField f = fc.getLegacyField (id); + + if (f != null) + { + + return f; + + } + + } + + return null; + + } + + /** + * Return how many non object name/object description fields there are. + * + * @return The count. + */ + public int getNonCoreFieldCount () + { + + int c = 0; + + for (UserConfigurableObjectTypeField f : this.getConfigurableFields ()) + { + + // TODO: Need a better way! + if (f instanceof ObjectNameUserConfigurableObjectTypeField) + { + + continue; + + } + + if (f instanceof ObjectDescriptionUserConfigurableObjectTypeField) + { + + continue; + + } + + c++; + + } + + return c; + + } + + public ObjectNameUserConfigurableObjectTypeField getPrimaryNameField () + { + + return this.primaryNameField; + + } + + public ObjectDescriptionUserConfigurableObjectTypeField getObjectDescriptionField () + { + + for (UserConfigurableObjectTypeField f : this.getConfigurableFields ()) + { + + // TODO: Need a better way! + if (f instanceof ObjectDescriptionUserConfigurableObjectTypeField) + { + + return (ObjectDescriptionUserConfigurableObjectTypeField) f; + + } + + } + + return null; + + } + + public boolean hasField (UserConfigurableObjectTypeField.Type t) + { + + for (UserConfigurableObjectTypeField f : this.getConfigurableFields ()) + { + + if (f.getType () == t) + { + + return true; + + } + + } + + return false; + + } + + public ObjectImageUserConfigurableObjectTypeField getObjectImageField () + { + + for (UserConfigurableObjectTypeField f : this.getConfigurableFields ()) + { + + // TODO: Need a better way! + if (f instanceof ObjectImageUserConfigurableObjectTypeField) + { + + return (ObjectImageUserConfigurableObjectTypeField) f; + + } + + } + + return null; + + } + + public void setIcon24x24 (Image im) + { + + Image oldim = this.icon24x24; + + this.icon24x24 = im; + this.icon24x24Prop.setValue (this.icon24x24); + + this.firePropertyChangedEvent (ICON24, + oldim, + im); + + } + + public Image getIcon24x24 () + { + + return this.icon24x24; + + } + + public ObjectProperty icon24x24Property () + { + + return this.icon24x24Prop; + + } + + public void setIcon16x16 (Image im) + { + + Image oldim = this.icon16x16; + + this.icon16x16 = im; + this.icon16x16Prop.setValue (this.icon16x16); + + this.firePropertyChangedEvent (ICON16, + oldim, + im); + + } + + public Image getIcon16x16 () + { + + return this.icon16x16; + + } + + public ObjectProperty icon16x16Property () + { + + return this.icon16x16Prop; + + } + + public void setObjectTypeName (String n) + { + + String oldName = this.getName (); + + if (n != null) + { + + this.setName (n); + this.singularNameSet = (n != null); + + } + + this.firePropertyChangedEvent (OBJECT_TYPE_NAME, + oldName, + n); + + } + + public String getObjectTypeName () + { + + if (this.singularNameSet) + { + + return super.getName (); + + } + + StringProperty s = Environment.getObjectTypeName (this.userObjectType); + + if (s != null) + { + + return s.getValue (); + + } + + return null; + + } + + @Override + public StringProperty nameProperty () + { + + if (this.singularNameSet) + { + + return super.nameProperty (); + + } + + return Environment.getObjectTypeName (this.userObjectType); + + } + + public StringProperty objectTypeNameProperty () + { + + return this.nameProperty (); + + } + + public String getActualObjectTypeName () + { + + return this.getName (); + + } + + public String getObjectTypeNamePlural () + { + + if (this.pluralNameSet) + { + + return this.objectTypeNamePlural; + + } + + StringProperty s = Environment.getObjectTypeNamePlural (this.userObjectType); + + if (s != null) + { + + return s.getValue (); + + } + + return null; + + } + + public String getActualObjectTypeNamePlural () + { + + return this.objectTypeNamePlural; + + } + + public void setObjectTypeNamePlural (String n) + { + + String oldName = this.objectTypeNamePlural; + + if (n != null) + { + + this.objectTypeNamePlural = n; + this.pluralNameSet = (n != null); + + } + + this.firePropertyChangedEvent (OBJECT_TYPE_NAME_PLURAL, + oldName, + n); + + this.objectTypeNamePluralProp.setValue (this.objectTypeNamePlural); + + } + + public StringProperty objectTypeNamePluralProperty () + { + + if (this.pluralNameSet) + { + + return this.objectTypeNamePluralProp; + + } + + return Environment.getObjectTypeNamePlural (this); + + } + + public String getObjectTypeId () + { + + if (this.getUserObjectType () != null) + { + + return this.getUserObjectType (); + + } else { + + if (this.isAssetObjectType ()) + { + + return "asset:" + this.getKey (); + + } else { + + return this.getObjectReference ().asString (); + + } + + } + + } + + public void setAssetObjectType (boolean v) + { + + this.isAsset = v; + + } + + public boolean isAssetObjectType () + { + + return this.isAsset; + + } + + public static class FieldsColumn + { + + private StringProperty titleProp = null; + private BooleanProperty showFieldLabelsProp = null; + private ObservableList fields = null; + + public FieldsColumn () + { + + this.titleProp = new SimpleStringProperty (); + this.showFieldLabelsProp = new SimpleBooleanProperty (true); + this.fields = FXCollections.observableList (new ArrayList<> ()); + + } + + public FieldsColumn (String title) + { + + this (); + this.titleProp.setValue (title); + + } + + public FieldsColumn (String title, + Collection fields) + { + + this (title); + + if (fields != null) + { + + for (UserConfigurableObjectTypeField f : fields) + { + + if (f != null) + { + + // Bit of a hack here but it saves a lot of pfaffing elsewhere. + if (f.getType () == UserConfigurableObjectTypeField.Type.objectname) + { + + continue; + + } + + this.fields.add (f); + + } + + } + + } + + } + + public FieldsColumn (Collection fields) + { + + this (null, + fields); + + } + + public UserConfigurableObjectTypeField getLegacyField (String id) + { + + for (UserConfigurableObjectTypeField f : this.fields) + { + + if ((f.getLegacyFieldId () != null) + && + (f.getLegacyFieldId ().equals (id)) + ) + { + + return f; + + } + + } + + return null; + + } + + public boolean isShowFieldLabels () + { + + return this.showFieldLabelsProp.getValue (); + + } + + public void setShowFieldLabels (boolean v) + { + + this.showFieldLabelsProp.setValue (v); + + } + + public BooleanProperty showFieldLabelsProperty () + { + + return this.showFieldLabelsProp; + + } + + public String getTitle () + { + + return this.titleProp.getValue (); + + } + + public void setTitle (String t) + { + + this.titleProp.setValue (t); + + } + + public StringProperty titleProperty () + { + + return this.titleProp; + + } + + void addField (UserConfigurableObjectTypeField f) + { + + if (f == null) + { + + return; + + } + + this.fields.add (f); + + } + + public ObservableList fields () + { + + return this.fields; + + } + + } + +} diff --git a/src/main/java/com/quollwriter/data/UserConfigurableObjectTypeField.java b/src/main/java/com/quollwriter/data/UserConfigurableObjectTypeField.java new file mode 100644 index 00000000..77a2ceab --- /dev/null +++ b/src/main/java/com/quollwriter/data/UserConfigurableObjectTypeField.java @@ -0,0 +1,614 @@ +package com.quollwriter.data; + +import java.util.*; +import java.time.*; +import java.time.format.*; + +import org.dom4j.*; + +import javafx.beans.property.*; + +import com.quollwriter.*; +import com.quollwriter.ui.fx.*; +import com.quollwriter.ui.fx.viewers.*; +import com.quollwriter.ui.fx.userobjects.*; + +import static com.quollwriter.LanguageStrings.*; +import static com.quollwriter.uistrings.UILanguageStringsManager.getUILanguageStringProperty; + +public abstract class UserConfigurableObjectTypeField extends NamedObject +{ + + private static DateTimeFormatter DATE_FORMATTER = null; + + public enum Type + { + + text ("text"), + multitext ("multitext"), + image ("image"), + select ("select"), + date ("date"), + number ("number"), + file ("file"), + webpage ("webpage"), + objectname ("objectname"), + objectdesc ("objectdesc"), + objectimage ("objectimage"), + documents ("documents"), + linkedto ("linkedto"); + + private String type = null; + + Type (String type) + { + + this.type = type; + + } + + public String getType () + { + + return this.type; + + } + + public static UserConfigurableObjectTypeField getNewFieldForType (Type t) + { + + switch (t) + { + case text : return new TextUserConfigurableObjectTypeField (); + case multitext : return new MultiTextUserConfigurableObjectTypeField (); + case select : return new SelectUserConfigurableObjectTypeField (); + case date : return new DateUserConfigurableObjectTypeField (); + case number : return new NumberUserConfigurableObjectTypeField (); + case webpage : return new WebpageUserConfigurableObjectTypeField (); + case file : return new FileUserConfigurableObjectTypeField (); + case image : return new ImageUserConfigurableObjectTypeField (); + case objectname : return new ObjectNameUserConfigurableObjectTypeField (); + case objectdesc : return new ObjectDescriptionUserConfigurableObjectTypeField (); + case objectimage : return new ObjectImageUserConfigurableObjectTypeField (); + case linkedto : return new LinkedToUserConfigurableObjectTypeField (); + case documents : return new DocumentsUserConfigurableObjectTypeField (); + default : return null; + + } + + } + + public String getName () + { + + java.util.List prefix = new ArrayList (); + prefix.add (LanguageStrings.form); + prefix.add (LanguageStrings.types); + + return Environment.getUIString (prefix, + this.type); + + } + + } + + public static final String OBJECT_TYPE = "userconfigobjfield"; + + private String formName = null; + private Type type = null; + private UserConfigurableObjectType userConfigType = null; + private Map definition = new HashMap (); + private String defValue = null; + private int order = -1; + + protected UserConfigurableObjectTypeField (Type type) + { + + super (OBJECT_TYPE); + + this.type = type; + + } + + @Override + public void fillToStringProperties (Map props) + { + + super.fillToStringProperties (props); + + this.addToStringProperties (props, + "formName", + this.formName); + this.addToStringProperties (props, + "type", + this.type.getName ()); + this.addToStringProperties (props, + "default", + this.defValue); + this.addToStringProperties (props, + "order", + this.order); + this.addToStringProperties (props, + "definition", + this.definition); + + } + + /** + * The view/edit handler is used for viewing/editing the data of a field of this type. + * + * @return The view/edit handler for this type of field. + */ + // TODO: Check to see if this needs to be generic. + // TODO: Have this be configurable and use class loading... + // TODO CLean up + public abstract com.quollwriter.ui.userobjects.UserConfigurableObjectFieldViewEditHandler getViewEditHandler (UserConfigurableObject obj, + UserConfigurableObjectField field, + com.quollwriter.ui.AbstractProjectViewer viewer); + + public abstract UserConfigurableObjectFieldViewEditHandler getViewEditHandler2 (UserConfigurableObject obj, + UserConfigurableObjectField field, + IPropertyBinder binder, + AbstractProjectViewer viewer); + + /** + * The config handler is used for editing/configuration of this field. + * + * Implementing classes should return a suitable sub-type that can handle this field. + * + * @return The config handler for this field. + */ + // TODO Clean up + public abstract com.quollwriter.ui.userobjects.UserConfigurableObjectTypeFieldConfigHandler getConfigHandler (); + + public abstract UserConfigurableObjectTypeFieldConfigHandler getConfigHandler2 (); + + public boolean isSortable () + { + + return false; + + } + + public boolean canEdit () + { + + return true; + + } + + public boolean canDelete () + { + + return true; + + } + + public void setDefinitionValue (String id, + Object v) + { + + this.definition.put (id, + v); + + } + + public void setDefinitionValue (String id, + Date v) + { + + this.definition.put (id, + Environment.formatDate (v)); + + } + + public void setDefinitionValue (String id, + Double v) + { + + this.definition.put (id, + (v != null ? Environment.formatNumber (v) : null)); + + } + + public Double getDoubleDefinitionValue (String id) + throws GeneralException + { + + Object o = this.getDefinitionValue (id); + + if (o == null) + { + + return null; + + } + + return Environment.parseToDouble (o.toString ()); + + } + + public static String formatDate (LocalDate d) + { + + if (DATE_FORMATTER == null) + { + + DATE_FORMATTER = DateTimeFormatter.ofPattern ("d-MM-yyyy"); + + } + + if (d == null) + { + + return null; + + } + + return d.format (DATE_FORMATTER); + + } + + public static LocalDate parseDate (String d) + { + + if (DATE_FORMATTER == null) + { + + DATE_FORMATTER = DateTimeFormatter.ofPattern ("d-MM-yyyy"); + + } + + if (d == null) + { + + return null; + + } + + try + { + + return LocalDate.parse (d, + DATE_FORMATTER); + + } catch (Exception e) { + + // Try legacy format. + try + { + + return LocalDate.parse (d, + DateTimeFormatter.ofPattern ("d MMM yyyy")); + + } catch (Exception ee) { + + Environment.logError ("Unable to parse date: " + + d, + ee); + + return null; + + } + + } + + } + + public LocalDate getDateDefinitionValue (String id) + { + + Object v = this.getDefinitionValue (id); + + if (v == null) + { + + return null; + + } + + return UserConfigurableObjectTypeField.parseDate (v.toString ()); + + } + + public boolean getBooleanDefinitionValue (String id) + { + + Boolean b = (Boolean) this.getDefinitionValue (id); + + if (b == null) + { + + return false; + + } + + return b; + + } + + public Object getDefinitionValue (String id) + { + + return this.definition.get (id); + + } + + public void removeDefinitionValue (String id) + { + + this.definition.remove (id); + + } + + public boolean isLegacyField () + { + + return this.getLegacyFieldId () != null; + + } + + public boolean isSearchable () + { + + return this.getBooleanDefinitionValue ("searchable"); + + } + + public void setSearchable (boolean v) + { + + this.setDefinitionValue ("searchable", true); + + } + + public StringProperty getLegacyFieldFormName () + { + + UserConfigurableObjectType ot = this.getUserConfigurableObjectType (); + + String ut = ot.getUserObjectType (); + + String id = this.getLegacyFieldId (); + + if (ut.equals (Chapter.OBJECT_TYPE)) + { + + if (id.equals (LegacyUserConfigurableObject.DESCRIPTION_LEGACY_FIELD_ID)) + { + + return getUILanguageStringProperty (chapters,fields,description); + + } + + if (id.equals (Chapter.PLAN_LEGACY_FIELD_ID)) + { + + return getUILanguageStringProperty (chapters,fields,plan); + + } + + if (id.equals (Chapter.GOALS_LEGACY_FIELD_ID)) + { + + return getUILanguageStringProperty (chapters,fields,goals); + + } + + } + + if (id.equals (LegacyUserConfigurableObject.NAME_LEGACY_FIELD_ID)) + { + + return getUILanguageStringProperty (assets,legacyfields,name); + + } + + if (id.equals (LegacyUserConfigurableObject.ALIASES_LEGACY_FIELD_ID)) + { + + return getUILanguageStringProperty (assets,legacyfields,aliases); + + } + + if (id.equals (LegacyUserConfigurableObject.DESCRIPTION_LEGACY_FIELD_ID)) + { + + return getUILanguageStringProperty (assets,legacyfields,description); + + } + + if (id.equals (QObject.TYPE_LEGACY_FIELD_ID)) + { + + return getUILanguageStringProperty (assets,legacyfields,LanguageStrings.type); + + } + + if (id.equals (ResearchItem.WEB_PAGE_LEGACY_FIELD_ID)) + { + + return getUILanguageStringProperty (assets,legacyfields,webpage); + + } + + throw new IllegalArgumentException ("Unsupported field id: " + id); + + } + + public void setLegacyFieldId (String i) + { + + this.setDefinitionValue ("legacyFieldId", i); + + } + + public String getLegacyFieldId () + { + + return (String) this.getDefinitionValue ("legacyFieldId"); + + } + + public void setOrder (int i) + { + + int c = this.order; + + this.order = i; + /* + if ((this.userConfigType != null) + && + (i != c) + ) + { + + this.userConfigType.reorderFields (); + + } + */ + } + + public int getOrder () + { + + return this.order; + + } + + public Map getDefinition () + { + + return this.definition; + + } + + public void setDefinition (Map m) + { + + this.definition = m; + + } + + public String getDefaultValue () + { + + return (String) this.getDefinitionValue ("default"); + + } + + public void setDefaultValue (String v) + { + + this.setDefinitionValue ("default", v); + + } + + public void setUserConfigurableObjectType (UserConfigurableObjectType t) + { + + this.userConfigType = t; + + this.setParent (t); + + } + + public UserConfigurableObjectType getUserConfigurableObjectType () + { + + return this.userConfigType; + + } + + @Override + public Set getAllNamedChildObjects () + { + + return null; + + } + + @Override + public void getChanges (NamedObject old, + Element root) + { + + } + + public boolean isNameField () + { + + Object o = this.getDefinitionValue ("nameField"); + + if (o == null) + { + + return false; + + } + + return (Boolean) o; + + } + + public void setNameField (boolean v) + { + + this.setDefinitionValue ("nameField", v); + + } + + public DataObject getObjectForReference (ObjectReference ref) + { + + return null; + + } + + public void setFormName (String n) + { + + super.setName (n); + + } + + public StringProperty formNameProperty () + { + + if (this.getName () != null) + { + + return this.nameProperty (); + + } + + return this.getLegacyFieldFormName (); + + } + + public String getFormName () + { + + String n = this.getName (); + + if (n != null) + { + + return n; + + } + + return this.getLegacyFieldFormName ().getValue (); + + //return this.getName (); + + } + + public Type getType () + { + + return this.type; + + } + +} diff --git a/src/main/java/com/quollwriter/data/UserSession.java b/src/main/java/com/quollwriter/data/UserSession.java new file mode 100644 index 00000000..cca06e7e --- /dev/null +++ b/src/main/java/com/quollwriter/data/UserSession.java @@ -0,0 +1,345 @@ +package com.quollwriter.data; + +import java.util.*; +import java.util.stream.*; + +import javafx.collections.*; +import javafx.beans.property.*; + +import com.quollwriter.*; +//import com.quollwriter.ui.*; +import com.quollwriter.ui.fx.*; +import com.quollwriter.ui.fx.viewers.*; + +/** + * Holds state information about the user session. + */ +public class UserSession extends Session +{ + + public boolean sessionTargetReachedPopupShown = false; + public boolean dailyTargetReachedPopupShown = false; + private int lastSnapshotSessionWordCount = 0; + private Date lastSnapshotSessionEnd = null; + private int currentSessionWordCount = 0; + private IntegerProperty currentSessionWordCountProp = null; + private Date dailyTargetReachedPopupShownDate = null; + private Date weeklyTargetReachedPopupShownDate = null; + private Date monthlyTargetReachedPopupShownDate = null; + + private PropertyBinder binder = new PropertyBinder (); + private Map listenerHandles = new HashMap<> (); + + public UserSession () + { + + this.init (); + + } + + public UserSession (Date start, + Date end, + int wc) + { + + super (start, + end, + wc); + + this.init (); + + } + + private void init () + { + + this.currentSessionWordCountProp = new SimpleIntegerProperty (0); + + // The UserSession object has the same life span as the Environment so this is ok. + Environment.getOpenViewers ().addListener ((SetChangeListener) ev -> + { + + if (ev.wasRemoved ()) + { + + this.listenerHandles.remove (ev.getElementRemoved ()); + + } + + if (ev.wasAdded ()) + { + + if (ev.getElementAdded () instanceof AbstractProjectViewer) + { + + AbstractProjectViewer pv = (AbstractProjectViewer) ev.getElementAdded (); + + this.listenerHandles.put (pv, + this.binder.addChangeListener (pv.sessionWordCountProperty (), + (pr, oldv, newv) -> + { + + this.currentSessionWordCount = Environment.getOpenViewers ().stream () + .filter (v -> v instanceof AbstractProjectViewer) + .map (v -> (AbstractProjectViewer) v) + .collect (Collectors.summingInt (v -> v.getSessionWordCount ())); + + UIUtils.runLater (() -> + { + + this.currentSessionWordCountProp.setValue (this.currentSessionWordCount); + + }); + + })); + + } + + } + + }); + + String dv = UserProperties.get (Constants.TARGET_DAILY_TARGET_REACHED_POPUP_SHOWN_DATE); + + Date currDate = Utils.zeroTimeFields (new Date ()); + + if (dv != null) + { + + try + { + + this.dailyTargetReachedPopupShownDate = Utils.zeroTimeFields (new Date (Long.parseLong (dv))); + + this.dailyTargetReachedPopupShown = (currDate == this.dailyTargetReachedPopupShownDate); + + } catch (Exception e) { + + Environment.logError ("Unable to parse daily target reached popup shown date", + e); + + } + + } + + dv = UserProperties.get (Constants.TARGET_WEEKLY_TARGET_REACHED_POPUP_SHOWN_DATE); + + if (dv != null) + { + + try + { + + this.weeklyTargetReachedPopupShownDate = new Date (Long.parseLong (dv)); + + } catch (Exception e) { + + Environment.logError ("Unable to parse weekly target reached popup shown date", + e); + + } + + } + + dv = UserProperties.get (Constants.TARGET_MONTHLY_TARGET_REACHED_POPUP_SHOWN_DATE); + + if (dv != null) + { + + try + { + + this.monthlyTargetReachedPopupShownDate = new Date (Long.parseLong (dv)); + + } catch (Exception e) { + + Environment.logError ("Unable to parse monthly target reached popup shown date", + e); + + } + + } + + } + + public void shownDailyTargetReachedPopup () + { + + Date d = Utils.zeroTimeFields (new Date ()); + + this.dailyTargetReachedPopupShownDate = d; + this.dailyTargetReachedPopupShown = true; + + // Set a user property. + UserProperties.set (Constants.TARGET_DAILY_TARGET_REACHED_POPUP_SHOWN_DATE, + String.valueOf (d.getTime ())); + + } + + public boolean shouldShowDailyTargetReachedPopup () + { + + if ((this.dailyTargetReachedPopupShownDate != null) + && + (this.dailyTargetReachedPopupShown) + ) + { + + Date d = Utils.zeroTimeFields (new Date ()); + + return d.after (this.dailyTargetReachedPopupShownDate); + + } + + return true; + + } + + private Date getWeekDate () + { + + GregorianCalendar gc = new GregorianCalendar (); + + gc.set (Calendar.DAY_OF_WEEK, + gc.getFirstDayOfWeek ()); + + Date d = Utils.zeroTimeFields (gc.getTime ()); + + return d; + + } + + public void shownWeeklyTargetReachedPopup () + { + + Date d = this.getWeekDate (); + + this.weeklyTargetReachedPopupShownDate = d; + + // Set a user property. + UserProperties.set (Constants.TARGET_WEEKLY_TARGET_REACHED_POPUP_SHOWN_DATE, + String.valueOf (d.getTime ())); + + } + + public boolean shouldShowWeeklyTargetReachedPopup () + { + + if (this.weeklyTargetReachedPopupShownDate != null) + { + + Date d = this.getWeekDate (); + + return d.after (this.weeklyTargetReachedPopupShownDate); + + } + + return true; + + } + + private Date getMonthDate () + { + + GregorianCalendar gc = new GregorianCalendar (); + + gc.set (Calendar.DAY_OF_MONTH, + 1); + + Date d = Utils.zeroTimeFields (gc.getTime ()); + + return d; + + } + + public void shownMonthlyTargetReachedPopup () + { + + Date d = this.getMonthDate (); + + this.monthlyTargetReachedPopupShownDate = d; + + // Set a user property. + UserProperties.set (Constants.TARGET_MONTHLY_TARGET_REACHED_POPUP_SHOWN_DATE, + String.valueOf (d.getTime ())); + + } + + public boolean shouldShowMonthlyTargetReachedPopup () + { + + if (this.monthlyTargetReachedPopupShownDate != null) + { + + Date d = this.getMonthDate (); + + return d.after (this.monthlyTargetReachedPopupShownDate); + + } + + return true; + + } + + public void shownSessionTargetReachedPopup () + { + + this.sessionTargetReachedPopupShown = true; + + } + + public boolean shouldShowSessionTargetReachedPopup () + { + + return !this.sessionTargetReachedPopupShown; + + } + + public String toString () + { + + return super.toString () + ", lastCurrent: " + this.currentSessionWordCount + ", current: " + this.getCurrentSessionWordCount (); + + } + + @Override + public int getWordCount () + { + + return this.getCurrentSessionWordCount (); + + } + + public int getCurrentSessionWordCount () + { + + return this.currentSessionWordCount; + + } + + public IntegerProperty currentSessionWordCountProperty () + { + + return this.currentSessionWordCountProp; + + } + + public UserSession createSnapshot () + { + + int wc = this.getCurrentSessionWordCount () - this.lastSnapshotSessionWordCount; + + Date end = new Date (); + + UserSession s = new UserSession ((this.lastSnapshotSessionEnd != null ? this.lastSnapshotSessionEnd : this.getStart ()), + end, + wc); + + this.lastSnapshotSessionEnd = end; + this.lastSnapshotSessionWordCount = wc; + + return s; + + } + +} diff --git a/src/com/quollwriter/data/Warmup.java b/src/main/java/com/quollwriter/data/Warmup.java similarity index 89% rename from src/com/quollwriter/data/Warmup.java rename to src/main/java/com/quollwriter/data/Warmup.java index 65f33bf8..9b0a1f5f 100644 --- a/src/com/quollwriter/data/Warmup.java +++ b/src/main/java/com/quollwriter/data/Warmup.java @@ -2,7 +2,7 @@ import java.util.*; -import org.jdom.*; +import org.dom4j.*; public class Warmup extends NamedObject @@ -57,13 +57,15 @@ public void setWords (int w) } + @Override public Set getAllNamedChildObjects () { - return new HashSet (this.getNotes ()); + return new HashSet<> (this.getNotes ()); } + @Override public void getChanges (NamedObject old, Element root) { @@ -81,7 +83,8 @@ public void setChapter (Chapter c) { this.chapter = c; - + this.nameProperty ().bind (c.nameProperty ()); + this.setParent (c); } @@ -100,6 +103,7 @@ public void setPrompt (Prompt p) } + @Override public DataObject getObjectForReference (ObjectReference r) { diff --git a/src/main/java/com/quollwriter/data/WebpageUserConfigurableObjectTypeField.java b/src/main/java/com/quollwriter/data/WebpageUserConfigurableObjectTypeField.java new file mode 100644 index 00000000..3db47983 --- /dev/null +++ b/src/main/java/com/quollwriter/data/WebpageUserConfigurableObjectTypeField.java @@ -0,0 +1,76 @@ +package com.quollwriter.data; + +import com.quollwriter.ui.fx.*; +import com.quollwriter.ui.fx.viewers.*; +import com.quollwriter.ui.fx.userobjects.*; + +public class WebpageUserConfigurableObjectTypeField extends UserConfigurableObjectTypeField +{ + + public WebpageUserConfigurableObjectTypeField () + { + + super (Type.webpage); + + } + + @Override + public boolean isSortable () + { + + return true; + + } + + @Override + public com.quollwriter.ui.userobjects.UserConfigurableObjectFieldViewEditHandler getViewEditHandler (UserConfigurableObject obj, + UserConfigurableObjectField field, + com.quollwriter.ui.AbstractProjectViewer viewer) + { + + return new com.quollwriter.ui.userobjects.WebpageUserConfigurableObjectFieldViewEditHandler (this, + obj, + field, + viewer); + + } + + @Override + public UserConfigurableObjectFieldViewEditHandler getViewEditHandler2 (UserConfigurableObject obj, + UserConfigurableObjectField field, + IPropertyBinder binder, + AbstractProjectViewer viewer) + { + + return new WebpageUserConfigurableObjectFieldViewEditHandler (this, + obj, + field, + viewer); + + } + + @Override + public com.quollwriter.ui.userobjects.UserConfigurableObjectTypeFieldConfigHandler getConfigHandler () + { + + return new com.quollwriter.ui.userobjects.WebpageUserConfigurableObjectTypeFieldConfigHandler (this); + + } + + @Override + public UserConfigurableObjectTypeFieldConfigHandler getConfigHandler2 () + { + + return new WebpageUserConfigurableObjectTypeFieldConfigHandler (this); + + } + + @Override + public boolean isSearchable () + { + + return true; + + } + +} diff --git a/src/com/quollwriter/data/WordCount.java b/src/main/java/com/quollwriter/data/WordCount.java similarity index 95% rename from src/com/quollwriter/data/WordCount.java rename to src/main/java/com/quollwriter/data/WordCount.java index 481cee6f..19c8be97 100644 --- a/src/com/quollwriter/data/WordCount.java +++ b/src/main/java/com/quollwriter/data/WordCount.java @@ -2,7 +2,7 @@ import java.util.*; -import org.jdom.*; +import org.dom4j.*; public class WordCount @@ -34,13 +34,14 @@ public WordCount(int count, } + @Override public String toString () { - + return "word-count(start: " + this.start + ", end: " + this.end + ", count: " + count + ")"; - + } - + public void getChanges (NamedObject old, Element root) { @@ -50,7 +51,7 @@ public void getChanges (NamedObject old, public Set getAllNamedChildObjects () { - return new HashSet (); + return new HashSet<> (); } diff --git a/src/main/java/com/quollwriter/data/comparators/ChapterItemSorter.java b/src/main/java/com/quollwriter/data/comparators/ChapterItemSorter.java new file mode 100644 index 00000000..fe4f3a17 --- /dev/null +++ b/src/main/java/com/quollwriter/data/comparators/ChapterItemSorter.java @@ -0,0 +1,134 @@ +package com.quollwriter.data.comparators; + +import java.util.*; + +import com.quollwriter.data.*; + +public class ChapterItemSorter implements Comparator +{ + + @Override + public int compare (ChapterItem o1, + ChapterItem o2) + { + + if (o1.getKey () == null) + { + + return 1; + + } + + if (o2.getKey () == null) + { + + return 1; + + } + + // The sorter may be used for contains checks in Sets and Maps so need an equality test here. + if (o1.getKey ().equals (o2.getKey ())) + { + + return 0; + + } + + if (o1.getPosition () == o2.getPosition ()) + { + + if ((o1.getKey () == null) + || + (o1.getName () == null) + ) + { + + return 1; + + } + + if ((o2.getKey () == null) + || + (o2.getName () == null) + ) + { + + return 1; + + } + + // Special case where a "new" item is added, this will have a negative key and no parent. + if ((o1.getKey () < 0) + && + (o1.getParent () == null) + && + (o2.getKey () > 0) + ) + { + + // The new item comes before. + return -1; + + } + + if ((o2.getKey () < 0) + && + (o2.getParent () == null) + && + (o1.getKey () > 0) + ) + { + + // The new item comes before. + return -1; + + } + + if ((o1 instanceof Scene) + && + (o2 instanceof OutlineItem) + ) + { + + return -1; + + } + + if ((o2 instanceof Scene) + && + (o1 instanceof OutlineItem) + ) + { + + return 1; + + } + + int nc = o1.getName ().compareTo (o2.getName ()); + + if (nc == 0) + { + + // Return the one created first. + return o1.getDateCreated ().compareTo (o2.getDateCreated ()); + + } + + return nc; + + //return (int) (o1.getKey () - o2.getKey ()); + + } + + return o1.getPosition () - o2.getPosition (); + + } + + public boolean equals (Object o) + { + + return this == o; + + } + +} diff --git a/src/com/quollwriter/data/comparators/ChapterSorter.java b/src/main/java/com/quollwriter/data/comparators/ChapterSorter.java similarity index 100% rename from src/com/quollwriter/data/comparators/ChapterSorter.java rename to src/main/java/com/quollwriter/data/comparators/ChapterSorter.java diff --git a/src/com/quollwriter/data/comparators/IdeaTypeComparator.java b/src/main/java/com/quollwriter/data/comparators/IdeaTypeComparator.java similarity index 100% rename from src/com/quollwriter/data/comparators/IdeaTypeComparator.java rename to src/main/java/com/quollwriter/data/comparators/IdeaTypeComparator.java diff --git a/src/com/quollwriter/data/comparators/NamedObjectSorter.java b/src/main/java/com/quollwriter/data/comparators/NamedObjectSorter.java similarity index 80% rename from src/com/quollwriter/data/comparators/NamedObjectSorter.java rename to src/main/java/com/quollwriter/data/comparators/NamedObjectSorter.java index ce408de5..dd06242c 100644 --- a/src/com/quollwriter/data/comparators/NamedObjectSorter.java +++ b/src/main/java/com/quollwriter/data/comparators/NamedObjectSorter.java @@ -11,52 +11,52 @@ public class NamedObjectSorter implements Comparator, ProjectEventL private static NamedObjectSorter sorter = null; - private Map objectTypeOrder = new HashMap (); + private Map objectTypeOrder = new HashMap<> (); private ChapterItemSorter chapterItemComp = new ChapterItemSorter (); - + public static NamedObjectSorter getInstance () { - + if (NamedObjectSorter.sorter == null) { - + Object o = new Object (); - + synchronized (o) { - + NamedObjectSorter.sorter = new NamedObjectSorter (); - - Environment.addUserProjectEventListener (NamedObjectSorter.sorter); - + + // TODO Environment.addUserProjectEventListener (NamedObjectSorter.sorter); + } - + } - + return NamedObjectSorter.sorter; - + } - + protected NamedObjectSorter() { this.initOrder (); - + } - + private void initOrder () { - + // We lock here on the object we will change, we don't want to be in a situation where // the ordering is being used and then it changes underneath whoever is using it. synchronized (this.objectTypeOrder) { - - Map m = new HashMap (); - + + Map m = new HashMap<> (); + int ind = 1; - + m.put (Scene.OBJECT_TYPE, ind++); m.put (OutlineItem.OBJECT_TYPE, @@ -65,17 +65,17 @@ private void initOrder () ind++); m.put (Note.OBJECT_TYPE, ind++); - + Set assetObjTypes = Environment.getAssetUserConfigurableObjectTypes (true); - + for (UserConfigurableObjectType type : assetObjTypes) { - + m.put (type.getObjectTypeId (), ind++); - + } - + m.put (IdeaType.OBJECT_TYPE, ind++); m.put (Idea.OBJECT_TYPE, @@ -84,13 +84,13 @@ private void initOrder () ind++); m.put (Project.OBJECT_TYPE, ind++); - + this.objectTypeOrder = m; - } - + } + } - + @Override public void eventOccurred (ProjectEvent ev) { @@ -99,11 +99,11 @@ public void eventOccurred (ProjectEvent ev) { this.initOrder (); - + } - + } - + @Override public int compare (NamedObject o1, NamedObject o2) @@ -114,9 +114,9 @@ public int compare (NamedObject o1, (o2 == null) ) { - + return 0; - + } if ((o1 == null) @@ -124,9 +124,9 @@ public int compare (NamedObject o1, (o2 != null) ) { - + return 1; - + } if ((o1 != null) @@ -134,16 +134,33 @@ public int compare (NamedObject o1, (o2 == null) ) { - + return -1; - + } if (!o1.getObjectType ().equals (o2.getObjectType ())) { - int o1k = this.objectTypeOrder.get (o1.getObjectType ()); - int o2k = this.objectTypeOrder.get (o2.getObjectType ()); + Integer _o1k = this.objectTypeOrder.get (o1.getObjectType ()); + Integer _o2k = this.objectTypeOrder.get (o2.getObjectType ()); + + int o1k = 0; + int o2k = 0; + + if (_o1k != null) + { + + o1k = _o1k.intValue (); + + } + + if (_o2k != null) + { + + o2k = _o2k.intValue (); + + } return o1k - o2k; @@ -167,6 +184,17 @@ public int compare (NamedObject o1, // Compare books. // If not equal fall through to a name sort. + if ((c1.getBook () == null) + || + (c2.getBook () == null) + ) + { + + // Not entirely sure how this can happen. + return 0; + + } + if (c1.getBook () == c2.getBook ()) { @@ -178,16 +206,16 @@ public int compare (NamedObject o1, if (o1.getName () == null) { - + return 1; - + } - + if (o2.getName () == null) { - + return -1; - + } return o1.getName ().toLowerCase ().compareTo (o2.getName ().toLowerCase ()); diff --git a/src/com/quollwriter/data/comparators/NoteSorter.java b/src/main/java/com/quollwriter/data/comparators/NoteSorter.java similarity index 100% rename from src/com/quollwriter/data/comparators/NoteSorter.java rename to src/main/java/com/quollwriter/data/comparators/NoteSorter.java diff --git a/src/com/quollwriter/data/comparators/OutlineItemSorter.java b/src/main/java/com/quollwriter/data/comparators/OutlineItemSorter.java similarity index 100% rename from src/com/quollwriter/data/comparators/OutlineItemSorter.java rename to src/main/java/com/quollwriter/data/comparators/OutlineItemSorter.java diff --git a/src/com/quollwriter/data/comparators/ProjectInfoSorter.java b/src/main/java/com/quollwriter/data/comparators/ProjectInfoSorter.java similarity index 100% rename from src/com/quollwriter/data/comparators/ProjectInfoSorter.java rename to src/main/java/com/quollwriter/data/comparators/ProjectInfoSorter.java diff --git a/src/com/quollwriter/data/comparators/ProjectSorter.java b/src/main/java/com/quollwriter/data/comparators/ProjectSorter.java similarity index 100% rename from src/com/quollwriter/data/comparators/ProjectSorter.java rename to src/main/java/com/quollwriter/data/comparators/ProjectSorter.java diff --git a/src/main/java/com/quollwriter/data/editors/AbstractEditorObject.java b/src/main/java/com/quollwriter/data/editors/AbstractEditorObject.java new file mode 100644 index 00000000..2a71a771 --- /dev/null +++ b/src/main/java/com/quollwriter/data/editors/AbstractEditorObject.java @@ -0,0 +1,110 @@ +package com.quollwriter.data.editors; + +import java.util.*; + +import org.dom4j.*; +import org.dom4j.tree.*; + +import com.quollwriter.data.*; + +public abstract class AbstractEditorObject extends NamedObject +{ + + public class XMLConstants + { + + public static final String id = "id"; + public static final String name = "name"; + public static final String lastModified = "lastModified"; + + } + + //private String id = null; + + public AbstractEditorObject (String objType) + { + + super (objType); + + } + + public AbstractEditorObject (String objType, + String name) + { + + super (objType, + name); + + } + + public AbstractEditorObject (Element root, + String objType) + throws Exception + { + + super (objType); + + this.setName (root.element (XMLConstants.name).getTextTrim ()); + + try + { + + this.setLastModified (new Date (Long.parseLong (root.attributeValue (XMLConstants.lastModified)))); + + } catch (Exception e) { + + } + + } + + @Override + public void fillToStringProperties (Map props) + { + + super.fillToStringProperties (props); +/* + this.addToStringProperties (props, + "id", + this.id); + */ + } + + @Override + public void getChanges (NamedObject old, + Element root) + { + + } + + public Set getAllNamedChildObjects (Class ofType) + { + + return null; + + } + + @Override + public Set getAllNamedChildObjects () + { + + return null; + + } + + public void fillElement (Element root) + { + + Element name = new DefaultElement (XMLConstants.name); + name.add (new DefaultCDATA (this.getName ())); + Element id = new DefaultElement (XMLConstants.id); + id.add (new DefaultCDATA (this.getId ())); + + root.add (id); + root.add (name); + + root.addAttribute (XMLConstants.lastModified, + "" + this.getLastModified ().getTime ()); + + } + +} diff --git a/src/com/quollwriter/data/editors/ChatMessage.java b/src/main/java/com/quollwriter/data/editors/ChatMessage.java similarity index 100% rename from src/com/quollwriter/data/editors/ChatMessage.java rename to src/main/java/com/quollwriter/data/editors/ChatMessage.java diff --git a/src/main/java/com/quollwriter/data/editors/EditorAccount.java b/src/main/java/com/quollwriter/data/editors/EditorAccount.java new file mode 100644 index 00000000..b12c9e40 --- /dev/null +++ b/src/main/java/com/quollwriter/data/editors/EditorAccount.java @@ -0,0 +1,279 @@ +package com.quollwriter.data.editors; + +import java.io.*; +import javax.imageio.*; + +import javafx.beans.property.*; +import javafx.scene.image.*; +import javafx.embed.swing.*; + +import java.util.Date; +import java.util.Map; +import java.util.LinkedHashMap; + +import org.bouncycastle.openpgp.*; + +import com.quollwriter.*; +import com.quollwriter.ui.fx.UIUtils; + +public class EditorAccount +{ + + private String email = null; + private String pwd = null; + private String name = null; + private Date lastLogin = null; + + private EditorAuthor author = null; + private EditorEditor editor = null; + + private String webServiceSessionId = null; + + private PGPPublicKey publicKey = null; + private PGPPrivateKey privateKey = null; + + private String messagingUsername = null; + private String serviceName = null; + + private ObjectProperty avatarProp = new SimpleObjectProperty (); + + public EditorAccount () + { + + + } + + @Override + public String toString () + { + + Map props = new LinkedHashMap (); + + props.put ("email", + this.email); + props.put ("name", + this.name); + props.put ("messagingUsername", + this.messagingUsername); + props.put ("serviceName", + this.serviceName); + + props.put ("hasPassword", + this.pwd != null); + + props.put ("lastLogin", + this.lastLogin); + + return Environment.formatObjectToStringProperties (props); + + } + + public String getServiceName () + { + + return this.serviceName; + + } + + public void setServiceName (String n) + { + + this.serviceName = n; + + } + + public String getMessagingUsername () + { + + return this.messagingUsername; + + } + + public void setMessagingUsername (String u) + { + + this.messagingUsername = u; + + } + + public void setPublicKey (PGPPublicKey k) + { + + this.publicKey = k; + + } + + public void setPrivateKey (PGPPrivateKey k) + { + + this.privateKey = k; + + } + + public PGPPublicKey getPublicKey () + { + + return this.publicKey; + + } + + public PGPPrivateKey getPrivateKey () + { + + return this.privateKey; + + } + + public Date getLastLogin () + { + + return this.lastLogin; + + } + + public void setLastLogin (Date d) + { + + this.lastLogin = d; + + } + + public void setWebServiceSessionId (String id) + { + + this.webServiceSessionId = id; + + } + + public String getWebServiceSessionId () + { + + return this.webServiceSessionId; + + } + + public String getAvatarBase64Encoded () + throws Exception + { + + if (this.avatarProp.getValue () == null) + { + + return null; + + } + + ByteArrayOutputStream bout = new ByteArrayOutputStream (); + ImageIO.write (SwingFXUtils.fromFXImage (this.avatarProp.getValue (), null), + "", + bout); + + return Base64.encodeBytes (bout.toByteArray ()); + + } + + public ObjectProperty avatarProperty () + { + + return this.avatarProp; + + } + + public void setAvatar (Image im) + { + + if (im != null) + { + + if (im.getWidth () > Constants.EDITORS_SERVICE_AVATAR_MAX_WIDTH) + { + + im = UIUtils.getScaledImage (im, + Constants.EDITORS_SERVICE_AVATAR_MAX_WIDTH); + + } + + } + + this.avatarProp.setValue (im); + + } + + public Image getAvatar () + { + + return this.avatarProp.getValue (); + + } + + public void setName (String n) + { + + this.name = n; + + } + + public String getName () + { + + return this.name; + + } + + public void setEditor (EditorEditor e) + { + + this.editor = e; + + } + + public EditorEditor getEditor () + { + + return this.editor; + + } + + public EditorAuthor getAuthor () + { + + return this.author; + + } + + public void setAuthor (EditorAuthor a) + { + + this.author = a; + + } + + public void setPassword (String p) + { + + this.pwd = p; + + } + + public String getPassword () + { + + return this.pwd; + + } + + public String getEmail () + { + + return this.email; + + } + + public void setEmail (String em) + { + + this.email = em; + + } + +} diff --git a/src/main/java/com/quollwriter/data/editors/EditorAuthor.java b/src/main/java/com/quollwriter/data/editors/EditorAuthor.java new file mode 100644 index 00000000..0d05516f --- /dev/null +++ b/src/main/java/com/quollwriter/data/editors/EditorAuthor.java @@ -0,0 +1,97 @@ +package com.quollwriter.data.editors; + +import java.io.*; + +import org.dom4j.*; +import org.dom4j.tree.*; + +import com.quollwriter.*; + +public class EditorAuthor extends AbstractEditorObject +{ + + public static final String OBJECT_TYPE = "editorauthor"; + + public class XMLConstants + { + + public static final String root = "author"; + public static final String about = "about"; + + } + + private String about = null; + private String avatarImageFileType = null; + + public EditorAuthor () + { + + super (OBJECT_TYPE); + + } + + public EditorAuthor (Element root) + throws Exception + { + + super (root, + OBJECT_TYPE); + + this.about = DOM4JUtils.childElementContent (root, + XMLConstants.about); + + } + + public Element getAsElement () + { + + Element root = new DefaultElement (XMLConstants.root); + + this.fillElement (root); + + Element about = new DefaultElement (XMLConstants.about); + about.add (new DefaultCDATA (this.about)); + + root.add (about); + + return root; + + } + + public void setAvatarImageFileType (String t) + { + + this.avatarImageFileType = t; + + } + + public String getAvatarImageFileType () + { + + return this.avatarImageFileType; + + } + + /* + public File getAvatarImage () + { + + return Environment.getEditorsAuthorAvatarImageFile (); + + } + */ + public String getAbout () + { + + return this.about; + + } + + public void setAbout (String a) + { + + this.about = a; + + } + +} diff --git a/src/main/java/com/quollwriter/data/editors/EditorEditor.java b/src/main/java/com/quollwriter/data/editors/EditorEditor.java new file mode 100644 index 00000000..94eb1ddb --- /dev/null +++ b/src/main/java/com/quollwriter/data/editors/EditorEditor.java @@ -0,0 +1,954 @@ +package com.quollwriter.data.editors; + +import java.io.*; +import java.util.*; + +import javafx.collections.*; +import javafx.beans.property.*; +import javafx.beans.binding.*; +import javafx.scene.image.*; + +import org.dom4j.*; +import org.dom4j.tree.*; + +import org.bouncycastle.openpgp.*; +import org.bouncycastle.bcpg.*; + +import com.quollwriter.*; +import com.quollwriter.data.*; +import com.quollwriter.editors.messages.*; + +import static com.quollwriter.LanguageStrings.*; +import static com.quollwriter.uistrings.UILanguageStringsManager.getUILanguageStringProperty; + +public class EditorEditor extends AbstractEditorObject +{ + + public enum OnlineStatus + { + + online ("online"), + busy ("busy"), + offline ("offline"), + away ("away"), + snooze ("snooze"); + + private String type = null; + + OnlineStatus (String type) + { + + this.type = type; + + } + + public String getType () + { + + return this.type; + + } + + public StringProperty nameProperty () + { + + switch (this) + { + case online : return getUILanguageStringProperty (editors,statuses, LanguageStrings.online);//"Online"; + case offline : return getUILanguageStringProperty (editors,statuses, LanguageStrings.offline);//"Offline"; + case busy : return getUILanguageStringProperty (editors,statuses, LanguageStrings.busy);//"Busy"; + case away : return getUILanguageStringProperty (editors,statuses, LanguageStrings.away);//"Away"; + case snooze : return getUILanguageStringProperty (editors,statuses, LanguageStrings.snooze);//"Snooze"; + default : return new SimpleStringProperty ("Unknown"); + + } + + } + + public String getName () + { + + return this.nameProperty ().getValue (); + + } + + } + + public enum EditorStatus + { + + current ("current"), + previous ("previous"), + pending ("pending"), + pending_inviteaccepted ("pending_inviteaccepted"), + rejected ("rejected"); + + private String type = null; + + EditorStatus (String type) + { + + this.type = type; + + } + + public String getType () + { + + return this.type; + + } + + } + + public static final String OBJECT_TYPE = "editor"; + + public class XMLConstants + { + + public static final String root = "editor"; + public static final String about = "about"; + public static final String genres = "genres"; + public static final String wordCountLengths = "wordCountLengths"; + + } + + private StringProperty emailProp = new SimpleStringProperty (); + private String about = null; + private Set wcLengths = null; + private Set genres = null; + private ObjectProperty statusProp = new SimpleObjectProperty (); + private ObjectProperty editorStatusProp = new SimpleObjectProperty (EditorStatus.pending); + private ObservableSet messages = FXCollections.observableSet (new LinkedHashSet<> ()); + private ObjectProperty avatarProp = new SimpleObjectProperty (); + private String avatarImageFileType = null; + private boolean invitedByMe = false; + private PGPPublicKey theirPublicKey = null; + private boolean messagesLoaded = false; + private StringProperty myNameForEditorProp = new SimpleStringProperty (); + private ObjectProperty myAvatarForEditorProp = new SimpleObjectProperty (); + private String serviceName = null; + private String messagingUsername = null; + private StringProperty mainNameProp = new SimpleStringProperty (); + private ObjectProperty mainAvatarProp = new SimpleObjectProperty (); + private IntegerProperty messagesUpdatedProp = new SimpleIntegerProperty (0); + + public EditorEditor () + { + + super (OBJECT_TYPE); + this.mainNameProp.bind (Bindings.createStringBinding (() -> + { + + if (this.myNameForEditorProp.getValue () != null) + { + + return this.myNameForEditorProp.getValue (); + + } + + if (this.getName () != null) + { + + return this.getName (); + + } + + return this.emailProp.getValue (); + + }, + this.nameProperty (), + this.emailProperty (), + this.myNameForEditorProperty ())); + + this.nameProperty ().addListener ((pr, oldv, newv) -> {}); + this.emailProp.addListener ((pr, oldv, newv) -> {}); + this.myNameForEditorProp.addListener ((pr, oldv, newv) -> {}); + + this.myAvatarForEditorProp.addListener ((pr, oldv, newv) -> + { + + if (newv == null) + { + + newv = this.avatarProp.getValue (); + + } + + this.mainAvatarProp.setValue (newv); + + }); + + this.avatarProp.addListener ((pr, oldv, newv) -> + { + + if (newv == null) + { + + newv = this.myAvatarForEditorProp.getValue (); + + } + + this.mainAvatarProp.setValue (newv); + + }); + + } + + public EditorEditor (String name, + Image avatar, + OnlineStatus status, + EditorStatus editorStatus) + { + + this (); + this.setName (name); + + this.setAvatar (avatar); + this.setOnlineStatus (status); + this.setEditorStatus (editorStatus); + + } + + public EditorEditor (Element root) + throws Exception + { + + super (root, + OBJECT_TYPE); + + this.about = DOM4JUtils.childElementContent (root, + XMLConstants.about); + + String genres = root.attributeValue (XMLConstants.genres); + + if (genres != null) + { + + this.genres = new TreeSet<> (); + + StringTokenizer t = new StringTokenizer (genres, + ","); + + while (t.hasMoreTokens ()) + { + + this.genres.add (t.nextToken ().trim ()); + + } + + } + + String wcls = root.attributeValue (XMLConstants.wordCountLengths); + + if (wcls != null) + { + + this.wcLengths = new TreeSet<> (); + + StringTokenizer t = new StringTokenizer (wcls, + ","); + + while (t.hasMoreTokens ()) + { + + this.wcLengths.add (EditorProject.WordCountLength.getWordCountLengthByType (t.nextToken ().trim ())); + + } + + } + + } + + @Override + public void fillToStringProperties (Map props) + { + + super.fillToStringProperties (props); + + this.addToStringProperties (props, + "email", + this.emailProp.getValue ()); + this.addToStringProperties (props, + "onlineStatus", + (this.statusProp.getValue () != null ? this.statusProp.getValue ().getType () : "unknown")); + this.addToStringProperties (props, + "editorStatus", + this.editorStatusProp.getValue ().getType ()); + this.addToStringProperties (props, + "serviceName", + this.serviceName); + this.addToStringProperties (props, + "messagingUsername", + this.messagingUsername); + this.addToStringProperties (props, + "hasPublicKey", + (this.theirPublicKey != null)); + this.addToStringProperties (props, + "invitedByMe", + this.invitedByMe); + this.addToStringProperties (props, + "messages", + (this.messages != null ? this.messages.size () : 0)); + this.addToStringProperties (props, + "myNameForEditor", + this.myNameForEditorProp.getValue ()); + this.addToStringProperties (props, + "hasMyAvatarForEditor", + (this.myAvatarForEditorProp.getValue () != null)); + + } + + public ObjectProperty editorStatusProperty () + { + + return this.editorStatusProp; + + } + + public String getMessagingUsername () + { + + return this.messagingUsername; + + } + + public void setMessagingUsername (String u) + { + + this.messagingUsername = u; + + } + + public String getServiceName () + { + + return this.serviceName; + + } + + public void setServiceName (String n) + { + + this.serviceName = n; + + } + + public StringProperty myNameForEditorProperty () + { + + return this.myNameForEditorProp; + + } + + public String getMyNameForEditor () + { + + return this.myNameForEditorProp.getValue (); + + } + + public void setMyNameForEditor (String n) + { + + this.myNameForEditorProp.setValue (n); + + } + /* + public void setMyPrivateKey (PGPPrivateKey k) + { + + this.myPrivateKey = k; + + } + */ + + public Image getMainAvatar () + { + + return this.mainAvatarProp.getValue (); + + } + /* + public BufferedImage getMainAvatar () + { + + if (this.myAvatarForEditor != null) + { + + return this.myAvatarForEditor; + + } + + return this.avatar; + + } +*/ + public String getMainName () + { + + return this.mainNameProp.getValue (); + + } + + public StringProperty mainNameProperty () + { + + return this.mainNameProp; + + } + + public PGPPublicKey getTheirPublicKey () + { + + return this.theirPublicKey; + + } + + public void setTheirPublicKey (PGPPublicKey k) + { + + this.theirPublicKey = k; + + } + + public boolean isInvitedByMe () + { + + return this.invitedByMe; + + } + + public void setInvitedByMe (boolean v) + { + + this.invitedByMe = v; + + } + + public String getEmail () + { + + return this.emailProp.getValue (); + + } + + public void setEmail (String em) + { + + this.emailProp.setValue (em); + + } + + public StringProperty emailProperty () + { + + return this.emailProp; + + } + + public void setAvatarImageFileType (String t) + { + + this.avatarImageFileType = t; + + } + + public String getAvatarImageFileType () + { + + return this.avatarImageFileType; + + } + + public void setEditorStatus (EditorStatus s) + { + + this.editorStatusProp.setValue (s); + + } + + public EditorStatus getEditorStatus () + { + + return this.editorStatusProp.getValue (); + + } + + /** + * Do we have an editor-info message sent by the editor? + * We can't assume that the messages have been loaded here. + * + * @return true If the info has been sent/recevied. + */ + public boolean hasSentInfo () + { + + if (this.messages == null) + { + + // This is kind of a false positive since we aren't querying the live db. + return false; + + } + + for (EditorMessage m : this.messages) + { + + if ((m instanceof EditorInfoMessage) + && + (!m.isSentByMe ()) + ) + { + + // It doesn't matter how many times it has been sent. + return true; + + } + + } + + return false; + + } + + public void setOnlineStatus (OnlineStatus status) + { + + this.statusProp.setValue (status); + + } + + public OnlineStatus getOnlineStatus () + { + + return this.statusProp.getValue (); + + } + + public ObjectProperty onlineStatusProperty () + { + + return this.statusProp; + + } + + public void messageUpdated () + { + + this.messagesUpdatedProp.setValue (this.messagesUpdatedProp.getValue () + 1); + + } + + public IntegerProperty messagesUpdatedProperty () + { + + return this.messagesUpdatedProp; + + } + + public boolean messagesLoaded () + { + + return this.messagesLoaded; + + } + + public void removeMessage (EditorMessage m) + { + + if (this.messages == null) + { + + return; + + } + + this.messages.remove (m); + + } + + public void setMessages (Set messages) + { + + this.messages.clear (); + + if (messages != null) + { + + this.messages.addAll (messages); + + } + + this.messagesLoaded = (messages != null); + + } + + public void addMessage (EditorMessage m) + { + + if (this.messagesLoaded) + { + + this.messages.add (m); + + } + + } + + /** + * Get all the messages for the specified accept types (message types). + * + * @param acceptTypes The types of messages we are looking for. + * @param projId Limit to the specified project, if provided. + * @return The matched messages in date created order, or null if no messages match. + */ + public SortedSet getMessages (String projId, + String... acceptTypes) + { + + Set mess = this.getMessages (new DefaultEditorMessageFilter (projId, + acceptTypes)); + + if (mess == null) + { + + return null; + + } + + SortedSet ss = new TreeSet (new Comparator () + { + + @Override + public int compare (EditorMessage m1, + EditorMessage m2) + { + + return m1.getWhen ().compareTo (m2.getWhen ()); + + } + + @Override + public boolean equals (Object o) + { + + return super.equals (o); + + } + + }); + + ss.addAll (mess); + + return ss; + + + } + + public Set getMessages (EditorMessageFilter filter) + { + + Set ret = new LinkedHashSet (); + + if ((this.messages == null) + || + (!this.messagesLoaded) + ) + { + + return ret; + + } + + for (EditorMessage m : this.messages) + { + + if (filter.accept (m)) + { + + ret.add (m); + + } + + } + + return ret; + + } + + public EditorMessage getMessage (String type, + Project forProject) + { + + if ((this.messages == null) + || + (!this.messagesLoaded) + || + (forProject == null) + ) + { + + return null; + + } + + return this.getMessage (type, + forProject.getId ()); + + } + + public EditorMessage getMessage (String type, + String forProjectId) + { + + if ((this.messages == null) + || + (!this.messagesLoaded) + ) + { + + return null; + + } + + for (EditorMessage m : this.messages) + { + + if (m.getMessageType ().equals (type)) + { + + if (m.getForProjectId ().equals (forProjectId)) + { + + return m; + + } + + } + + } + + return null; + + } + + public ObservableSet getMessages () + { + + return this.messages; + + } + + public void setWordCountLengths (Set wcs) + { + + this.wcLengths = wcs; + + } + + public Set getWordCountLengths () + { + + return this.wcLengths; + + } + + public Set getGenres () + { + + return this.genres; + + } + + public void setGenres (Set s) + { + + this.genres = s; + + } + + public Element getAsElement () + { + + Element root = new DefaultElement (XMLConstants.root); + + this.fillElement (root); + + Element about = new DefaultElement (XMLConstants.about); + about.add (new DefaultCDATA (this.about)); + + root.add (about); + + if (this.genres != null) + { + + String gs = Utils.toString (this.genres, + ","); + + if (gs.length () > 0) + { + + root.addAttribute (XMLConstants.genres, + gs); + + } + + } + + if (this.wcLengths != null) + { + + String wcs = Utils.toString (this.wcLengths, + ","); + + if (wcs.length () > 0) + { + + root.addAttribute (XMLConstants.wordCountLengths, + wcs); + + } + + } + + return root; + + } +/* + public String getAvatarImageFileType () + { + + return this.avatarImageFileType; + + } + */ + + public boolean isPending () + { + + if (this.editorStatusProp.getValue () == null) + { + + return false; + + } + + return this.editorStatusProp.getValue () == EditorStatus.pending; + + } + + public boolean isPrevious () + { + + if (this.editorStatusProp.getValue () == null) + { + + return false; + + } + + return this.editorStatusProp.getValue () == EditorStatus.previous; + + } + + public boolean isRejected () + { + + if (this.editorStatusProp.getValue () == null) + { + + return false; + + } + + return this.editorStatusProp.getValue () == EditorStatus.rejected; + + } + + public boolean isCurrent () + { + + if (this.editorStatusProp.getValue () == null) + { + + return false; + + } + + return this.editorStatusProp.getValue () == EditorStatus.current; + + } + + public boolean isOffline () + { + + if (this.statusProp.getValue () == null) + { + + return true; + + } + + return this.statusProp.getValue () == OnlineStatus.offline; + + } + + public void setAvatar (Image im) + { + + this.avatarProp.setValue (im); + + } + + public ObjectProperty mainAvatarProperty () + { + + return this.mainAvatarProp; + + } +/* + public ObjectProperty avatarProperty () + { + + return this.avatarProp; + + } +*/ + public void setMyAvatarForEditor (Image im) + { + + this.myAvatarForEditorProp.setValue (im); + + } + + public Image getMyAvatarForEditor () + { + + return this.myAvatarForEditorProp.getValue (); + + } + + /* + public File getAvatarImage () + { + + return Environment.getEditorsEditorAvatarImageFile (); + + } + */ + public String getAbout () + { + + return this.about; + + } + + public void setAbout (String a) + { + + this.about = a; + + } + +} diff --git a/src/com/quollwriter/data/editors/EditorProject.java b/src/main/java/com/quollwriter/data/editors/EditorProject.java similarity index 100% rename from src/com/quollwriter/data/editors/EditorProject.java rename to src/main/java/com/quollwriter/data/editors/EditorProject.java diff --git a/src/com/quollwriter/data/editors/Invite.java b/src/main/java/com/quollwriter/data/editors/Invite.java similarity index 100% rename from src/com/quollwriter/data/editors/Invite.java rename to src/main/java/com/quollwriter/data/editors/Invite.java diff --git a/src/main/java/com/quollwriter/data/editors/ProjectEditor.java b/src/main/java/com/quollwriter/data/editors/ProjectEditor.java new file mode 100644 index 00000000..5d988493 --- /dev/null +++ b/src/main/java/com/quollwriter/data/editors/ProjectEditor.java @@ -0,0 +1,359 @@ +package com.quollwriter.data.editors; + +import java.util.*; +import javafx.beans.property.*; + +import com.quollwriter.*; +import com.quollwriter.uistrings.*; +import com.quollwriter.data.*; + +import static com.quollwriter.uistrings.UILanguageStringsManager.getUILanguageStringProperty; + +/** + * Models an editor for a project. + */ +public class ProjectEditor extends DataObject implements Comparable +{ + + public static final String OBJECT_TYPE = "projecteditor"; + + public enum Status + { + + invited ("invited"), + accepted ("accepted"); + + private String type = null; + + Status (String type) + { + + this.type = type; + + } + + public String getType () + { + + return this.type; + + } + + } + + protected EditorEditor editor = null; + private String forProjectId = null; + private String forProjectName = null; + private ObjectProperty statusProp = new SimpleObjectProperty (); + private StringProperty statusMessageProp = null; + private Date from = null; + private Date to = null; + private BooleanProperty currentProp = new SimpleBooleanProperty (false); + private ObjectProperty> statusString = null; + private ObjectProperty> statusStringParms = null; + + public ProjectEditor () + { + + super (OBJECT_TYPE); + + this.statusString = new SimpleObjectProperty (new ArrayList<> ()); + this.statusStringParms = new SimpleObjectProperty (new ArrayList<> ()); + + this.statusMessageProp = new SimpleStringProperty (); + this.statusMessageProp.bind (UILanguageStringsManager.createStringBinding (() -> + { + + if ((this.statusString.getValue () == null) + || + (this.statusString.getValue ().size () == 0) + ) + { + + return ""; + + } + + return getUILanguageStringProperty (this.statusString.getValue (), + (this.statusStringParms.getValue () != null ? this.statusStringParms.getValue ().toArray () : null)).getValue (); + + }, + this.statusString)); + + } + + public ProjectEditor (Project proj, + EditorEditor editor) + { + + this (); + + this.forProjectId = proj.getId (); + this.forProjectName = proj.getName (); + this.editor = editor; + + } + + @Override + public void fillToStringProperties (Map props) + { + + super.fillToStringProperties (props); + + this.addToStringProperties (props, + "forProjectId", + this.forProjectId); + this.addToStringProperties (props, + "forProjectName", + this.forProjectName); + this.addToStringProperties (props, + "editor", + this.editor); + this.addToStringProperties (props, + "current", + this.currentProp.getValue ()); + this.addToStringProperties (props, + "statusMessage", + this.statusMessageProp.getValue ()); + this.addToStringProperties (props, + "from", + this.from); + this.addToStringProperties (props, + "to", + this.to); + + } + + public int compareTo (ProjectEditor pe) + { + + return this.editor.getMainName ().compareTo (pe.editor.getMainName ()); + + } + + public boolean isPrevious () + { + + return this.to != null; + + } + + public boolean isInvited () + { + + if (this.statusProp.getValue () == null) + { + + return true; + + } + + return this.statusProp.getValue () == Status.invited; + + } + + public Status getStatus () + { + + return this.statusProp.getValue (); + + } + + public void setStatus (Status s) + { + + this.statusProp.setValue (s); + + } + + public ObjectProperty statusProperty () + { + + return this.statusProp; + + } + + public void setForProjectName (String n) + { + + this.forProjectName = n; + + } + + public String getForProjectName () + { + + return this.forProjectName; + + } + + public DataObject getObjectForReference (ObjectReference r) + { + + return null; + + } + + public void setForProjectId (String id) + { + + this.forProjectId = id; + + } + + public String getForProjectId () + { + + return this.forProjectId; + + } + + public void setCurrent (boolean v) + { + + this.currentProp.setValue (v); + + } + + public boolean isCurrent () + { + + return this.currentProp.getValue (); + + } + + public BooleanProperty currentProperty () + { + + return this.currentProp; + + } + + public void setEditorTo (Date d) + { + + this.to = d; + this.currentProp.setValue (false); + + } + + public Date getEditorTo () + { + + return this.to; + + } + + public void setEditorFrom (Date d) + { + + this.from = d; + + } + + public Date getEditorFrom () + { + + return this.from; + + } + + public StringProperty statusMessageProperty () + { + + return this.statusMessageProp; + + } + + public void setStatusMessage (List str, + List parms) + { + + this.statusStringParms.setValue (parms); + this.statusString.setValue (str); + + } + + public void setStatusMessage (String s) + { + + if (s == null) + { + + return; + + } + + // Eeek! + if (s.startsWith ("{")) + { + + try + { + + Map m = (Map) JSONDecoder.decode (s); + Object str = m.get ("str"); + + Object p = m.get ("parms"); + + if ((p != null) + && + (p instanceof List) + ) + { + + this.statusStringParms.setValue ((List) p); + + } + + if (str instanceof List) + { + + this.statusString.setValue ((List) str); + + } + + } catch (Exception e) { + + this.statusString.setValue (Arrays.asList ("")); + + } + + } else { + + // Legacy, pre v3. + this.statusString.setValue (Arrays.asList (s)); + + } + + } + + public String getStatusMessage () + throws GeneralException + { + + Map m = new HashMap (); + m.put ("str", + this.statusString.getValue ()); + m.put ("parms", + this.statusStringParms.getValue ()); + + return JSONEncoder.encode (m); + + } + + public void setEditor (EditorEditor ed) + { + + this.editor = ed; + + } + + public EditorEditor getEditor () + { + + return this.editor; + + } + +} diff --git a/src/com/quollwriter/db/AssetDataHandler.java b/src/main/java/com/quollwriter/db/AssetDataHandler.java similarity index 86% rename from src/com/quollwriter/db/AssetDataHandler.java rename to src/main/java/com/quollwriter/db/AssetDataHandler.java index ed425045..cf289c10 100644 --- a/src/com/quollwriter/db/AssetDataHandler.java +++ b/src/main/java/com/quollwriter/db/AssetDataHandler.java @@ -12,7 +12,7 @@ public class AssetDataHandler implements DataHandler { private static final String STD_SELECT_PREFIX = "SELECT dbkey, userobjecttypedbkey, name, description, markup, files, lastmodified, datecreated, properties, id, version FROM asset_v "; - + private ObjectManager objectManager = null; public AssetDataHandler (ObjectManager om) @@ -34,33 +34,33 @@ private Asset getAsset (ResultSet rs, int ind = 1; long key = rs.getLong (ind++); - + long typekey = rs.getLong (ind++); - + UserConfigurableObjectType t = (UserConfigurableObjectType) Environment.getUserConfigurableObjectType (typekey); if (t == null) { - + // This isn't an error, the type may have been removed without the requesting project knowing about // the deletion. return null; - + } - + Asset f = new Asset (t); - + f.setKey (key); - + // Load the object fields. this.objectManager.setUserConfigurableObjectFields (f, rs.getStatement ().getConnection ()); - + f.setName (rs.getString (ind++)); f.setDescription (new StringWithMarkup (rs.getString (ind++), rs.getString (ind++))); - - f.setFiles (Utils.getFilesFromXML (rs.getString (ind++))); + + f.setFiles (Utils.getFilesFromXML (rs.getString (ind++))); f.setLastModified (rs.getTimestamp (ind++)); f.setDateCreated (rs.getTimestamp (ind++)); f.setPropertiesAsString (rs.getString (ind++)); @@ -71,17 +71,17 @@ private Asset getAsset (ResultSet rs, // Get all the notes. if (loadChildObjects) { - + this.objectManager.loadNotes (f, rs.getStatement ().getConnection ()); - + } - + if (parent != null) { - + parent.addAsset (f); - + } return f; @@ -102,12 +102,12 @@ public List getObjects (Project parent, throws GeneralException { - List ret = new ArrayList (); + List ret = new ArrayList<> (); try { - List params = new ArrayList (); + List params = new ArrayList<> (); ResultSet rs = this.objectManager.executeQuery (STD_SELECT_PREFIX + " WHERE latest = TRUE", params, @@ -124,11 +124,11 @@ public List getObjects (Project parent, if (f != null) { - - ret.add (f); - + + ret.add (f); + } - + } try @@ -148,7 +148,7 @@ public List getObjects (Project parent, e); } - + return ret; } @@ -165,7 +165,7 @@ public Asset getObjectByKey (long key, try { - List params = new ArrayList (); + List params = new ArrayList<> (); params.add (key); ResultSet rs = this.objectManager.executeQuery (STD_SELECT_PREFIX + " WHERE latest = TRUE AND dbkey = ?", @@ -207,10 +207,10 @@ public void createObject (Asset t, Connection conn) throws GeneralException { - - List params = new ArrayList (); + + List params = new ArrayList<> (); params.add (t.getKey ()); - + this.objectManager.executeStatement ("INSERT INTO asset (dbkey) VALUES (?)", params, conn); @@ -218,12 +218,12 @@ public void createObject (Asset t, } public void deleteObject (Asset t, - boolean deleteChildObjects, + boolean deleteChildObjects, Connection conn) throws GeneralException { - List params = new ArrayList (); + List params = new ArrayList<> (); params.add (t.getKey ()); this.objectManager.executeStatement ("DELETE FROM asset WHERE dbkey = ?", @@ -238,7 +238,7 @@ public void updateObject (Asset t, { // Nothing to do... - + } } diff --git a/src/com/quollwriter/db/BookDataHandler.java b/src/main/java/com/quollwriter/db/BookDataHandler.java similarity index 92% rename from src/com/quollwriter/db/BookDataHandler.java rename to src/main/java/com/quollwriter/db/BookDataHandler.java index 284e0f53..7adc5ca2 100644 --- a/src/com/quollwriter/db/BookDataHandler.java +++ b/src/main/java/com/quollwriter/db/BookDataHandler.java @@ -39,7 +39,7 @@ private Book getBook (ResultSet rs, b.setName (rs.getString (ind++)); b.setKey (key); - + b.setDescription (new StringWithMarkup (rs.getString (ind++), rs.getString (ind++))); @@ -51,23 +51,23 @@ private Book getBook (ResultSet rs, if (p != null) { - + p.addBook (b); - + } if (loadChildObjects) { - + Connection conn = rs.getStatement ().getConnection (); - + this.objectManager.getObjects (Chapter.class, b, conn, loadChildObjects); } - + return b; } catch (Exception e) @@ -87,36 +87,36 @@ public List getObjects (Project parent, throws GeneralException { - List ret = new ArrayList (); - + List ret = new ArrayList<> (); + try { - + ResultSet rs = this.objectManager.executeQuery (STD_SELECT_PREFIX + " WHERE latest = TRUE", null, conn); - + while (rs.next ()) { - + ret.add (this.getBook (rs, parent, loadChildObjects)); - + } - + rs.close (); return ret; - + } catch (Exception e) { - + throw new GeneralException ("Unable to get books for project: " + parent, e); - + } - + } @Override @@ -126,36 +126,36 @@ public Book getObjectByKey (long key, boolean loadChildObjects) throws GeneralException { - + try { - - List params = new ArrayList (); + + List params = new ArrayList<> (); params.add (key); - + ResultSet rs = this.objectManager.executeQuery (STD_SELECT_PREFIX + "WHERE dbkey = ?", params, conn); - + if (rs.next ()) { - + return this.getBook (rs, proj, loadChildObjects); - + } - + return null; - + } catch (Exception e) { - + throw new GeneralException ("Unable to get book for key: " + key, e); - + } - + } public void updateChapterIndexes (Book b, @@ -163,7 +163,7 @@ public void updateChapterIndexes (Book b, throws GeneralException { - List params = new ArrayList (); + List params = new ArrayList<> (); params.add (null); params.add (null); params.add (b.getKey ()); @@ -190,7 +190,7 @@ public void createObject (Book b, throws GeneralException { - List params = new ArrayList (); + List params = new ArrayList<> (); params.add (b.getKey ()); params.add (b.getProject ().getKey ()); params.add (b.getProject ().getBookIndex (b)); @@ -226,7 +226,7 @@ public void deleteObject (Book b, } - List params = new ArrayList (); + List params = new ArrayList<> (); params.add (b.getKey ()); this.objectManager.executeStatement ("DELETE FROM book WHERE dbkey = ?", @@ -241,7 +241,7 @@ public void updateObject (Book b, throws GeneralException { - List params = new ArrayList (); + List params = new ArrayList<> (); params.add (b.getProject ().getBookIndex (b)); params.add (b.getKey ()); diff --git a/src/com/quollwriter/db/ChapterDataHandler.java b/src/main/java/com/quollwriter/db/ChapterDataHandler.java similarity index 95% rename from src/com/quollwriter/db/ChapterDataHandler.java rename to src/main/java/com/quollwriter/db/ChapterDataHandler.java index e24a7966..1d74ae3d 100644 --- a/src/com/quollwriter/db/ChapterDataHandler.java +++ b/src/main/java/com/quollwriter/db/ChapterDataHandler.java @@ -32,7 +32,7 @@ private void deleteProblemFinderIgnores (Chapter c, throws GeneralException { - List params = new ArrayList (); + List params = new ArrayList<> (); params.add (c.getKey ()); this.objectManager.executeStatement ("DELETE FROM problemfinderignore WHERE chapterdbkey = ?", @@ -66,7 +66,7 @@ public void saveProblemFinderIgnores (Chapter c, for (Issue iss : c.getProblemFinderIgnores ()) { - List params = new ArrayList (); + List params = new ArrayList<> (); params.add (c.getKey ()); params.add (iss.getRuleId ()); params.add (iss.getIssueId ()); @@ -117,7 +117,7 @@ private Set getProblemFinderIgnores (Chapter c, throws GeneralException { - Set ret = new HashSet (); //new TreeSet (new IssueSorter ()); + Set ret = new HashSet<> (); //new TreeSet (new IssueSorter ()); boolean releaseConn = false; @@ -132,7 +132,7 @@ private Set getProblemFinderIgnores (Chapter c, try { - List params = new ArrayList (); + List params = new ArrayList<> (); params.add (c.getKey ()); ResultSet rs = this.objectManager.executeQuery ("SELECT ruleid, startposition, wordposition, issueid FROM problemfinderignore WHERE chapterdbkey = ? ORDER BY startposition, wordposition", @@ -228,14 +228,14 @@ private Chapter getChapter (ResultSet rs, long key = rs.getInt (ind++); long userObjTypeKey = rs.getLong (ind++); - + Chapter c = new Chapter (); c.setKey (key); - + // Load the object fields. this.objectManager.setUserConfigurableObjectFields (c, rs.getStatement ().getConnection ()); - + c.setName (rs.getString (ind++)); c.setDescription (new StringWithMarkup (rs.getString (ind++), @@ -257,7 +257,7 @@ private Chapter getChapter (ResultSet rs, c.setPlan (new StringWithMarkup (rs.getString (ind++), rs.getString (ind++))); c.setEditPosition (rs.getInt (ind++)); - + // Ensure that the edit position is valid (not sure why this can happen). // If it's not then set it to the end of the text. if ((c.getEditPosition () > 0) @@ -267,11 +267,11 @@ private Chapter getChapter (ResultSet rs, (c.getEditPosition () > c.getText ().getText ().length ()) ) { - + c.setEditPosition (c.getText ().getText ().length ()); - + } - + c.setEditComplete (rs.getBoolean (ind++)); c.setId (rs.getString (ind++)); c.setVersion (rs.getString (ind++)); @@ -283,7 +283,7 @@ private Chapter getChapter (ResultSet rs, book.addChapter (c); } - + c.setProblemFinderIgnores (this.getProblemFinderIgnores (c, null, rs.getStatement ().getConnection ())); @@ -345,7 +345,7 @@ public Set getChaptersForVersion (ProjectVersion pv, throws GeneralException { - Set ret = new LinkedHashSet (); + Set ret = new LinkedHashSet<> (); boolean closeConn = false; @@ -361,7 +361,7 @@ public Set getChaptersForVersion (ProjectVersion pv, try { - List params = new ArrayList (); + List params = new ArrayList<> (); params.add (pv.getKey ()); ResultSet rs = this.objectManager.executeQuery (STD_SELECT_PREFIX + " WHERE projectversiondbkey = ? ORDER BY index", @@ -407,7 +407,7 @@ public Set getVersionedChapters (Collection chaps) throws Exception { - List params = new ArrayList (); + List params = new ArrayList<> (); StringBuilder b = new StringBuilder (); @@ -428,7 +428,7 @@ public Set getVersionedChapters (Collection chaps) } - Set ret = new LinkedHashSet (); + Set ret = new LinkedHashSet<> (); Connection conn = null; @@ -495,7 +495,7 @@ public List getObjects (Book book, try { - List ret = new ArrayList (); + List ret = new ArrayList<> (); ResultSet rs = this.objectManager.executeQuery (STD_SELECT_PREFIX + "WHERE latest = TRUE ORDER BY index", null, @@ -534,7 +534,7 @@ public Chapter getObjectByKey (long key, try { - List params = new ArrayList (); + List params = new ArrayList<> (); params.add (key); ResultSet rs = this.objectManager.executeQuery (STD_SELECT_PREFIX + "WHERE dbkey = ?", @@ -581,14 +581,14 @@ public void saveWordCounts (Project project, try { - List wcs = new ArrayList (); + List wcs = new ArrayList<> (); conn = this.objectManager.getConnection (); - start = Environment.zeroTimeFieldsForDate (start); - end = Environment.zeroTimeFieldsForDate (end); + start = Utils.zeroTimeFieldsForDate (start); + end = Utils.zeroTimeFieldsForDate (end); - List params = new ArrayList (); + List params = new ArrayList<> (); params.add (start); params.add (project.getKey ()); @@ -604,12 +604,12 @@ public void saveWordCounts (Project project, ChapterCounts cc = new ChapterCounts (c.getChapterText ()); - params = new ArrayList (); + params = new ArrayList<> (); params.add (project.getKey ()); params.add (c.getKey ()); - params.add (cc.wordCount); + params.add (cc.getWordCount ()); params.add (start); params.add (end); @@ -660,7 +660,7 @@ public List getWordCounts (Chapter ch, conn = this.objectManager.getConnection (); - List params = new ArrayList (); + List params = new ArrayList<> (); params.add (ch.getKey ()); params.add (ch.getBook ().getProject ().getKey ()); @@ -678,7 +678,7 @@ public List getWordCounts (Chapter ch, params, conn); - List ret = new ArrayList (); + List ret = new ArrayList<> (); while (rs.next ()) { @@ -721,7 +721,7 @@ public void createObject (Chapter c, throws GeneralException { - List params = new ArrayList (); + List params = new ArrayList<> (); params.add (c.getKey ()); params.add (c.getBook ().getKey ()); @@ -827,7 +827,7 @@ public Set snapshot (Set chapters, } - Set newChapters = new LinkedHashSet (); + Set newChapters = new LinkedHashSet<> (); Connection conn = null; @@ -898,7 +898,7 @@ public Chapter getChapterById (String id, try { - List params = new ArrayList (); + List params = new ArrayList<> (); params.add (id); ResultSet rs = this.objectManager.executeQuery (STD_SELECT_PREFIX + " WHERE id = ?", @@ -942,7 +942,7 @@ public Set updateToNewVersions (ProjectVersion pv, throws GeneralException { - Set newChapters = new LinkedHashSet (); + Set newChapters = new LinkedHashSet<> (); Connection conn = null; @@ -960,14 +960,14 @@ public Set updateToNewVersions (ProjectVersion pv, } // Need to set all existing chapters to be not the latest. - List params = new ArrayList (); + List params = new ArrayList<> (); params.add (Chapter.OBJECT_TYPE); this.objectManager.executeStatement ("UPDATE dataobject SET latest = FALSE WHERE objecttype = ? AND dbkey IN (SELECT dbkey FROM chapter)", params, conn); - final List chaps = new ArrayList (chapters); + final List chaps = new ArrayList<> (chapters); // TODO: Handle multiple books. This is "ok" for now, i.e. assume a single book. Book b = this.objectManager.getProject ().getBook (0); @@ -1161,7 +1161,7 @@ public void deleteObject (Chapter c, if (!c.isLatest ()) { - List params = new ArrayList (); + List params = new ArrayList<> (); params.add (c.getKey ()); this.objectManager.executeStatement ("DELETE FROM chapter WHERE dbkey = ?", @@ -1172,7 +1172,7 @@ public void deleteObject (Chapter c, } - List params = new ArrayList (); + List params = new ArrayList<> (); params.add (c.getId ()); try @@ -1227,7 +1227,7 @@ public void deleteObject (Chapter c, this.deleteProblemFinderIgnores (c, conn); - params = new ArrayList (); + params = new ArrayList<> (); params.add (c.getKey ()); // Delete the word counts. @@ -1265,7 +1265,7 @@ public void updateObject (Chapter c, } - List params = new ArrayList (); + List params = new ArrayList<> (); params.add (t); params.add (m); params.add (c.getBook ().getChapterIndex (c)); diff --git a/src/com/quollwriter/db/CharacterDataHandler.java b/src/main/java/com/quollwriter/db/CharacterDataHandler.java similarity index 91% rename from src/com/quollwriter/db/CharacterDataHandler.java rename to src/main/java/com/quollwriter/db/CharacterDataHandler.java index ae0ddf04..51746774 100644 --- a/src/com/quollwriter/db/CharacterDataHandler.java +++ b/src/main/java/com/quollwriter/db/CharacterDataHandler.java @@ -39,15 +39,15 @@ private QCharacter getCharacter (ResultSet rs, long key = rs.getLong (ind++); c.setKey (key); - + // Load the object fields. this.objectManager.setUserConfigurableObjectFields (c, rs.getStatement ().getConnection ()); - + c.setName (rs.getString (ind++)); c.setDescription (new StringWithMarkup (rs.getString (ind++), rs.getString (ind++))); - + c.setFiles (Utils.getFilesFromXML (rs.getString (ind++))); c.setLastModified (rs.getTimestamp (ind++)); @@ -57,32 +57,32 @@ private QCharacter getCharacter (ResultSet rs, // Handle the legacy value. if (c.getLegacyField (QCharacter.ALIASES_LEGACY_FIELD_ID) == null) { - + c.setAliases (rs.getString (ind++)); - + } else { - + ind++; - + } c.setId (rs.getString (ind++)); - c.setVersion (rs.getString (ind++)); - + c.setVersion (rs.getString (ind++)); + if (p != null) { p.addAsset (c); - + } - + // Get all the notes. if (loadChildObjects) { - + this.objectManager.loadNotes (c, rs.getStatement ().getConnection ()); - + } return c; @@ -103,12 +103,12 @@ public List getObjects (Project parent, throws GeneralException { - List ret = new ArrayList (); + List ret = new ArrayList<> (); try { - List params = new ArrayList (); + List params = new ArrayList<> (); params.add (parent.getKey ()); ResultSet rs = this.objectManager.executeQuery (STD_SELECT_PREFIX + " WHERE latest = TRUE AND projectdbkey = ?", @@ -158,7 +158,7 @@ public QCharacter getObjectByKey (long key, try { - List params = new ArrayList (); + List params = new ArrayList<> (); params.add (key); //params.add (proj.getKey ()); @@ -204,7 +204,7 @@ public void createObject (QCharacter d, QCharacter c = (QCharacter) d; - List params = new ArrayList (); + List params = new ArrayList<> (); params.add (c.getKey ()); params.add (c.getAliases ()); params.add (c.getProject ().getKey ()); @@ -223,7 +223,7 @@ public void deleteObject (QCharacter d, QCharacter c = (QCharacter) d; - List params = new ArrayList (); + List params = new ArrayList<> (); params.add (c.getKey ()); this.objectManager.executeStatement ("DELETE FROM character WHERE dbkey = ?", @@ -239,14 +239,14 @@ public void updateObject (QCharacter d, QCharacter c = (QCharacter) d; - List params = new ArrayList (); + List params = new ArrayList<> (); params.add (c.getAliases ()); params.add (c.getKey ()); - + this.objectManager.executeStatement ("UPDATE character SET aliases = ? WHERE dbkey = ?", params, conn); - + } } diff --git a/src/com/quollwriter/db/DataHandler.java b/src/main/java/com/quollwriter/db/DataHandler.java similarity index 100% rename from src/com/quollwriter/db/DataHandler.java rename to src/main/java/com/quollwriter/db/DataHandler.java diff --git a/src/com/quollwriter/db/EditorEditorDataHandler.java b/src/main/java/com/quollwriter/db/EditorEditorDataHandler.java similarity index 85% rename from src/com/quollwriter/db/EditorEditorDataHandler.java rename to src/main/java/com/quollwriter/db/EditorEditorDataHandler.java index 2ef888ef..b3032bed 100644 --- a/src/com/quollwriter/db/EditorEditorDataHandler.java +++ b/src/main/java/com/quollwriter/db/EditorEditorDataHandler.java @@ -16,7 +16,7 @@ import com.quollwriter.*; -import com.quollwriter.ui.*; +import com.quollwriter.ui.fx.*; import com.quollwriter.data.*; import com.quollwriter.data.editors.*; import com.quollwriter.editors.*; @@ -24,7 +24,7 @@ public class EditorEditorDataHandler implements DataHandler { - private static final String STD_SELECT_PREFIX = "SELECT dbkey, email, name, mynameforeditor, avatarimage, myavatarimageforeditor, status, invitedbyme, theirpublickey, id, messagingusername, servicename FROM editor_v"; + private static final String STD_SELECT_PREFIX = "SELECT dbkey, email, name, mynameforeditor, avatarimage, myavatarimageforeditor, status, invitedbyme, lastmodified, datecreated, properties, theirpublickey, id, messagingusername, servicename FROM editor_v"; private ObjectManager objectManager = null; @@ -32,89 +32,89 @@ public class EditorEditorDataHandler implements DataHandler multiple viewers. */ - private Map cache = new HashMap (); - + private Map cache = new HashMap (); + public EditorEditorDataHandler (ObjectManager om) { this.objectManager = om; } - + @Override public void createObject (EditorEditor ed, Connection conn) throws GeneralException { - + /* try { - + PGPKeyPair pair = this.generateKeyPair (); - + ed.setMyPublicKey (pair.getPublicKey ()); ed.setMyPrivateKey (pair.getPrivateKey ()); - + } catch (Exception e) { - + throw new GeneralException ("Unable to generate key pair for editor: " + ed, e); - + } - */ - List params = new ArrayList (); + */ + List params = new ArrayList<> (); params.add (ed.getKey ()); params.add (ed.getEmail ()); params.add (ed.getEditorStatus ().getType ()); params.add (ed.isInvitedByMe ()); - + try { - - params.add (UIUtils.getImageBytes (ed.getAvatar ())); - + + params.add (UIUtils.getImageBytes (ed.getMainAvatar ())); + } catch (Exception e) { - + params.add (null); - + Environment.logError ("Unable to get image bytes for avatar for editor: " + ed); - - } - + + } + if (ed.getTheirPublicKey () != null) { - + try { params.add (EditorsUtils.getPGPPublicKeyByteEncoded (ed.getTheirPublicKey ())); - + } catch (Exception e) { - + throw new GeneralException ("Unable to encode public key", e); - + } - + } else { - + params.add (null); - + } - + params.add (ed.getMessagingUsername ()); params.add (ed.getServiceName ()); - + this.objectManager.executeStatement ("INSERT INTO editor (dbkey, email, status, invitedbyme, avatarimage, theirpublickey, messagingusername, servicename) VALUES (?, ?, ?, ?, ?, ?, ?, ?)", params, - conn); - + conn); + this.cache.put (ed.getKey (), ed); - + } @Override @@ -123,16 +123,16 @@ public void deleteObject (EditorEditor d, Connection conn) throws GeneralException { - - List params = new ArrayList (); + + List params = new ArrayList<> (); params.add (d.getKey ()); - + this.objectManager.executeStatement ("DELETE FROM editor WHERE dbkey = ?", params, conn); - + this.cache.remove (d.getKey ()); - + } @Override @@ -140,8 +140,8 @@ public void updateObject (EditorEditor ed, Connection conn) throws GeneralException { - - List params = new ArrayList (); + + List params = new ArrayList<> (); params.add (ed.getEditorStatus ().getType ()); // May not exist if the editor is rejected. @@ -151,50 +151,50 @@ public void updateObject (EditorEditor ed, //params.add (((RSAPublicBCPGKey) ed.getTheirPublicKey ().getPublicKeyPacket ().getKey ()).getEncoded ()); try { - + params.add (EditorsUtils.getPGPPublicKeyByteEncoded (ed.getTheirPublicKey ())); - + } catch (Exception e) { - + throw new GeneralException ("Unable to encode public key", e); - + } - + } else { - + params.add (null); - + } - + params.add (ed.getMyNameForEditor ()); - + try { - - params.add (UIUtils.getImageBytes (ed.getAvatar ())); - + + params.add (UIUtils.getImageBytes (ed.getMainAvatar ())); + } catch (Exception e) { - + params.add (null); - + Environment.logError ("Unable to get image bytes for avatar for editor: " + ed); - + } - + try { - + params.add (UIUtils.getImageBytes (ed.getMyAvatarForEditor ())); - + } catch (Exception e) { - + params.add (null); - + Environment.logError ("Unable to get image bytes for my avatar for editor: " + ed); - + } params.add (ed.getMessagingUsername ()); @@ -204,7 +204,7 @@ public void updateObject (EditorEditor ed, this.objectManager.executeStatement ("UPDATE editor SET status = ?, theirpublickey = ?, mynameforeditor = ?, avatarimage = ?, myavatarimageforeditor = ?, messagingusername = ?, servicename = ? WHERE dbkey = ?", params, conn); - + } @Override @@ -213,15 +213,15 @@ public List getObjects (NamedObject parent, boolean loadChildObjects) throws GeneralException { - - List ret = new ArrayList (); + + List ret = new ArrayList<> (); try { //List params = new ArrayList (); //params.add (EditorEditor.EditorStatus.rejected.getType ()); - + ResultSet rs = this.objectManager.executeQuery (STD_SELECT_PREFIX,// + " WHERE status != ?", null, conn); @@ -252,10 +252,10 @@ public List getObjects (NamedObject parent, } return ret; - + } - + private EditorEditor getEditor (ResultSet rs) throws GeneralException { @@ -268,48 +268,53 @@ private EditorEditor getEditor (ResultSet rs) long key = rs.getLong (ind++); EditorEditor ed = new EditorEditor (); - + ed.setKey (key); ed.setEmail (rs.getString (ind++)); ed.setName (rs.getString (ind++)); ed.setMyNameForEditor (rs.getString (ind++)); - + ed.setAvatar (UIUtils.getImage (rs.getBytes (ind++))); - + // My avatar image for the editor. ed.setMyAvatarForEditor (UIUtils.getImage (rs.getBytes (ind++))); ed.setEditorStatus (EditorEditor.EditorStatus.valueOf (rs.getString (ind++))); ed.setInvitedByMe (rs.getBoolean (ind++)); + + ed.setLastModified (rs.getTimestamp (ind++)); + ed.setDateCreated (rs.getTimestamp (ind++)); + ed.setPropertiesAsString (rs.getString (ind++)); + /* // My private key. byte[] bytes = rs.getBytes (ind++); - + // My public key. ed.setMyPublicKey (EditorsUtils.convertToPGPPublicKey (rs.getBytes (ind++))); if (bytes != null) { - + ByteArrayInputStream bin = new ByteArrayInputStream (bytes); - - RSASecretBCPGKey nprivKey = new RSASecretBCPGKey (new BCPGInputStream (bin)); - + + RSASecretBCPGKey nprivKey = new RSASecretBCPGKey (new BCPGInputStream (bin)); + ed.setMyPrivateKey (new PGPPrivateKey (1, ed.getMyPublicKey ().getPublicKeyPacket (), nprivKey)); } - */ + */ // Their public key ed.setTheirPublicKey (EditorsUtils.convertToPGPPublicKey (rs.getBytes (ind++))); ed.setId (rs.getString (ind++)); ed.setMessagingUsername (rs.getString (ind++)); ed.setServiceName (rs.getString (ind++)); - + this.cache.put (ed.getKey (), ed); - + return ed; } catch (Exception e) @@ -319,9 +324,9 @@ private EditorEditor getEditor (ResultSet rs) e); } - + } - + @Override public EditorEditor getObjectByKey (long key, NamedObject parent, @@ -329,15 +334,15 @@ public EditorEditor getObjectByKey (long key, boolean loadChildObjects) throws GeneralException { - + ResultSet rs = null; try { - - List params = new ArrayList (); + + List params = new ArrayList<> (); params.add (key); - + rs = this.objectManager.executeQuery (STD_SELECT_PREFIX + " WHERE dbkey = ?", params, conn); @@ -378,7 +383,7 @@ public EditorEditor getObjectByKey (long key, } } - + } } diff --git a/src/com/quollwriter/db/EditorMessageDataHandler.java b/src/main/java/com/quollwriter/db/EditorMessageDataHandler.java similarity index 85% rename from src/com/quollwriter/db/EditorMessageDataHandler.java rename to src/main/java/com/quollwriter/db/EditorMessageDataHandler.java index d9a123d4..c67b7c9f 100644 --- a/src/com/quollwriter/db/EditorMessageDataHandler.java +++ b/src/main/java/com/quollwriter/db/EditorMessageDataHandler.java @@ -27,44 +27,44 @@ public class EditorMessageDataHandler implements DataHandler multiple viewers. */ private Map messageCache = new HashMap (); - + public EditorMessageDataHandler (ObjectManager om) { this.objectManager = om; } - + @Override public void createObject (EditorMessage m, Connection conn) throws GeneralException { - + if ((m.getOriginalMessage () == null) && (m.isEncrypted ()) ) { - + throw new GeneralException ("Cannot save a message where the original, encrypted message is not available."); - + } - + if (m.getEditor () == null) { - + throw new GeneralException ("Cannot save a message where no editor is available."); - + } - - List params = new ArrayList (); + + List params = new ArrayList<> (); params.add (m.getKey ()); params.add (m.getWhen ()); params.add (m.getMessageType ()); @@ -75,14 +75,14 @@ public void createObject (EditorMessage m, params.add (m.getMessage ()); params.add (m.getOriginalMessage ()); params.add (m.isDealtWith ()); - + this.objectManager.executeStatement ("INSERT INTO message (dbkey, when, type, sentbyme, editordbkey, forprojectid, messageid, message, origmessage, dealtwith) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", params, - conn); + conn); this.messageCache.put (m.getKey (), m); - + } @Override @@ -91,16 +91,16 @@ public void deleteObject (EditorMessage d, Connection conn) throws GeneralException { - - List params = new ArrayList (); + + List params = new ArrayList<> (); params.add (d.getKey ()); - + this.objectManager.executeStatement ("DELETE FROM message WHERE dbkey = ?", params, conn); this.messageCache.remove (d.getKey ()); - + } @Override @@ -108,17 +108,17 @@ public void updateObject (EditorMessage m, Connection conn) throws GeneralException { - - List params = new ArrayList (); + + List params = new ArrayList<> (); params.add (m.getMessage ()); params.add (m.isDealtWith ()); params.add (m.getKey ()); - + this.objectManager.executeStatement ("UPDATE message SET message = ?, dealtwith = ? WHERE dbkey = ?", params, - conn); - + conn); + } public boolean hasSentMessageOfTypeToEditor (EditorEditor ed, @@ -128,33 +128,33 @@ public boolean hasSentMessageOfTypeToEditor (EditorEditor ed, // Ugh... so sick of this type of get connection, do something, release connection! Connection conn = null; - + try { conn = this.objectManager.getConnection (); - List params = new ArrayList (); + List params = new ArrayList<> (); params.add (ed.getKey ()); params.add (messageType); - + ResultSet rs = this.objectManager.executeQuery ("SELECT type FROM message_v WHERE editordbkey = ? AND sentbyme = TRUE AND type = ?", params, conn); if (rs.next ()) { - + // Using the type here rather than the key because of stupid java Long/long ambiguities. if (rs.getString (1) != null) { - + return true; - + } - + } - + } catch (Exception e) { this.objectManager.throwException (conn, @@ -165,50 +165,50 @@ public boolean hasSentMessageOfTypeToEditor (EditorEditor ed, e); } finally { - + this.objectManager.releaseConnection (conn); - - } + + } return false; - + } - + public boolean hasEditorSentInfo (EditorEditor ed) throws GeneralException { - + // Ugh... so sick of this type of get connection, do something, release connection! Connection conn = null; - + ResultSet rs = null; - + try { conn = this.objectManager.getConnection (); - List params = new ArrayList (); + List params = new ArrayList<> (); params.add (ed.getKey ()); params.add (EditorInfoMessage.MESSAGE_TYPE); - + rs = this.objectManager.executeQuery ("SELECT type FROM message_v WHERE editordbkey = ? AND sentbyme = FALSE AND type = ?", params, conn); if (rs.next ()) { - + // Using the type here rather than the key because of stupid java Long/long ambiguities. if (rs.getString (1) != null) { - + return true; - + } - + } - + } catch (Exception e) { this.objectManager.throwException (conn, @@ -217,48 +217,48 @@ public boolean hasEditorSentInfo (EditorEditor ed) e); } finally { - + this.objectManager.releaseConnection (conn); - - } - + + } + return false; - + } - + public boolean hasMyPublicKeyBeenSentToEditor (EditorEditor ed) throws GeneralException { - + // Ugh... so sick of this type of get connection, do something, release connection! Connection conn = null; - + try { conn = this.objectManager.getConnection (); - List params = new ArrayList (); + List params = new ArrayList<> (); params.add (ed.getKey ()); params.add (PublicKeyMessage.MESSAGE_TYPE); - + ResultSet rs = this.objectManager.executeQuery ("SELECT type FROM message_v WHERE editordbkey = ? AND sentbyme = TRUE AND type = ?", params, conn); if (rs.next ()) { - + // Using the type here rather than the key because of stupid java Long/long ambiguities. if (rs.getString (1) != null) { - + return true; - + } - + } - + } catch (Exception e) { this.objectManager.throwException (conn, @@ -267,13 +267,13 @@ public boolean hasMyPublicKeyBeenSentToEditor (EditorEditor ed) e); } finally { - + this.objectManager.releaseConnection (conn); - - } + + } return false; - + } @Override @@ -282,17 +282,17 @@ public List getObjects (EditorEditor ed, boolean loadChildObjects) throws GeneralException { - - List ret = new ArrayList (); + + List ret = new ArrayList<> (); ResultSet rs = null; - + try { - List params = new ArrayList (); + List params = new ArrayList<> (); params.add (ed.getKey ()); - + rs = this.objectManager.executeQuery (STD_SELECT_PREFIX + " WHERE editordbkey = ? ORDER BY when", params, conn); @@ -303,7 +303,7 @@ public List getObjects (EditorEditor ed, ret.add (this.getMessage (rs)); } - + } catch (Exception e) { throw new GeneralException ("Unable to load message for: " + @@ -311,7 +311,7 @@ public List getObjects (EditorEditor ed, e); } finally { - + try { @@ -319,15 +319,15 @@ public List getObjects (EditorEditor ed, } catch (Exception e) { - + } - - } + + } return ret; - + } - + private EditorMessage getMessage (ResultSet rs) throws GeneralException { @@ -340,30 +340,30 @@ private EditorMessage getMessage (ResultSet rs) long key = rs.getLong (ind++); EditorMessage am = this.messageCache.get (key); - + if (am != null) { - + return am; - + } - + String type = rs.getString (ind++); - + am = MessageFactory.getInstance (type); am.setKey (key); am.setWhen (rs.getTimestamp (ind++)); am.setSentByMe (rs.getBoolean (ind++)); am.setEditor (EditorsEnvironment.getEditorByKey (rs.getLong (ind++))); am.setForProjectId (rs.getString (ind++)); - am.setMessageId (rs.getString (ind++)); + am.setMessageId (rs.getString (ind++)); am.setMessage (rs.getString (ind++)); am.setPropertiesAsString (rs.getString (ind++)); am.setDealtWith (rs.getBoolean (ind++)); - + this.messageCache.put (key, am); - + return am; } catch (Exception e) @@ -373,25 +373,25 @@ private EditorMessage getMessage (ResultSet rs) e); } - + } - + public byte[] getOriginalMessage (EditorMessage em) throws GeneralException { - + // Ugh... so sick of this type of get connection, do something, release connection! Connection conn = null; - + try { conn = this.objectManager.getConnection (); - List params = new ArrayList (); + List params = new ArrayList<> (); params.add (em.getEditor ().getKey ()); params.add (em.getKey ()); - + ResultSet rs = this.objectManager.executeQuery ("SELECT origmessage FROM message WHERE editordbkey = ? AND dbkey = ?", params, conn); @@ -402,7 +402,7 @@ public byte[] getOriginalMessage (EditorMessage em) return rs.getString (1).getBytes (); } - + } catch (Exception e) { this.objectManager.throwException (conn, @@ -411,32 +411,32 @@ public byte[] getOriginalMessage (EditorMessage em) e); } finally { - + this.objectManager.releaseConnection (conn); - - } + + } return null; - + } - + public int getMessageCount (String messageType, boolean sentByMe) throws GeneralException { - + // Ugh... so sick of this type of get connection, do something, release connection! Connection conn = null; - + try { conn = this.objectManager.getConnection (); - List params = new ArrayList (); + List params = new ArrayList<> (); params.add (messageType); params.add (sentByMe); - + ResultSet rs = this.objectManager.executeQuery ("SELECT COUNT(*) FROM message_v WHERE type = ? AND sentbyme = ?", params, conn); @@ -447,7 +447,7 @@ public int getMessageCount (String messageType, return rs.getInt (1); } - + } catch (Exception e) { this.objectManager.throwException (conn, @@ -456,22 +456,22 @@ public int getMessageCount (String messageType, e); } finally { - + this.objectManager.releaseConnection (conn); - - } - + + } + return 0; - + } - + public Set getProjectsSentToEditor (EditorEditor ed) throws GeneralException { // Ugh... so sick of this type of get connection, do something, release connection! Connection conn = null; - + try { @@ -479,45 +479,45 @@ public Set getProjectsSentToEditor (EditorEditor ed) // Do this here to prevent an O^n lookup to occur. Set allProjs = Environment.getAllProjectInfos (); - - Map allProjsM = new HashMap (); - + + Map allProjsM = new HashMap<> (); + for (ProjectInfo p : allProjs) { - + allProjsM.put (p.getId (), p); - + } - - Set projs = new LinkedHashSet (); - - List params = new ArrayList (); + + Set projs = new LinkedHashSet<> (); + + List params = new ArrayList<> (); params.add (ed.getKey ()); params.add (NewProjectMessage.MESSAGE_TYPE); - + ResultSet rs = this.objectManager.executeQuery ("SELECT DISTINCT forprojectid FROM message_v WHERE editordbkey = ? AND type = ? AND sentbyme = TRUE", params, conn); while (rs.next ()) { - + String pid = rs.getString (1); ProjectInfo p = allProjsM.get (pid); - + if (p != null) { - + projs.add (p); - + } - + } - + return projs; - + } catch (Exception e) { this.objectManager.throwException (conn, @@ -526,15 +526,15 @@ public Set getProjectsSentToEditor (EditorEditor ed) e); } finally { - + this.objectManager.releaseConnection (conn); - } - + } + return null; - + } - + public NewProjectMessage getNewProjectMessage (EditorEditor ed, String projectId, boolean sentByMe) @@ -543,21 +543,21 @@ public NewProjectMessage getNewProjectMessage (EditorEditor ed, // Ugh... so sick of this type of get connection, do something, release connection! Connection conn = null; - + try { conn = this.objectManager.getConnection (); - List params = new ArrayList (); + List params = new ArrayList<> (); params.add (ed.getKey ()); params.add (projectId); params.add (NewProjectMessage.MESSAGE_TYPE); params.add (sentByMe); - + ResultSet rs = this.objectManager.executeQuery (STD_SELECT_PREFIX + " WHERE editordbkey = ? AND forprojectid = ? AND type = ? AND sentbyme = ? ORDER BY when DESC", params, - conn); + conn); if (rs.next ()) { @@ -565,7 +565,7 @@ public NewProjectMessage getNewProjectMessage (EditorEditor ed, return (NewProjectMessage) this.getMessage (rs); } - + } catch (Exception e) { this.objectManager.throwException (conn, @@ -576,43 +576,43 @@ public NewProjectMessage getNewProjectMessage (EditorEditor ed, e); } finally { - + this.objectManager.releaseConnection (conn); - } - + } + return null; - + } - + public Set getAllUndealtWithMessages () throws GeneralException { // Ugh... so sick of this type of get connection, do something, release connection! Connection conn = null; - + try { - + conn = this.objectManager.getConnection (); - // We only include messages from non-pending editors. + // We only include messages from non-pending editors. ResultSet rs = this.objectManager.executeQuery (STD_SELECT_PREFIX + " WHERE dealtwith = FALSE AND editordbkey IN (SELECT dbkey FROM editor WHERE status <> 'pending') ORDER BY when", null, conn); - Set messages = new LinkedHashSet (); - + Set messages = new LinkedHashSet<> (); + while (rs.next ()) { messages.add (this.getMessage (rs)); } - + return messages; - + } catch (Exception e) { this.objectManager.throwException (conn, @@ -620,13 +620,13 @@ public Set getAllUndealtWithMessages () e); } finally { - + this.objectManager.releaseConnection (conn); - - } - + + } + return null; - + } public Set getProjectMessages (String projId, @@ -636,66 +636,66 @@ public Set getProjectMessages (String projId, // Ugh... so sick of this type of get connection, do something, release connection! Connection conn = null; - + try { - + conn = this.objectManager.getConnection (); - List params = new ArrayList (); + List params = new ArrayList<> (); params.add (projId); - + String other = ""; - + if ((messageTypes != null) && // Oh java... (messageTypes.length > 0) ) { - + StringBuilder b = new StringBuilder ("AND type IN ("); - + for (int i = 0; i < messageTypes.length; i++) { - + params.add (messageTypes[i]); - + if (i < messageTypes.length - 1) { - + b.append (","); - + } - + b.append ("?"); - + } - + b.append (")"); - + other = b.toString (); - + } - - // We only include messages from non-pending editors. + + // We only include messages from non-pending editors. ResultSet rs = this.objectManager.executeQuery (String.format ("%s WHERE forprojectid = ? %s ORDER BY when DESC", STD_SELECT_PREFIX, other), params, conn); - Set messages = new LinkedHashSet (); - + Set messages = new LinkedHashSet<> (); + while (rs.next ()) { messages.add (this.getMessage (rs)); } - + return messages; - + } catch (Exception e) { this.objectManager.throwException (conn, @@ -706,13 +706,13 @@ public Set getProjectMessages (String projId, e); } finally { - + this.objectManager.releaseConnection (conn); - - } - + + } + return null; - + } public int getUndealtWithMessageCount () @@ -721,16 +721,16 @@ public int getUndealtWithMessageCount () // Ugh... so sick of this type of get connection, do something, release connection! Connection conn = null; - + try { - + conn = this.objectManager.getConnection (); // We only include messages from non-pending editors. ResultSet rs = this.objectManager.executeQuery ("SELECT COUNT(*) FROM message_v mv WHERE dealtwith = FALSE AND editordbkey IN (SELECT dbkey FROM editor WHERE status <> 'pending')", null, - conn); + conn); if (rs.next ()) { @@ -738,7 +738,7 @@ public int getUndealtWithMessageCount () return rs.getInt (1); } - + } catch (Exception e) { this.objectManager.throwException (conn, @@ -746,13 +746,33 @@ public int getUndealtWithMessageCount () e); } finally { - + this.objectManager.releaseConnection (conn); - - } - + + } + return 0; - + + } + + public void deleteAllMessagesForEditor (EditorEditor ed, + Connection conn) + throws GeneralException + { + + List mess = this.getObjects (ed, + conn, + true); + + for (EditorMessage m : mess) + { + + this.objectManager.deleteObject (m, + true, + conn); + + } + } public EditorMessage getMessageByEditorAndId (EditorEditor ed, @@ -760,16 +780,16 @@ public EditorMessage getMessageByEditorAndId (EditorEditor ed, Connection conn) throws GeneralException { - + ResultSet rs = null; - + try { - List params = new ArrayList (); + List params = new ArrayList<> (); params.add (ed.getKey ()); params.add (messId); - + rs = this.objectManager.executeQuery (STD_SELECT_PREFIX + " WHERE editordbkey = ? AND messageid = ?", params, conn); @@ -780,9 +800,9 @@ public EditorMessage getMessageByEditorAndId (EditorEditor ed, return this.getMessage (rs); } - + return null; - + } catch (Exception e) { throw new GeneralException ("Unable to get message: " + @@ -792,7 +812,7 @@ public EditorMessage getMessageByEditorAndId (EditorEditor ed, e); } finally { - + try { @@ -800,13 +820,13 @@ public EditorMessage getMessageByEditorAndId (EditorEditor ed, } catch (Exception e) { - + } - - } - + + } + } - + @Override public EditorMessage getObjectByKey (long key, EditorEditor ed, @@ -814,16 +834,16 @@ public EditorMessage getObjectByKey (long key, boolean loadChildObjects) throws GeneralException { - + ResultSet rs = null; - + try { - List params = new ArrayList (); + List params = new ArrayList<> (); params.add (key); params.add (ed.getKey ()); - + rs = this.objectManager.executeQuery (STD_SELECT_PREFIX + " WHERE dbkey = ? AND editordbkey = ?", params, conn); @@ -834,9 +854,9 @@ public EditorMessage getObjectByKey (long key, return this.getMessage (rs); } - + return null; - + } catch (Exception e) { throw new GeneralException ("Unable to get message with key: " + @@ -844,7 +864,7 @@ public EditorMessage getObjectByKey (long key, e); } finally { - + try { @@ -852,11 +872,11 @@ public EditorMessage getObjectByKey (long key, } catch (Exception e) { - + } - - } - + + } + } } diff --git a/src/com/quollwriter/db/EditorProjectDataHandler.java b/src/main/java/com/quollwriter/db/EditorProjectDataHandler.java similarity index 89% rename from src/com/quollwriter/db/EditorProjectDataHandler.java rename to src/main/java/com/quollwriter/db/EditorProjectDataHandler.java index ce883d3c..31240a66 100644 --- a/src/com/quollwriter/db/EditorProjectDataHandler.java +++ b/src/main/java/com/quollwriter/db/EditorProjectDataHandler.java @@ -23,54 +23,54 @@ public EditorProjectDataHandler (ObjectManager om) private String getAsString (Set items) { - + if ((items == null) || (items.size () == 0) ) { - + return null; - + } - + StringBuilder b = new StringBuilder (); - + for (String g : items) { - + if (b.length () > 0) { - + b.append (","); - + } - + b.append (g); - + } - + return b.toString (); - + } - + @Override public void createObject (EditorProject p, Connection conn) throws GeneralException { - - List params = new ArrayList (); + + List params = new ArrayList<> (); params.add (p.getKey ()); params.add (p.getId ()); params.add (this.getAsString (p.getGenres ())); params.add (p.getExpectations ()); params.add (p.getWordCountLength ().getType ()); - + this.objectManager.executeStatement ("INSERT INTO editorproject (dbkey, id, genres, expectations, wordcounttypelength) VALUES (?, ?, ?, ?, ?)", params, - conn); - + conn); + } @Override @@ -79,14 +79,14 @@ public void deleteObject (EditorProject d, Connection conn) throws GeneralException { - - List params = new ArrayList (); + + List params = new ArrayList<> (); params.add (d.getKey ()); - + this.objectManager.executeStatement ("DELETE FROM editorproject WHERE dbkey = ?", params, conn); - + } @Override @@ -94,18 +94,18 @@ public void updateObject (EditorProject p, Connection conn) throws GeneralException { - - List params = new ArrayList (); + + List params = new ArrayList<> (); params.add (p.getId ()); params.add (this.getAsString (p.getGenres ())); params.add (p.getExpectations ()); params.add (p.getWordCountLength ().getType ()); params.add (p.getKey ()); - + this.objectManager.executeStatement ("UPDATE editorproject SET id = ?, genres = ?, expectations = ?, wordcounttypelength = ? WHERE dbkey = ?", params, conn); - + } @Override @@ -114,31 +114,31 @@ public List getObjects (NamedObject parent, boolean loadChildObjects) throws GeneralException { - - throw new UnsupportedOperationException ("Not supported"); - + + throw new UnsupportedOperationException ("Not supported"); + } private Set split (String s, String sep) { - - Set ret = new LinkedHashSet (); - + + Set ret = new LinkedHashSet<> (); + StringTokenizer t = new StringTokenizer (s, sep); - + while (t.hasMoreTokens ()) { - + ret.add (t.nextToken ().trim ()); - + } - + return ret; - + } - + private EditorProject getEditorProject (ResultSet rs) throws GeneralException { @@ -155,18 +155,18 @@ private EditorProject getEditorProject (ResultSet rs) p.setKey (key); p.setId (rs.getString (ind++)); p.setName (rs.getString (ind++)); - + String genres = rs.getString (ind++); - + p.setGenres (this.split (genres, ",")); - + p.setExpectations (rs.getString (ind++)); - + String wcLength = rs.getString (ind++); - + p.setWordCountLength (EditorProject.WordCountLength.getWordCountLengthByType (wcLength)); - + p.setDescription (new StringWithMarkup (rs.getString (ind++))); p.setLastModified (rs.getTimestamp (ind++)); @@ -182,9 +182,9 @@ private EditorProject getEditorProject (ResultSet rs) e); } - + } - + @Override public EditorProject getObjectByKey (long key, NamedObject parent, @@ -192,12 +192,12 @@ public EditorProject getObjectByKey (long key, boolean loadChildObjects) throws GeneralException { - + ResultSet rs = null; try { - + rs = this.objectManager.executeQuery ("SELECT dbkey, id, name, genres, expectations, wordcounttypelength, description, lastmodified, datecreated, properties FROM editorproject_v", null, conn); @@ -238,7 +238,7 @@ public EditorProject getObjectByKey (long key, } } - + } } diff --git a/src/com/quollwriter/db/GeneralObjectProvider.java b/src/main/java/com/quollwriter/db/GeneralObjectProvider.java similarity index 100% rename from src/com/quollwriter/db/GeneralObjectProvider.java rename to src/main/java/com/quollwriter/db/GeneralObjectProvider.java diff --git a/src/com/quollwriter/db/IdeaDataHandler.java b/src/main/java/com/quollwriter/db/IdeaDataHandler.java similarity index 92% rename from src/com/quollwriter/db/IdeaDataHandler.java rename to src/main/java/com/quollwriter/db/IdeaDataHandler.java index 07fee7b0..943cc761 100644 --- a/src/com/quollwriter/db/IdeaDataHandler.java +++ b/src/main/java/com/quollwriter/db/IdeaDataHandler.java @@ -42,7 +42,7 @@ private Idea getIdea (ResultSet rs, i.setType (ideaType); i.setDescription (new StringWithMarkup (rs.getString (ind++), rs.getString (ind++))); - i.setFiles (Utils.getFilesFromXML (rs.getString (ind++))); + i.setFiles (Utils.getFilesFromXML (rs.getString (ind++))); i.setRating (rs.getInt (ind++)); i.setLastModified (rs.getTimestamp (ind++)); @@ -50,11 +50,11 @@ private Idea getIdea (ResultSet rs, if (ideaType != null) { - + ideaType.addIdea (i); - + } - + return i; } catch (Exception e) @@ -74,12 +74,12 @@ public List getObjects (IdeaType parent, throws GeneralException { - List ret = new ArrayList (); + List ret = new ArrayList<> (); try { - List params = new ArrayList (); + List params = new ArrayList<> (); params.add (parent.getKey ()); ResultSet rs = this.objectManager.executeQuery (STD_SELECT_PREFIX + " WHERE ideatypedbkey = ?", @@ -124,7 +124,7 @@ public Idea getObjectByKey (long key, throws GeneralException { - List params = new ArrayList (); + List params = new ArrayList<> (); params.add (key); ResultSet rs = this.objectManager.executeQuery (STD_SELECT_PREFIX + " WHERE dbkey = ?", @@ -162,7 +162,7 @@ public void createObject (Idea d, Idea i = (Idea) d; - List params = new ArrayList (); + List params = new ArrayList<> (); params.add (i.getKey ()); params.add (i.getType ().getKey ()); params.add (i.getRating ()); @@ -175,12 +175,12 @@ public void createObject (Idea d, @Override public void deleteObject (Idea d, - boolean deleteChildObjects, + boolean deleteChildObjects, Connection conn) throws GeneralException { - List params = new ArrayList (); + List params = new ArrayList<> (); params.add (d.getKey ()); this.objectManager.executeStatement ("DELETE FROM idea WHERE dbkey = ?", @@ -197,7 +197,7 @@ public void updateObject (Idea d, Idea i = (Idea) d; - List params = new ArrayList (); + List params = new ArrayList<> (); params.add (i.getRating ()); params.add (i.getKey ()); params.add (i.getType ().getKey ()); diff --git a/src/com/quollwriter/db/IdeaTypeDataHandler.java b/src/main/java/com/quollwriter/db/IdeaTypeDataHandler.java similarity index 93% rename from src/com/quollwriter/db/IdeaTypeDataHandler.java rename to src/main/java/com/quollwriter/db/IdeaTypeDataHandler.java index 4db2c474..a025841f 100644 --- a/src/com/quollwriter/db/IdeaTypeDataHandler.java +++ b/src/main/java/com/quollwriter/db/IdeaTypeDataHandler.java @@ -49,11 +49,11 @@ private IdeaType getIdeaType (ResultSet rs, if (p != null) { - + p.addIdeaType (it); - + } - + Connection conn = rs.getStatement ().getConnection (); this.objectManager.getObjects (Idea.class, @@ -80,7 +80,7 @@ public List getObjects (Project parent, throws GeneralException { - List ret = new ArrayList (); + List ret = new ArrayList<> (); try { @@ -132,7 +132,7 @@ public IdeaType getObjectByKey (long key, try { - List params = new ArrayList (); + List params = new ArrayList<> (); params.add (key); ResultSet rs = this.objectManager.executeQuery (STD_SELECT_PREFIX + " WHERE dbkey = ?", @@ -175,7 +175,7 @@ public void createObject (IdeaType it, throws GeneralException { - List params = new ArrayList (); + List params = new ArrayList<> (); params.add (it.getKey ()); params.add (it.getSortBy ()); params.add (it.getIconType ()); @@ -188,13 +188,13 @@ public void createObject (IdeaType it, @Override public void deleteObject (IdeaType it, - boolean deleteChildObjects, + boolean deleteChildObjects, Connection conn) throws GeneralException { // Remove all the ideas. - List ideas = it.getIdeas (); + Set ideas = it.getIdeas (); for (Idea i : ideas) { @@ -205,7 +205,7 @@ public void deleteObject (IdeaType it, } - List params = new ArrayList (); + List params = new ArrayList<> (); params.add (it.getKey ()); this.objectManager.executeStatement ("DELETE FROM ideatype WHERE dbkey = ?", @@ -220,7 +220,7 @@ public void updateObject (IdeaType it, throws GeneralException { - List params = new ArrayList (); + List params = new ArrayList<> (); params.add (it.getSortBy ()); params.add (it.getIconType ()); params.add (it.getKey ()); diff --git a/src/main/java/com/quollwriter/db/LinkDataHandler.java b/src/main/java/com/quollwriter/db/LinkDataHandler.java new file mode 100644 index 00000000..872d2d91 --- /dev/null +++ b/src/main/java/com/quollwriter/db/LinkDataHandler.java @@ -0,0 +1,230 @@ +package com.quollwriter.db; + +import java.sql.*; + +import java.util.*; + +import com.quollwriter.*; + +import com.quollwriter.data.*; + + +public class LinkDataHandler implements DataHandler +{ + + private ObjectManager objectManager = null; + + public LinkDataHandler(ObjectManager om) + { + + this.objectManager = om; + + } + + @Override + public List getObjects (NamedObject parent, + Connection conn, + boolean loadChildObjects) + throws GeneralException + { + + try + { + + Project project = null; + String suffix = ""; + List params = new ArrayList (); + + if (parent instanceof Project) + { + + project = (Project) parent; + + } else { + + if (parent instanceof NamedObject) + { + + NamedObject d = (NamedObject) parent; + + project = this.objectManager.getProject (); + suffix = "WHERE (object1dbkey = ? AND object1objtype = ?) OR (object2dbkey = ? AND object2objtype = ?)"; + params.add (d.getKey ()); + params.add (d.getObjectType ()); + params.add (d.getKey ()); + params.add (d.getObjectType ()); + + } + + } + + if (project == null) + { + + throw new IllegalArgumentException ("Unable to find project."); + + } + + List ret = new ArrayList<> (); + + ResultSet rs = this.objectManager.executeQuery ("SELECT object1dbkey, object1objtype, object2dbkey, object2objtype, dbkey FROM link " + suffix, + params, + conn); + + while (rs.next ()) + { + + long o1key = rs.getLong (1); + String o1type = rs.getString (2); + long o2key = rs.getLong (3); + String o2type = rs.getString (4); + long key = rs.getLong (5); + + if (o1type == null) + { + + continue; + + } + + if (o2type == null) + { + + continue; + + } + + ObjectReference o1 = new ObjectReference (o1type, + o1key, + null); + ObjectReference o2 = new ObjectReference (o2type, + o2key, + null); + + NamedObject d1 = (NamedObject) project.getObjectForReference (o1); + NamedObject d2 = (NamedObject) project.getObjectForReference (o2); + + if ((d1 == null) || + (d2 == null)) + { + + continue; + + } + + Link l = new Link (d1, + d2); + l.setKey (key); + + ret.add (l); + + } + + try + { + + rs.close (); + + } catch (Exception e) + { + } + + return ret; + + } catch (Exception e) { + + throw new GeneralException ("Unable to load links for: " + + parent, + e); + + } + + } + + @Override + public Link getObjectByKey (long key, + NamedObject parent, + Connection conn, + boolean loadChildObjects) + throws GeneralException + { + + throw new UnsupportedOperationException ("Not supported"); + + } + + @Override + public void createObject (Link l, + Connection conn) + throws GeneralException + { + + // Check to see if it already exists. ??? + + this.objectManager.executeStatement ("INSERT INTO link (dbkey, object1dbkey, object1objtype, object2dbkey, object2objtype) VALUES (?, ?, ?, ?, ?)", + Arrays.asList (l.getKey (), + l.getObject1 ().getKey (), + l.getObject1 ().getObjectType (), + l.getObject2 ().getKey (), + l.getObject2 ().getObjectType ()), + conn); + + } + + @Override + public void deleteObject (Link d, + boolean deleteChildObjects, + Connection conn) + throws GeneralException + { + + this.objectManager.executeStatement ("DELETE FROM link WHERE dbkey = ?", + Arrays.asList (d.getKey ()), + conn); + + } + + @Override + public void updateObject (Link l, + Connection conn) + throws GeneralException + { + + throw new UnsupportedOperationException ("Not supported"); + + } + + public void deleteLink (NamedObject obj1, + NamedObject obj2, + Connection conn) + throws GeneralException + { + + this.objectManager.executeStatement ("DELETE FROM link WHERE (object1dbkey = ? AND object1objtype = ? AND object2dbkey = ? AND object2objtype = ?) OR (object1dbkey = ? AND object1objtype = ? AND object2dbkey = ? AND object2objtype = ?)", + Arrays.asList (obj1.getKey (), + obj1.getObjectType (), + obj2.getKey (), + obj2.getObjectType (), + obj2.getKey (), + obj2.getObjectType (), + obj1.getKey (), + obj1.getObjectType ()), + conn); + + } + + public void deleteAllLinks (NamedObject obj, + Connection conn) + throws GeneralException + { + + this.objectManager.executeStatement ("DELETE FROM link WHERE (object1dbkey = ? AND object1objtype = ?) OR (object2dbkey = ? AND object2objtype = ?)", + Arrays.asList (obj.getKey (), + obj.getObjectType (), + obj.getKey (), + obj.getObjectType ()), + conn); + + } + +} diff --git a/src/com/quollwriter/db/LocationDataHandler.java b/src/main/java/com/quollwriter/db/LocationDataHandler.java similarity index 78% rename from src/com/quollwriter/db/LocationDataHandler.java rename to src/main/java/com/quollwriter/db/LocationDataHandler.java index 9245576d..a0412ec7 100644 --- a/src/com/quollwriter/db/LocationDataHandler.java +++ b/src/main/java/com/quollwriter/db/LocationDataHandler.java @@ -41,33 +41,33 @@ private Location getLocation (ResultSet rs, // Load the object fields. this.objectManager.setUserConfigurableObjectFields (l, rs.getStatement ().getConnection ()); - + l.setName (rs.getString (ind++)); l.setDescription (new StringWithMarkup (rs.getString (ind++), rs.getString (ind++))); l.setFiles (Utils.getFilesFromXML (rs.getString (ind++))); - + l.setLastModified (rs.getTimestamp (ind++)); l.setDateCreated (rs.getTimestamp (ind++)); l.setPropertiesAsString (rs.getString (ind++)); l.setId (rs.getString (ind++)); - l.setVersion (rs.getString (ind++)); - + l.setVersion (rs.getString (ind++)); + if (proj != null) { - + proj.addAsset (l); - + } - + // Get all the notes. if (loadChildObjects) { - + this.objectManager.loadNotes (l, rs.getStatement ().getConnection ()); - + } return l; @@ -88,16 +88,13 @@ public List getObjects (Project parent, throws GeneralException { - List ret = new ArrayList (); + List ret = new ArrayList<> (); try { - List params = new ArrayList (); - params.add (parent.getKey ()); - ResultSet rs = this.objectManager.executeQuery (STD_SELECT_PREFIX + " WHERE latest = TRUE AND projectdbkey = ?", - params, + Arrays.asList (parent.getKey ()), conn); while (rs.next ()) @@ -143,12 +140,8 @@ public Location getObjectByKey (long key, try { - List params = new ArrayList (); - params.add (key); - //params.add (proj.getKey ()); - ResultSet rs = this.objectManager.executeQuery (STD_SELECT_PREFIX + " WHERE latest = TRUE AND dbkey = ?",// AND projectdbkey = ?", - params, + Arrays.asList (key), conn); if (rs.next ()) @@ -189,29 +182,23 @@ public void createObject (Location d, Location l = (Location) d; - List params = new ArrayList (); - params.add (l.getKey ()); - params.add (l.getProject ().getKey ()); - this.objectManager.executeStatement ("INSERT INTO location (dbkey, projectdbkey) VALUES (?, ?)", - params, + Arrays.asList (l.getKey (), + l.getProject ().getKey ()), conn); } public void deleteObject (Location d, - boolean deleteChildObjects, + boolean deleteChildObjects, Connection conn) throws GeneralException { Location l = (Location) d; - List params = new ArrayList (); - params.add (l.getKey ()); - this.objectManager.executeStatement ("DELETE FROM location WHERE dbkey = ?", - params, + Arrays.asList (l.getKey ()), conn); } @@ -221,15 +208,6 @@ public void updateObject (Location d, throws GeneralException { - Location l = (Location) d; - - List params = new ArrayList (); - params.add (l.getKey ()); - /* - this.objectManager.executeStatement ("UPDATE location SET ? WHERE dbkey = ?", - params, - conn); - */ } } diff --git a/src/com/quollwriter/db/NoteDataHandler.java b/src/main/java/com/quollwriter/db/NoteDataHandler.java similarity index 79% rename from src/com/quollwriter/db/NoteDataHandler.java rename to src/main/java/com/quollwriter/db/NoteDataHandler.java index 2c6f0e66..166a9573 100644 --- a/src/com/quollwriter/db/NoteDataHandler.java +++ b/src/main/java/com/quollwriter/db/NoteDataHandler.java @@ -56,7 +56,7 @@ private Note getNote (ResultSet rs, n.setPosition (rs.getInt (ind++)); n.setEndPosition (rs.getInt (ind++)); n.setId (rs.getString (ind++)); - n.setVersion (rs.getString (ind++)); + n.setVersion (rs.getString (ind++)); return n; @@ -79,12 +79,10 @@ public List getObjects (NamedObject parent, try { - List ret = new ArrayList (); - - List params = new ArrayList (); - params.add (parent.getKey ()); - params.add (parent.getVersion ()); - + List ret = new ArrayList<> (); + + List params = Arrays.asList (parent.getKey (), parent.getVersion ()); + ResultSet rs = this.objectManager.executeQuery (STD_SELECT_PREFIX + " WHERE objectdbkey = ? AND objectversion = ?", params, conn); @@ -107,7 +105,7 @@ public List getObjects (NamedObject parent, } return ret; - + } catch (Exception e) { @@ -116,7 +114,7 @@ public List getObjects (NamedObject parent, e); } - + } public Note getObjectByKey (long key, @@ -128,32 +126,32 @@ public Note getObjectByKey (long key, try { - - List params = new ArrayList (); + + List params = new ArrayList<> (); params.add (key); - + ResultSet rs = this.objectManager.executeQuery (STD_SELECT_PREFIX + " WHERE dbkey = ?", params, conn); - + if (rs.next ()) { - + return this.getNote (rs, loadChildObjects); - + } - + return null; - + } catch (Exception e) { - + throw new GeneralException ("Unable to get note with key: " + key, e); - + } - + } public Set getNotesForVersion (ProjectVersion pv, @@ -163,30 +161,30 @@ public Set getNotesForVersion (ProjectVersion pv, if (pv == null) { - + throw new IllegalArgumentException ("Must provide a project version"); - + } - + boolean closeConn = false; - + if (conn == null) { - + conn = this.objectManager.getConnection (); - + closeConn = true; - + } - + try { - Set ret = new LinkedHashSet (); - - List params = new ArrayList (); + Set ret = new LinkedHashSet<> (); + + List params = new ArrayList<> (); params.add (pv.getKey ()); - + ResultSet rs = this.objectManager.executeQuery (String.format ("%s WHERE objectdbkey IN (SELECT dbkey FROM chapter WHERE projectversiondbkey = ?) ORDER BY datecreated", STD_SELECT_PREFIX), params, @@ -210,29 +208,29 @@ public Set getNotesForVersion (ProjectVersion pv, } return ret; - + } catch (Exception e) { - + this.objectManager.throwException (conn, "Unable to get notes for project version: " + pv, e); - + } finally { - + if (closeConn) { - + this.objectManager.releaseConnection (conn); - + } - - } - + + } + return null; - + } - + public Set getDealtWith (ProjectVersion pv, boolean isDealtWith, Connection conn) @@ -241,30 +239,30 @@ public Set getDealtWith (ProjectVersion pv, if (pv == null) { - + throw new IllegalArgumentException ("Must provide a project version"); - + } - + boolean closeConn = false; - + if (conn == null) { - + conn = this.objectManager.getConnection (); - + closeConn = true; - + } - + try { - Set ret = new LinkedHashSet (); - - List params = new ArrayList (); + Set ret = new LinkedHashSet<> (); + + List params = new ArrayList<> (); params.add (pv.getKey ()); - + ResultSet rs = this.objectManager.executeQuery (String.format ("%s WHERE dealtwith IS %s NULL AND objectdbkey IN (SELECT dbkey FROM chapter WHERE projectversiondbkey = ?) ORDER BY datecreated", STD_SELECT_PREFIX, (isDealtWith ? "NOT" : "")), @@ -289,93 +287,93 @@ public Set getDealtWith (ProjectVersion pv, } return ret; - + } catch (Exception e) { - + this.objectManager.throwException (conn, "Unable to get notes for project version: " + pv, e); - + } finally { - + if (closeConn) { - + this.objectManager.releaseConnection (conn); - + } - - } - + + } + return null; - + } - + public int getDealtWithCount (ProjectVersion projVer, boolean isDealtWith, Connection conn) throws GeneralException { - + if (projVer == null) { - + throw new IllegalArgumentException ("Must provide a project version"); - + } - + boolean closeConn = false; - + if (conn == null) { - + conn = this.objectManager.getConnection (); - + closeConn = true; - + } - + try { - List params = new ArrayList (); + List params = new ArrayList<> (); params.add (projVer.getKey ()); - + ResultSet rs = this.objectManager.executeQuery (String.format ("SELECT COUNT(*) FROM note_v WHERE dealtwith IS %s NULL AND objectdbkey IN (SELECT dbkey FROM chapter WHERE projectversiondbkey = ?)", (isDealtWith ? "NOT" : "")), params, conn); - + if (rs.next ()) { - return rs.getInt (1); + return rs.getInt (1); } - + } catch (Exception e) { - + this.objectManager.throwException (conn, "Unable to get count of notes for project version: " + projVer, e); - + } finally { - + if (closeConn) { - + this.objectManager.releaseConnection (conn); - + } - - } - + + } + return 0; - + } - + /** * Get a count of the dealt with notes for all versions except that passed in. */ @@ -384,63 +382,63 @@ public int getDealtWithCountForOtherVersions (ProjectVersion projVer, Connection conn) throws GeneralException { - + if (projVer == null) { - + throw new IllegalArgumentException ("Must provide a project version"); - + } - + boolean closeConn = false; - + if (conn == null) { - + conn = this.objectManager.getConnection (); - + closeConn = true; - + } - + try { - List params = new ArrayList (); + List params = new ArrayList<> (); params.add (projVer.getKey ()); - + ResultSet rs = this.objectManager.executeQuery (String.format ("SELECT COUNT(*) FROM note_v WHERE dealtwith IS %s NULL AND objectdbkey IN (SELECT dbkey FROM chapter WHERE projectversiondbkey <> ?)", (isDealtWith ? "NOT" : "")), params, conn); - + if (rs.next ()) { - return rs.getInt (1); + return rs.getInt (1); } - + } catch (Exception e) { - + this.objectManager.throwException (conn, "Unable to get count of notes for project version: " + projVer, e); - + } finally { - + if (closeConn) { - + this.objectManager.releaseConnection (conn); - + } - - } - + + } + return 0; - + } public void setObjectNotesToLatest (DataObject d, @@ -448,58 +446,54 @@ public void setObjectNotesToLatest (DataObject d, Connection conn) throws GeneralException { - + if (d == null) { - + return; - + } - + boolean closeConn = false; - + if (conn == null) { - + conn = this.objectManager.getConnection (); - + closeConn = true; - + } - + try { - List params = new ArrayList (); - params.add (latest); - params.add (Note.OBJECT_TYPE); - params.add (d.getKey ()); - params.add (d.getVersion ()); - + List params = Arrays.asList (latest, Note.OBJECT_TYPE, d.getKey (), d.getVersion ()); + this.objectManager.executeStatement ("UPDATE dataobject SET latest = ? WHERE objecttype = ? AND dbkey IN (SELECT dbkey FROM note WHERE objectdbkey = ? AND objectversion = ?)", params, conn); - + } catch (Exception e) { this.objectManager.throwException (conn, "Unable to update notes to be latest for object: " + d, e); - + } finally { - + if (closeConn) { - + this.objectManager.releaseConnection (conn); - + } - + } - + } - + public void createObject (Note d, Connection conn) throws GeneralException @@ -507,35 +501,29 @@ public void createObject (Note d, Note n = (Note) d; - List params = new ArrayList (); - params.add (n.getKey ()); - params.add (n.getDue ()); - params.add (n.getDealtWith ()); - params.add (n.getType ()); - params.add (n.getPosition ()); - params.add (n.getEndPosition ()); - params.add (n.getObject ().getKey ()); - params.add (n.getObject ().getVersion ()); - this.objectManager.executeStatement ("INSERT INTO note (dbkey, due, dealtwith, type, position, end_position, objectdbkey, objectversion) VALUES (?, ?, ?, ?, ?, ?, ?, ?)", - params, + Arrays.asList (n.getKey (), + n.getDue (), + n.getDealtWith (), + n.getType (), + n.getPosition (), + n.getEndPosition (), + n.getObject ().getKey (), + n.getObject ().getVersion ()), conn); } public void deleteObject (Note d, - boolean deleteChildObjects, + boolean deleteChildObjects, Connection conn) throws GeneralException { Note n = (Note) d; - List params = new ArrayList (); - params.add (n.getKey ()); - this.objectManager.executeStatement ("DELETE FROM note WHERE dbkey = ?", - params, + Arrays.asList (n.getKey ()), conn); } @@ -547,18 +535,15 @@ public void updateObject (Note d, Note n = (Note) d; - List params = new ArrayList (); - params.add (n.getDue ()); - params.add (n.getDealtWith ()); - params.add (n.getType ()); - params.add (n.getObject ().getKey ()); - params.add (n.getObject ().getVersion ()); - params.add (n.getPosition ()); - params.add (n.getEndPosition ()); - params.add (n.getKey ()); - this.objectManager.executeStatement ("UPDATE note SET due = ?, dealtwith = ?, type = ?, objectdbkey = ?, objectversion = ?, position = ?, end_position = ? WHERE dbkey = ?", - params, + Arrays.asList (n.getDue (), + n.getDealtWith (), + n.getType (), + n.getObject ().getKey (), + n.getObject ().getVersion (), + n.getPosition (), + n.getEndPosition (), + n.getKey ()), conn); } diff --git a/src/com/quollwriter/db/ObjectDataHandler.java b/src/main/java/com/quollwriter/db/ObjectDataHandler.java similarity index 80% rename from src/com/quollwriter/db/ObjectDataHandler.java rename to src/main/java/com/quollwriter/db/ObjectDataHandler.java index 8cf15037..5d838bcb 100644 --- a/src/com/quollwriter/db/ObjectDataHandler.java +++ b/src/main/java/com/quollwriter/db/ObjectDataHandler.java @@ -36,11 +36,11 @@ private QObject getQObject (ResultSet rs, QObject l = new QObject (); l.setKey (key); - + // Load the object fields. this.objectManager.setUserConfigurableObjectFields (l, - rs.getStatement ().getConnection ()); - + rs.getStatement ().getConnection ()); + l.setName (rs.getString (ind++)); l.setDescription (new StringWithMarkup (rs.getString (ind++), rs.getString (ind++))); @@ -49,37 +49,37 @@ private QObject getQObject (ResultSet rs, l.setLastModified (rs.getTimestamp (ind++)); l.setDateCreated (rs.getTimestamp (ind++)); l.setPropertiesAsString (rs.getString (ind++)); - + if (l.getLegacyField (QObject.TYPE_LEGACY_FIELD_ID) == null) { - + l.setType (rs.getString (ind++)); - + } else { - + ind++; - + } - + l.setId (rs.getString (ind++)); - l.setVersion (rs.getString (ind++)); - + l.setVersion (rs.getString (ind++)); + // Get all the notes. if (loadChildObjects) { - + this.objectManager.loadNotes (l, rs.getStatement ().getConnection ()); - + } if (proj != null) { - + proj.addAsset (l); - + } - + return l; } catch (Exception e) @@ -99,16 +99,13 @@ public List getObjects (Project parent, throws GeneralException { - List ret = new ArrayList (); + List ret = new ArrayList<> (); try { - List params = new ArrayList (); - params.add (parent.getKey ()); - ResultSet rs = this.objectManager.executeQuery (STD_SELECT_PREFIX + " WHERE latest = TRUE AND projectdbkey = ?", - params, + Arrays.asList (parent.getKey ()), conn); while (rs.next ()) @@ -155,12 +152,8 @@ public QObject getObjectByKey (long key, try { - List params = new ArrayList (); - params.add (key); - //params.add (proj.getKey ()); - ResultSet rs = this.objectManager.executeQuery (STD_SELECT_PREFIX + " WHERE latest = TRUE AND dbkey = ?", // AND projectdbkey = ?", - params, + Arrays.asList (key), conn); if (rs.next ()) @@ -200,29 +193,23 @@ public void createObject (QObject o, throws GeneralException { - List params = new ArrayList (); - params.add (o.getKey ()); - params.add (o.getType ()); - params.add (o.getProject ().getKey ()); - this.objectManager.executeStatement ("INSERT INTO qobject (dbkey, type, projectdbkey) VALUES (?, ?, ?)", - params, + Arrays.asList (o.getKey (), + o.getType (), + o.getProject ().getKey ()), conn); } @Override public void deleteObject (QObject o, - boolean deleteChildObjects, + boolean deleteChildObjects, Connection conn) throws GeneralException { - List params = new ArrayList (); - params.add (o.getKey ()); - this.objectManager.executeStatement ("DELETE FROM qobject WHERE dbkey = ?", - params, + Arrays.asList (o.getKey ()), conn); } @@ -233,11 +220,9 @@ public void updateObject (QObject o, throws GeneralException { - List params = new ArrayList (); - params.add (o.getType ()); - params.add (o.getKey ()); this.objectManager.executeStatement ("UPDATE qobject SET type = ? WHERE dbkey = ?", - params, + Arrays.asList (o.getType (), + o.getKey ()), conn); } diff --git a/src/com/quollwriter/db/ObjectManager.java b/src/main/java/com/quollwriter/db/ObjectManager.java similarity index 88% rename from src/com/quollwriter/db/ObjectManager.java rename to src/main/java/com/quollwriter/db/ObjectManager.java index 4303d0af..e763bf25 100644 --- a/src/com/quollwriter/db/ObjectManager.java +++ b/src/main/java/com/quollwriter/db/ObjectManager.java @@ -1,14 +1,16 @@ package com.quollwriter.db; import java.io.*; +import java.nio.file.*; import java.sql.*; import java.util.*; +import java.util.stream.*; import javax.sql.*; -import com.gentlyweb.xml.JDOMUtils; +import javafx.collections.*; import com.quollwriter.*; @@ -19,12 +21,16 @@ import com.quollwriter.ui.*; -import org.apache.commons.dbcp.*; -import org.apache.commons.pool.impl.*; +import org.apache.commons.dbcp2.PoolingDataSource; +import org.apache.commons.dbcp2.PoolableConnection; +import org.apache.commons.dbcp2.ConnectionFactory; +import org.apache.commons.dbcp2.PoolableConnectionFactory; +import org.apache.commons.dbcp2.DriverManagerConnectionFactory; +import org.apache.commons.pool2.impl.*; import org.h2.jdbc.*; -import org.jdom.*; +import org.dom4j.*; import org.josql.*; @@ -48,7 +54,7 @@ public class XMLConstants private File dir = null; protected Map handlers = new HashMap (); private String sequenceName = null; - private GenericObjectPool connectionPool = null; + private GenericObjectPool connectionPool = null; private Project project = null; private Map actionLogHandlers = new HashMap (); @@ -465,20 +471,27 @@ public void init (File dir, e); } - this.connectionPool = new GenericObjectPool (null); - this.connectionPool.setMaxActive (20); - this.connectionPool.setMaxIdle (10); - ConnectionFactory connectionFactory = new DriverManagerConnectionFactory (url, username, pwd); - new PoolableConnectionFactory (connectionFactory, + PoolableConnectionFactory poolf = new PoolableConnectionFactory (connectionFactory, + null); +/* +OLD? DBCP1 + PoolableConnectionFactory poolf = new PoolableConnectionFactory (connectionFactory, this.connectionPool, null, null, false, false); +*/ + + this.connectionPool = new GenericObjectPool<> (poolf); + // TODO Remove? this.connectionPool.setMaxActive (20); + this.connectionPool.setMaxTotal (50); + this.connectionPool.setMaxIdle (10); + poolf.setPool (this.connectionPool); this.ds = new PoolingDataSource (this.connectionPool); @@ -566,17 +579,79 @@ private String getSequenceName () } + // Ugh a terrible hack... + // TODO Fix this horribleness... + public boolean supportsLinks () + { + + return true; + + } + public void updateLinks (NamedObject d, - Set newLinks) + Connection c) throws GeneralException { - Connection c = null; + // GAH... this is soooo bad... + if ((!this.supportsLinks ()) + || + (d instanceof Project) + ) + { + + return; + + } + + List currLinks = this.getLinks (d, + c); + + Set oldOtherObjects = new HashSet<> (); + + for (Link l : currLinks) + { + + oldOtherObjects.add (l.getOtherObject (d)); + + } + + Set newOtherObjects = d.getOtherObjectsInLinks (); + + // Find out what has been added. + Set added = new HashSet<> (newOtherObjects); + added.removeAll (oldOtherObjects); + + // Find out what has been removed. + Set removed = new HashSet<> (oldOtherObjects); + removed.removeAll (newOtherObjects); try { - c = this.getConnection (); + this.deleteLinks (d, + removed, + c); + + for (NamedObject n : added) + { + + Link l = d.getLinkFor (n); + + if (l.getKey () != null) + { + + // This shouldn't happen! + continue; + + } + + this.saveObject (l, + c); + + } +/* +TODO REmove this.deleteLinks (d, c); @@ -588,6 +663,14 @@ public void updateLinks (NamedObject d, Link l = iter.next (); + if (l.getKey () != null) + { + + // We don't support updating links only adding new ones. + continue; + + } + if ((l.getObject1 () == null) || (l.getObject2 () == null) @@ -614,7 +697,7 @@ public void updateLinks (NamedObject d, l.getObject2 ().addLink (l); } - +*/ } catch (Exception e) { @@ -623,37 +706,29 @@ public void updateLinks (NamedObject d, d, e); - } finally { - - this.releaseConnection (c); - } } - public void getLinks (NamedObject d, - Connection conn) - throws GeneralException + public List getLinks (NamedObject d, + Connection conn) + throws GeneralException { - if (d == null) + if ((d == null) + || + (!this.supportsLinks ()) + ) { - return; + return new ArrayList<> (); } if (d.getKey () == null) { - return; - - } - - if (d.getLinks ().size () > 0) - { - - return; + return new ArrayList<> (); } @@ -679,11 +754,40 @@ public void getLinks (NamedObject d, } - try { - d.clearLinks (); + return (List) this.getObjects (Link.class, + d, + conn, + true); + + } catch (Exception e) + { + + this.throwException (conn, + "Unable to get links for: " + + d, + e); + + } finally + { + + if (closeConn) + { + + this.releaseConnection (conn); + + } + + } + + return new ArrayList<> (); + +/* + + try + { List params = new ArrayList (); params.add (d.getKey ()); @@ -771,7 +875,7 @@ public void getLinks (NamedObject d, } } - +*/ } public void getLinks (NamedObject d) @@ -1262,11 +1366,19 @@ public void throwException (Connection conn, } - public void deleteLinks (NamedObject n, - Connection conn) + public void deleteLinks (NamedObject n, + Set remove, + Connection conn) throws GeneralException { + if (!this.supportsLinks ()) + { + + return; + + } + boolean closeConn = false; if (conn == null) @@ -1293,6 +1405,18 @@ public void deleteLinks (NamedObject n, try { + LinkDataHandler dh = (LinkDataHandler) this.getHandler (Link.class); + + for (NamedObject o : remove) + { + + dh.deleteLink (n, + o, + conn); + + } + +/* this.getLinks (n, conn); @@ -1305,9 +1429,14 @@ public void deleteLinks (NamedObject n, Link l = iter.next (); - this.deleteObject (l, - false, - conn); + if (l.getKey () != null) + { + + this.deleteObject (l, + false, + conn); + + } iter.remove (); @@ -1316,7 +1445,103 @@ public void deleteLinks (NamedObject n, l.getObject2 ().removeLink (l); } +*/ + } catch (Exception e) { + + this.throwException (conn, + "Unable to delete links for: " + + n, + e); + + } finally { + + if (closeConn) + { + + this.releaseConnection (conn); + + } + } + + } + + public void deleteAllLinks (NamedObject n, + Connection conn) + throws GeneralException + { + + // GAH... this is soooo bad... + if ((!this.supportsLinks ()) + || + (n instanceof Project) + ) + { + + return; + + } + + boolean closeConn = false; + + if (conn == null) + { + + closeConn = true; + + try + { + + conn = this.getConnection (); + + } catch (Exception e) + { + + this.throwException (null, + "Unable to get connection", + e); + + } + + } + + try + { + + LinkDataHandler dh = (LinkDataHandler) this.getHandler (Link.class); + + dh.deleteAllLinks (n, + conn); +/* + this.getLinks (n, + conn); + + Set links = n.getLinks (); + + Iterator iter = links.iterator (); + + while (iter.hasNext ()) + { + + Link l = iter.next (); + + if (l.getKey () != null) + { + + this.deleteObject (l, + false, + conn); + + } + + iter.remove (); + + // Get either side. + l.getObject1 ().removeLink (l); + l.getObject2 ().removeLink (l); + + } +*/ } catch (Exception e) { this.throwException (conn, @@ -1402,7 +1627,7 @@ private void deleteAllUserConfigurableObjectFieldsForObject (UserConfigurableObj throw new GeneralException ("Class is not supported."); } - + dh.deleteAllFieldsForObject (obj, conn); @@ -1484,8 +1709,12 @@ public void deleteObject (DataObject d, } - this.deleteLinks (n, - conn); + n.getNotes ().clear (); + + this.deleteAllLinks (n, + conn); + + n.getLinks ().clear (); List params = new ArrayList (); params.add (d.getKey ()); @@ -1711,7 +1940,7 @@ public void createActionLogEntry (NamedObject n, try { - m = JDOMUtils.getElementAsString (changesEl); + m = DOM4JUtils.elementAsString (changesEl); } catch (Exception e) { @@ -2059,7 +2288,7 @@ public void saveObject (DataObject d, } this.updateLinks (n, - n.getLinks ()); + conn); } @@ -2144,6 +2373,22 @@ public void saveObject (DataObject d, } + if (!(n instanceof Link)) + { + + for (Note nn : n.getNotes ()) + { + + this.saveObject (nn, + conn); + + } + + this.updateLinks (n, + conn); + + } + } } @@ -2592,7 +2837,7 @@ private void runCreateViewsScript (Connection conn) String f = this.getCreateViewsFile (); - String xml = Environment.getResourceFileAsString (f); + String xml = Utils.getResourceFileAsString (f); if (xml == null) { @@ -2601,7 +2846,7 @@ private void runCreateViewsScript (Connection conn) } - Element root = JDOMUtils.getStringAsElement (xml); + Element root = DOM4JUtils.stringAsElement (xml); this.runScriptElements (root, conn, @@ -2689,7 +2934,7 @@ private void runUpgradeScript (int oldVersion, String f = this.getUpgradeScriptFile (oldVersion, newVersion); - String xml = Environment.getResourceFileAsString (f); + String xml = Utils.getResourceFileAsString (f); if (xml == null) { @@ -2698,11 +2943,11 @@ private void runUpgradeScript (int oldVersion, } - Element root = JDOMUtils.getStringAsElement (xml); + Element root = DOM4JUtils.stringAsElement (xml); - int from = JDOMUtils.getAttributeValueAsInt (root, + int from = DOM4JUtils.attributeValueAsInt (root, XMLConstants.from); - int to = JDOMUtils.getAttributeValueAsInt (root, + int to = DOM4JUtils.attributeValueAsInt (root, XMLConstants.to); if ((oldVersion != from) || @@ -2766,8 +3011,7 @@ public String getSchemaFile (String file) private void runScriptElements (Element root, Connection conn, boolean allowAllToFail) - throws GeneralException, - JDOMException + throws GeneralException { if ((allowAllToFail) @@ -2780,43 +3024,36 @@ private void runScriptElements (Element root, } - List itemEls = JDOMUtils.getChildElements (root, - XMLConstants.item, - false); - - for (int i = 0; i < itemEls.size (); i++) + for (Element el : root.elements (XMLConstants.item)) { - Element el = (Element) itemEls.get (i); - - String log = JDOMUtils.getChildElementContent (el, + String log = DOM4JUtils.childElementContent (el, XMLConstants.log); - Element sqlEl = JDOMUtils.getChildElement (el, - XMLConstants.sql); + Element sqlEl = el.element (XMLConstants.sql); - boolean canFail = JDOMUtils.getAttributeValueAsBoolean (el, + boolean canFail = DOM4JUtils.attributeValueAsBoolean (el, XMLConstants.canFail, false); // See if there is a file attribute. - String file = JDOMUtils.getAttributeValue (sqlEl, + String file = DOM4JUtils.attributeValue (sqlEl, XMLConstants.file, false); String sql = null; - if (!file.equals ("")) + if (file != null) { // Get the file. - sql = Environment.getResourceFileAsString (this.getSchemaFile (file)); + sql = Utils.getResourceFileAsString (this.getSchemaFile (file)); } else { - sql = JDOMUtils.getChildElementContent (el, + sql = DOM4JUtils.childElementContent (el, XMLConstants.sql); } @@ -2825,7 +3062,7 @@ private void runScriptElements (Element root, { throw new GeneralException ("Expected to find sql for item: " + - JDOMUtils.getPath (el) + + DOM4JUtils.getPath (el) + " from update script: " + file); @@ -2851,7 +3088,7 @@ private void runScriptElements (Element root, Environment.logError ("Unable to execute sql: " + sql + " for item: " + - JDOMUtils.getPath (el) + + DOM4JUtils.getPath (el) + " from update script: " + file + ", not fatal, continuing.", @@ -2863,7 +3100,7 @@ private void runScriptElements (Element root, throw new GeneralException ("Unable to execute sql: " + sql + " for item: " + - JDOMUtils.getPath (el) + + DOM4JUtils.getPath (el) + " from update script: " + file, e); @@ -2878,10 +3115,39 @@ private void runScriptElements (Element root, } - private List getBackupFiles (Project project) - throws Exception + public int getBackupFilesCount (Project project) + throws Exception { + int c = 0; + + Set bfiles = this.getBackupFiles (project); + + if (bfiles != null) + { + + c = bfiles.size (); + + } + + return c; + + } + private ObservableSet getBackupFiles (Project project) + throws Exception + { + + ProjectInfo inf = Environment.getProjectInfo (project); + + if (inf == null) + { + + return FXCollections.observableSet (); + + } + + return inf.getBackupPaths (); +/* File dir = project.getBackupDirectory (); if (dir == null) @@ -2924,14 +3190,14 @@ private List getBackupFiles (Project project) ret = (List) qr.getResults (); return ret; - +*/ } - public File getLastBackupFile (Project project) + public Path getLastBackupFile (Project project) throws Exception { - List files = this.getBackupFiles (project); + Set files = this.getBackupFiles (project); if (files == null) { @@ -2943,7 +3209,7 @@ public File getLastBackupFile (Project project) if (files.size () > 0) { - return files.get (0); + return files.iterator ().next (); } @@ -2972,7 +3238,9 @@ public void pruneBackups (Project project, } - List files = this.getBackupFiles (project); + ProjectInfo inf = Environment.getProjectInfo (project); + + List files = new ArrayList<> (inf.getBackupPaths ()); if (files == null) { @@ -2988,45 +3256,51 @@ public void pruneBackups (Project project, files.size ()); // Delete the files. - for (File f : files) + for (Path f : files) { - if (f.delete ()) + inf.removeBackupPath (f); + + if (Files.exists (f)) { - this.createActionLogEntry (project, - "Pruned backup, file: " + f.getPath (), - null, - null); + Files.delete (f); } + this.createActionLogEntry (project, + "Pruned backup, file: " + f.toString (), + null, + null); + } } } - public File createBackup (Project project, + public Path createBackup (Project project, int keepCount) throws Exception { - File dir = project.getBackupDirectory (); + File fdir = project.getBackupDirectory (); - if (dir == null) + if (fdir == null) { return null; } - dir.mkdirs (); + Path dir = fdir.toPath (); + + Files.createDirectories (dir); // Indicate that this directory can be deleted. Utils.createQuollWriterDirFile (dir); - File last = this.getLastBackupFile (project); + Path last = this.getLastBackupFile (project); int ver = 0; @@ -3034,8 +3308,10 @@ public File createBackup (Project project, { // Split the filename, get the version. - String n = last.getName ().substring (6, - last.getName ().length () - 4); + String fn = last.getFileName ().toString (); + + String n = fn.substring (Constants.BACKUP_FILE_NAME_PREFIX.length (), + fn.length () - Constants.BACKUP_FILE_NAME_SUFFIX.length ()); try { @@ -3058,7 +3334,7 @@ public File createBackup (Project project, ver++; - File f = new File (dir.getPath () + "/backup" + ver + ".zip"); + Path f = dir.resolve (Constants.BACKUP_FILE_NAME_PREFIX + ver + Constants.BACKUP_FILE_NAME_SUFFIX); Connection conn = null; @@ -3068,7 +3344,7 @@ public File createBackup (Project project, conn = this.getConnection (); List params = new ArrayList (); - params.add (f.getPath ()); + params.add (f.toString ()); this.executeStatement ("BACKUP TO ?", params, @@ -3077,7 +3353,7 @@ public File createBackup (Project project, this.releaseConnection (conn); this.createActionLogEntry (project, - "Created backup, written to file: " + f.getPath (), + "Created backup, written to file: " + f.toString (), null, null); @@ -3086,11 +3362,13 @@ public File createBackup (Project project, { // Add the files dir to the backup. - Utils.addDirToZip (f, + Utils.addDirToZip (f.toFile (), project.getFilesDirectory ()); } + Environment.getProjectInfo (project).addBackupPath (f); + // Test the backup? } catch (Exception e) @@ -3293,6 +3571,8 @@ public void closeConnectionPool () } + this.project = null; + } /* public void saveWordCounts (java.util.Date start, diff --git a/src/com/quollwriter/db/ObjectProvider.java b/src/main/java/com/quollwriter/db/ObjectProvider.java similarity index 100% rename from src/com/quollwriter/db/ObjectProvider.java rename to src/main/java/com/quollwriter/db/ObjectProvider.java diff --git a/src/com/quollwriter/db/OutlineItemDataHandler.java b/src/main/java/com/quollwriter/db/OutlineItemDataHandler.java similarity index 83% rename from src/com/quollwriter/db/OutlineItemDataHandler.java rename to src/main/java/com/quollwriter/db/OutlineItemDataHandler.java index 8743f587..733ef2a3 100644 --- a/src/com/quollwriter/db/OutlineItemDataHandler.java +++ b/src/main/java/com/quollwriter/db/OutlineItemDataHandler.java @@ -39,45 +39,45 @@ private OutlineItem getOutlineItem (ResultSet rs, long key = rs.getLong (ind++); OutlineItem o = null; - + if (parent == null) { - + o = new OutlineItem (); - + } else { - + if (sceneKey > 0) { - + Scene s = (Scene) parent; - + o = new OutlineItem (pos, s); - + } else { - + if (parent instanceof Chapter) { - + o = new OutlineItem (pos, (Chapter) parent); } - + if (parent instanceof Scene) { - + o = new OutlineItem (pos, (Scene) parent); } } - - } - + + } + o.setKey (key); o.setName (rs.getString (ind++)); o.setDescription (new StringWithMarkup (rs.getString (ind++), @@ -89,34 +89,34 @@ private OutlineItem getOutlineItem (ResultSet rs, if (parent != null) { - + if (sceneKey > 0) { - + Scene s = (Scene) parent; - + s.addOutlineItem (o); - + } else { - + if (parent instanceof Chapter) { - + ((Chapter) parent).addOutlineItem (o); - + } - + if (parent instanceof Scene) { - + ((Scene) parent).addOutlineItem (o); - + } } } - + return o; } catch (Exception e) @@ -138,15 +138,12 @@ public List getObjects (Scene parent, try { - List params = new ArrayList (); - params.add (parent.getKey ()); - ResultSet rs = this.objectManager.executeQuery (STD_SELECT_PREFIX + " WHERE scenedbkey = ?", - params, + Arrays.asList (parent.getKey ()), conn); - List items = new ArrayList (); - + List items = new ArrayList<> (); + while (rs.next ()) { @@ -166,7 +163,7 @@ public List getObjects (Scene parent, } return items; - + } catch (Exception e) { @@ -175,7 +172,7 @@ public List getObjects (Scene parent, e); } - + } public List getObjects (Chapter parent, @@ -187,16 +184,13 @@ public List getObjects (Chapter parent, try { - List params = new ArrayList (); - params.add (parent.getKey ()); - // No scene allowed here. ResultSet rs = this.objectManager.executeQuery (STD_SELECT_PREFIX + " WHERE chapterdbkey = ? AND scenedbkey IS NULL", - params, + Arrays.asList (parent.getKey ()), conn); - List items = new ArrayList (); - + List items = new ArrayList<> (); + while (rs.next ()) { @@ -216,7 +210,7 @@ public List getObjects (Chapter parent, } return items; - + } catch (Exception e) { @@ -225,7 +219,7 @@ public List getObjects (Chapter parent, e); } - + } @Override @@ -237,22 +231,22 @@ public List getObjects (NamedObject parent, if (parent instanceof Scene) { - + return this.getObjects ((Scene) parent, conn, loadChildObjects); - + } - + if (parent instanceof Chapter) { - + return this.getObjects ((Chapter) parent, conn, loadChildObjects); - + } - + throw new IllegalArgumentException ("Unsupported parent object type: " + parent); @@ -268,34 +262,31 @@ public OutlineItem getObjectByKey (long key, try { - - List params = new ArrayList (); - params.add (key); - + // No scene allowed here. ResultSet rs = this.objectManager.executeQuery (STD_SELECT_PREFIX + " WHERE dbkey = ?", - params, + Arrays.asList (key), conn); - + if (rs.next ()) { - + return this.getOutlineItem (rs, parent, loadChildObjects); - + } - + return null; - + } catch (Exception e) { - + throw new GeneralException ("Unable to get outline item with key: " + key, e); - + } - + } @Override @@ -304,7 +295,7 @@ public void createObject (OutlineItem o, throws GeneralException { - List params = new ArrayList (); + List params = new ArrayList<> (); params.add (o.getKey ()); params.add (o.getPosition ()); params.add (o.getChapter ().getKey ()); @@ -328,16 +319,13 @@ public void createObject (OutlineItem o, @Override public void deleteObject (OutlineItem o, - boolean deleteChildObjects, + boolean deleteChildObjects, Connection conn) throws GeneralException { - List params = new ArrayList (); - params.add (o.getKey ()); - this.objectManager.executeStatement ("DELETE FROM outlineitem WHERE dbkey = ?", - params, + Arrays.asList (o.getKey ()), conn); } @@ -348,7 +336,7 @@ public void updateObject (OutlineItem o, throws GeneralException { - List params = new ArrayList (); + List params = new ArrayList<> (); params.add (o.getPosition ()); params.add (o.getChapter ().getKey ()); diff --git a/src/com/quollwriter/db/ProjectDataHandler.java b/src/main/java/com/quollwriter/db/ProjectDataHandler.java similarity index 95% rename from src/com/quollwriter/db/ProjectDataHandler.java rename to src/main/java/com/quollwriter/db/ProjectDataHandler.java index 19b857fc..ef9a365a 100644 --- a/src/com/quollwriter/db/ProjectDataHandler.java +++ b/src/main/java/com/quollwriter/db/ProjectDataHandler.java @@ -172,6 +172,18 @@ private Project getProject (ResultSet rs, conn, loadChildObjects); + List links = (List) this.objectManager.getObjects (Link.class, + p, + conn, + true); + + for (Link l : links) + { + + l.getObject1 ().addLink (l); + + } + /* p.setEditorProject ((EditorProject) this.objectManager.getObjectByKey (EditorProject.class, -1, @@ -202,7 +214,7 @@ private Project getProject (ResultSet rs, } Set items = c.getAllNamedChildObjects (); - +/* for (NamedObject ni : items) { @@ -276,6 +288,7 @@ private Project getProject (ResultSet rs, } } + */ } @@ -411,7 +424,7 @@ public List getWordCounts (Project p, try { - List params = new ArrayList (); + List params = new ArrayList<> (); params.add (p.getKey ()); String whereDays = ""; @@ -428,7 +441,7 @@ public List getWordCounts (Project p, params, conn); - List ret = new ArrayList (); + List ret = new ArrayList<> (); while (rs.next ()) { @@ -564,13 +577,10 @@ public void createObject (Project p, } - List params = new ArrayList (); - params.add (p.getKey ()); - params.add (Environment.getSchemaVersion ()); - params.add (p.getType ()); - this.objectManager.executeStatement ("INSERT INTO project (dbkey, schema_version, type) VALUES (?, ?, ?)", - params, + Arrays.asList (p.getKey (), + Environment.getSchemaVersion (), + p.getType ()), conn); // Need to create the project version first since the chapters rely on it. @@ -661,11 +671,9 @@ public void updateObject (Project p, throws GeneralException { - List params = new ArrayList (); - params.add (p.getLastEdited ()); - params.add (p.getKey ()); this.objectManager.executeStatement ("UPDATE project SET lastedited = ? WHERE dbkey = ?", - params, + Arrays.asList (p.getLastEdited (), + p.getKey ()), conn); } diff --git a/src/main/java/com/quollwriter/db/ProjectEditorDataHandler.java b/src/main/java/com/quollwriter/db/ProjectEditorDataHandler.java new file mode 100644 index 00000000..c47f4d48 --- /dev/null +++ b/src/main/java/com/quollwriter/db/ProjectEditorDataHandler.java @@ -0,0 +1,321 @@ +package com.quollwriter.db; + +import java.sql.*; +import java.io.*; +import java.util.*; + +import java.math.*; +import javax.crypto.*; +import java.security.*; + +import org.bouncycastle.bcpg.*; +import org.bouncycastle.openpgp.*; +import org.bouncycastle.crypto.generators.*; +import org.bouncycastle.crypto.params.*; +import org.bouncycastle.openpgp.operator.bc.*; + +import com.quollwriter.*; + +import com.quollwriter.data.*; +import com.quollwriter.data.editors.*; +import com.quollwriter.editors.*; +import com.quollwriter.editors.messages.*; + +public class ProjectEditorDataHandler implements DataHandler +{ + + private static final String STD_SELECT_PREFIX = "SELECT dbkey, editordbkey, forprojectid, forprojectname, status, statusmessage, current, editorfrom, editorto FROM projecteditor_v"; + + private ObjectManager objectManager = null; + + /** + * A cache, since the same projEditor can be viewed in multiple places and updated in multiple places + * we need a single object for the editor so that we have one object -> multiple viewers. + */ + private Map cache = new HashMap<> (); + + public ProjectEditorDataHandler (ObjectManager om) + { + + this.objectManager = om; + + } + + @Override + public void createObject (ProjectEditor pe, + Connection conn) + throws GeneralException + { + + if (pe.getForProjectId () == null) + { + + throw new GeneralException ("No for project id specified."); + + } + + if (pe.getEditor () == null) + { + + throw new GeneralException ("No editor is specified."); + + } + + this.objectManager.executeStatement ("INSERT INTO projecteditor " + + "(dbkey, " + + " editordbkey, " + + " forprojectid, " + + " forprojectname, " + + " status, " + + " statusmessage, " + + " current, " + + " editorfrom, " + + " editorto) " + + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)", + Arrays.asList (pe.getKey (), + pe.getEditor ().getKey (), + pe.getForProjectId (), + pe.getForProjectName (), + pe.getStatus ().getType (), + pe.getStatusMessage (), + pe.isCurrent (), + (pe.getEditorFrom () != null ? pe.getEditorFrom () : new java.util.Date ()), + pe.getEditorTo ()), + conn); + + this.cache.put (pe.getKey (), + pe); + + } + + @Override + public void deleteObject (ProjectEditor d, + boolean deleteChildObjects, + Connection conn) + throws GeneralException + { + + this.objectManager.executeStatement ("DELETE FROM projecteditor WHERE dbkey = ?", + Arrays.asList (d.getKey ()), + conn); + + this.cache.remove (d.getKey ()); + + } + + @Override + public void updateObject (ProjectEditor pe, + Connection conn) + throws GeneralException + { + + this.objectManager.executeStatement ("UPDATE projecteditor " + + "SET forprojectname = ?, " + + " status = ?, " + + " statusmessage = ?, " + + " current = ?, " + + " editorfrom = ?, " + + " editorto = ? " + + "WHERE dbkey = ?", + Arrays.asList (pe.getForProjectName (), + pe.getStatus ().getType (), + pe.getStatusMessage (), + pe.isCurrent (), + pe.getEditorFrom (), + pe.getEditorTo (), + pe.getKey ()), + conn); + + } + + @Override + public List getObjects (ProjectInfo p, + Connection conn, + boolean loadChildObjects) + throws GeneralException + { + + List ret = new ArrayList<> (); + + ResultSet rs = null; + + try + { + + rs = this.objectManager.executeQuery (STD_SELECT_PREFIX + " WHERE forprojectid = ? ORDER BY editorfrom", + Arrays.asList (p.getId ()), + conn); + + while (rs.next ()) + { + + ret.add (this.getProjectEditor (rs)); + + } + + } catch (Exception e) { + + throw new GeneralException ("Unable to load project editors for: " + + p, + e); + + } finally { + + try + { + + rs.close (); + + } catch (Exception e) + { + + } + + } + + return ret; + + } + + private ProjectEditor getProjectEditor (ResultSet rs) + throws GeneralException + { + + try + { + + int ind = 1; + + long key = rs.getLong (ind++); + + ProjectEditor pe = this.cache.get (key); + + if (pe != null) + { + + return pe; + + } + + pe = new ProjectEditor (); + + long edKey = rs.getLong (ind++); + + EditorEditor ed = EditorsEnvironment.getEditorByKey (edKey); + + pe.setKey (key); + pe.setEditor (ed); + pe.setForProjectId (rs.getString (ind++)); + pe.setForProjectName (rs.getString (ind++)); + pe.setStatus (ProjectEditor.Status.valueOf (rs.getString (ind++))); + pe.setStatusMessage (rs.getString (ind++)); + pe.setCurrent (rs.getBoolean (ind++)); + pe.setEditorFrom (rs.getTimestamp (ind++)); + pe.setEditorTo (rs.getTimestamp (ind++)); + + this.cache.put (key, + pe); + + return pe; + + } catch (Exception e) + { + + throw new GeneralException ("Unable to load project editor", + e); + + } + + } + + @Override + public ProjectEditor getObjectByKey (long key, + ProjectInfo p, + Connection conn, + boolean loadChildObjects) + throws GeneralException + { + + ResultSet rs = null; + + try + { + + rs = this.objectManager.executeQuery (STD_SELECT_PREFIX + " WHERE dbkey = ?", + Arrays.asList (key), + conn); + + if (rs.next ()) + { + + return this.getProjectEditor (rs); + + } + + return null; + + } catch (Exception e) { + + throw new GeneralException ("Unable to get project editor with key: " + + key, + e); + + } finally { + + try + { + + rs.close (); + + } catch (Exception e) + { + + } + + } + + } + + public void deleteFromAllProjects (EditorEditor ed, + Connection conn) + throws GeneralException + { + + List ret = new ArrayList<> (); + + ResultSet rs = null; + + try + { + + rs = this.objectManager.executeQuery (STD_SELECT_PREFIX + " WHERE editordbkey = ?", + Arrays.asList (ed.getKey ()), + conn); + + while (rs.next ()) + { + + ret.add (this.getProjectEditor (rs)); + + } + + } catch (Exception e) { + + throw new GeneralException ("Unable to load project editors for: " + + ed, + e); + + } + + for (ProjectEditor pe : ret) + { + + this.objectManager.deleteObject (pe, + true, + conn); + + } + + } + +} diff --git a/src/com/quollwriter/db/ProjectInfoDataHandler.java b/src/main/java/com/quollwriter/db/ProjectInfoDataHandler.java similarity index 79% rename from src/com/quollwriter/db/ProjectInfoDataHandler.java rename to src/main/java/com/quollwriter/db/ProjectInfoDataHandler.java index 9435185f..91afcb95 100644 --- a/src/com/quollwriter/db/ProjectInfoDataHandler.java +++ b/src/main/java/com/quollwriter/db/ProjectInfoDataHandler.java @@ -2,6 +2,7 @@ import java.sql.*; import java.io.*; +import java.nio.file.*; import java.util.*; @@ -21,8 +22,8 @@ public class ProjectInfoDataHandler implements DataHandler multiple viewers. */ - private Map cache = new HashMap (); - + private Map cache = new HashMap<> (); + public ProjectInfoDataHandler(ObjectManager om) { @@ -43,54 +44,55 @@ private ProjectInfo getProjectInfo (ResultSet rs, long key = rs.getLong (ind++); ProjectInfo p = this.cache.get (key); - + if (p != null) { - + return p; - - } - + + } + p = new ProjectInfo (); p.setKey (key); p.setName (rs.getString (ind++)); - p.setProjectDirectory (new File (rs.getString (ind++))); - p.setBackupDirectory (new File (rs.getString (ind++))); + p.setProjectDirectory (Paths.get (rs.getString (ind++))); + p.setBackupDirPath (Paths.get (rs.getString (ind++))); + // TODO p.setBackupDirectory (new File (rs.getString (ind++))); p.setStatus (rs.getString (ind++)); - + // Get the statistics which should look something like: // // // [value] // p.setStatistics (Utils.getStatisticsFromXML (rs.getString (ind++))); - + p.setEncrypted (rs.getBoolean (ind++)); p.setNoCredentials (rs.getBoolean (ind++)); - + String ic = rs.getString (ind++); - + if (ic != null) { - + p.setIcon (new File (ic)); - + } - + p.setType (rs.getString (ind++)); - + String edEmail = rs.getString (ind++); - + if (edEmail != null) { - + EditorEditor ed = EditorsEnvironment.getEditorByEmail (edEmail); - + p.setForEditor (ed); - + } - + p.setLastEdited (rs.getTimestamp (ind++)); p.setDescription (new StringWithMarkup (rs.getString (ind++), rs.getString (ind++))); @@ -99,10 +101,10 @@ private ProjectInfo getProjectInfo (ResultSet rs, p.setLastModified (rs.getTimestamp (ind++)); p.setDateCreated (rs.getTimestamp (ind++)); p.setPropertiesAsString (rs.getString (ind++)); - + this.cache.put (key, - p); - + p); + return p; } catch (Exception e) @@ -114,7 +116,7 @@ private ProjectInfo getProjectInfo (ResultSet rs, } } - + @Override public List getObjects (NamedObject parent, Connection conn, @@ -123,26 +125,26 @@ public List getObjects (NamedObject parent, { boolean closeConn = false; - + if (conn == null) { - + conn = this.objectManager.getConnection (); closeConn = true; - + } ResultSet rs = null; try { - + rs = this.objectManager.executeQuery (STD_SELECT_PREFIX, null, conn); - List ret = new ArrayList (); - + List ret = new ArrayList<> (); + while (rs.next ()) { @@ -150,11 +152,11 @@ public List getObjects (NamedObject parent, loadChildObjects); ret.add (p); - + } return ret; - + } catch (Exception e) { @@ -164,16 +166,16 @@ public List getObjects (NamedObject parent, } finally { - + if (closeConn) { - + this.objectManager.releaseConnection (conn); - + } } - + return null; } @@ -187,25 +189,22 @@ public ProjectInfo getObjectByKey (long key, { boolean closeConn = false; - + if (conn == null) { - + conn = this.objectManager.getConnection (); closeConn = true; - + } - + ResultSet rs = null; try { - List params = new ArrayList (); - params.add (key); - rs = this.objectManager.executeQuery (STD_SELECT_PREFIX + " WHERE dbkey = ?", - params, + Arrays.asList (key), conn); if (rs.next ()) @@ -226,20 +225,20 @@ public ProjectInfo getObjectByKey (long key, } finally { - + if (closeConn) { - + this.objectManager.releaseConnection (conn); - + } } - + return null; - + } - + @Override public void createObject (ProjectInfo p, Connection conn) @@ -251,48 +250,47 @@ public void createObject (ProjectInfo p, (p.getForEditor () == null) ) { - + throw new IllegalStateException ("If the project is for an editor then the forEditor must be specified."); - - } - - List params = new ArrayList (); + + } + + List params = new ArrayList<> (); params.add (p.getKey ()); params.add (p.getLastEdited ()); params.add (p.isEncrypted ()); params.add (p.isNoCredentials ()); - params.add (p.getProjectDirectory ().getPath ()); - params.add (p.getBackupDirectory ().getPath ()); + params.add (p.getProjectDirectory ().toString ()); + params.add (p.getBackupDirPath ().toString ()); + //params.add (p.getBackupDirectory ().getPath ()); params.add (p.getStatus ()); params.add (Utils.getStatisticsAsXML (p.getStatistics ())); params.add ((p.getIcon () != null ? p.getIcon ().getPath () : null)); params.add (p.getType ()); params.add ((p.getForEditor () != null ? p.getForEditor ().getEmail () : null)); - + this.objectManager.executeStatement ("INSERT INTO projectinfo (dbkey, lastedited, encrypted, nocredentials, directory, backupdirectory, status, statistics, icon, type, foreditor) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", params, conn); - + this.cache.put (p.getKey (), p); - + } @Override public void deleteObject (ProjectInfo p, - boolean deleteChildObjects, + boolean deleteChildObjects, Connection conn) throws GeneralException { - List params = new ArrayList (); - params.add (p.getKey ()); this.objectManager.executeStatement ("DELETE FROM projectinfo WHERE dbkey = ?", - params, + Arrays.asList (p.getKey ()), conn); this.cache.remove (p.getKey ()); - + } @Override @@ -301,17 +299,14 @@ public void updateObject (ProjectInfo p, throws GeneralException { - List params = new ArrayList (); - params.add (p.getLastEdited ()); - params.add (p.getProjectDirectory ().getPath ()); - params.add (p.getBackupDirectory ().getPath ()); - params.add (p.getStatus ()); - params.add (Utils.getStatisticsAsXML (p.getStatistics ())); - params.add ((p.getIcon () != null ? p.getIcon ().getPath () : null)); - - params.add (p.getKey ()); this.objectManager.executeStatement ("UPDATE projectinfo SET lastedited = ?, directory = ?, backupdirectory = ?, status = ?, statistics = ?, icon = ? WHERE dbkey = ?", - params, + Arrays.asList (p.getLastEdited (), + p.getProjectDirectory ().toString (), + p.getBackupDirPath ().toString (), + p.getStatus (), + Utils.getStatisticsAsXML (p.getStatistics ()), + (p.getIcon () != null ? p.getIcon ().getPath () : null), + p.getKey ()), conn); } diff --git a/src/com/quollwriter/db/ProjectInfoObjectManager.java b/src/main/java/com/quollwriter/db/ProjectInfoObjectManager.java similarity index 80% rename from src/com/quollwriter/db/ProjectInfoObjectManager.java rename to src/main/java/com/quollwriter/db/ProjectInfoObjectManager.java index 023d3ed3..988b11fb 100644 --- a/src/com/quollwriter/db/ProjectInfoObjectManager.java +++ b/src/main/java/com/quollwriter/db/ProjectInfoObjectManager.java @@ -3,9 +3,9 @@ import java.io.*; import java.util.*; import java.sql.*; -import javax.imageio.*; -import java.awt.image.*; -import javax.swing.*; +//import javax.imageio.*; +//import java.awt.image.*; +import javafx.scene.image.*; import org.bouncycastle.bcpg.*; import org.bouncycastle.openpgp.*; @@ -14,8 +14,6 @@ import org.bouncycastle.crypto.params.*; import org.bouncycastle.openpgp.operator.bc.*; -import com.gentlyweb.xml.*; - import com.quollwriter.*; import com.quollwriter.ui.*; import com.quollwriter.db.*; @@ -29,7 +27,7 @@ public class ProjectInfoObjectManager extends ObjectManager public static final String USER_PROPERTIES_OBJTYPE = "user-properties"; // Key is the object type string, maps to a user config object type. - private Map userConfigObjTypes = new HashMap (); + private Map userConfigObjTypes = new HashMap<> (); public ProjectInfoObjectManager () { @@ -39,6 +37,14 @@ public ProjectInfoObjectManager () } + @Override + public boolean supportsLinks () + { + + return false; + + } + public void init (File dir, String username, String password, @@ -52,7 +58,6 @@ public void init (File dir, password, filePassword, newSchemaVersion); - // Load the object types. Each type will register itself with the Environment. this.getObjects (UserConfigurableObjectType.class, null, @@ -212,6 +217,13 @@ public void addSession (Session s) throws GeneralException { + if (s.getStart () == null) + { + + return; + + } + Connection conn = null; try @@ -388,12 +400,7 @@ public com.gentlyweb.properties.Properties getUserProperties () String p = rs.getString (ind++); - com.gentlyweb.properties.Properties props = new com.gentlyweb.properties.Properties (JDOMUtils.getStringAsElement (p)); - - - //new ByteArrayInputStream (p.getBytes ()), - // null); - + com.gentlyweb.properties.Properties props = new com.gentlyweb.properties.Properties (DOM4JUtils.stringAsElement (p)); props.setId ("user"); return props; @@ -448,7 +455,7 @@ public void setUserProperties (com.gentlyweb.properties.Properties props) params = new ArrayList (); - String t = JDOMUtils.getElementAsString (props.getAsJDOMElement ()); + String t = DOM4JUtils.elementAsString (props.getAsElement ()); if (rs.next ()) { @@ -498,7 +505,7 @@ public void setUserProperties (com.gentlyweb.properties.Properties props) * It will create each object and the minimum required fields. */ public void initLegacyObjectTypes () - throws GeneralException + throws Exception { // If we have no user config object types then create the ones we need. @@ -508,11 +515,97 @@ public void initLegacyObjectTypes () if (chapT != null) { + // Check to make sure that the legacy types have their icons setup. + UserConfigurableObjectType assT = Environment.getUserConfigurableObjectType (QCharacter.OBJECT_TYPE); + + if (assT != null) + { + + if (assT.icon16x16Property ().getValue () == null) + { + + assT.setIcon16x16 (new Image (Utils.getResourceStream (Constants.LEGACY_CHARACTER_SMALL_ICON_IMAGE_NAME))); + + } + + if (assT.icon24x24Property ().getValue () == null) + { + + assT.setIcon24x24 (new Image (Utils.getResourceStream (Constants.LEGACY_CHARACTER_LARGE_ICON_IMAGE_NAME))); + + } + + } + + assT = Environment.getUserConfigurableObjectType (Location.OBJECT_TYPE); + + if (assT != null) + { + + if (assT.icon16x16Property ().getValue () == null) + { + + assT.setIcon16x16 (new Image (Utils.getResourceStream (Constants.LEGACY_LOCATION_SMALL_ICON_IMAGE_NAME))); + + } + + if (assT.icon24x24Property ().getValue () == null) + { + + assT.setIcon24x24 (new Image (Utils.getResourceStream (Constants.LEGACY_LOCATION_LARGE_ICON_IMAGE_NAME))); + + } + + } + + assT = Environment.getUserConfigurableObjectType (QObject.OBJECT_TYPE); + + if (assT != null) + { + + if (assT.icon16x16Property ().getValue () == null) + { + + assT.setIcon16x16 (new Image (Utils.getResourceStream (Constants.LEGACY_OBJECT_SMALL_ICON_IMAGE_NAME))); + + } + + if (assT.icon24x24Property ().getValue () == null) + { + + assT.setIcon24x24 (new Image (Utils.getResourceStream (Constants.LEGACY_OBJECT_LARGE_ICON_IMAGE_NAME))); + + } + + } + + assT = Environment.getUserConfigurableObjectType (ResearchItem.OBJECT_TYPE); + + if (assT != null) + { + + if (assT.icon16x16Property ().getValue () == null) + { + + assT.setIcon16x16 (new Image (Utils.getResourceStream (Constants.LEGACY_RESEARCHITEM_SMALL_ICON_IMAGE_NAME))); + + } + + if (assT.icon24x24Property ().getValue () == null) + { + + assT.setIcon24x24 (new Image (Utils.getResourceStream (Constants.LEGACY_RESEARCHITEM_LARGE_ICON_IMAGE_NAME))); + + } + + } + // Already inited. return; } + Set fields = new LinkedHashSet<> (); // Create the chapter type. UserConfigurableObjectType chapterType = new UserConfigurableObjectType (); @@ -520,12 +613,14 @@ public void initLegacyObjectTypes () //chapterType.setObjectTypeName (Environment.getObjectTypeName (Chapter.OBJECT_TYPE)); //chapterType.setObjectTypeNamePlural (Environment.getObjectTypeNamePlural (Chapter.OBJECT_TYPE)); chapterType.setLayout (null); - chapterType.setCreateShortcutKeyStroke (KeyStroke.getKeyStroke ("ctrl shift H")); + // TODO DO! chapterType.setCreateShortcutKeyStroke (KeyStroke.getKeyStroke ("ctrl shift H")); + /* + TODO chapterType.setIcon24x24 (Environment.getObjectIcon (Chapter.OBJECT_TYPE, Constants.ICON_TITLE)); chapterType.setIcon16x16 (Environment.getObjectIcon (Chapter.OBJECT_TYPE, Constants.ICON_SIDEBAR)); - + */ chapterType.setUserObjectType (Chapter.OBJECT_TYPE); // Add the fields. @@ -534,6 +629,8 @@ public void initLegacyObjectTypes () // Description ObjectDescriptionUserConfigurableObjectTypeField descF = new ObjectDescriptionUserConfigurableObjectTypeField (); + descF.setUserConfigurableObjectType (chapterType); + descF.setSearchable (true); /* descF.setFormName (Environment.getUIString (LanguageStrings.chapters, @@ -543,11 +640,10 @@ public void initLegacyObjectTypes () //LegacyUserConfigurableObject.DESCRIPTION_LEGACY_FIELD_FORM_NAME); descF.setLegacyFieldId (LegacyUserConfigurableObject.DESCRIPTION_LEGACY_FIELD_ID); - chapterType.addConfigurableField (descF); - // Plan MultiTextUserConfigurableObjectTypeField planF = new MultiTextUserConfigurableObjectTypeField (); + planF.setUserConfigurableObjectType (chapterType); planF.setSearchable (true); planF.setDisplayAsBullets (true); /* @@ -558,10 +654,9 @@ public void initLegacyObjectTypes () //Chapter.PLAN_LEGACY_FIELD_FORM_NAME); planF.setLegacyFieldId (Chapter.PLAN_LEGACY_FIELD_ID); - chapterType.addConfigurableField (planF); - MultiTextUserConfigurableObjectTypeField goalsF = new MultiTextUserConfigurableObjectTypeField (); + goalsF.setUserConfigurableObjectType (chapterType); goalsF.setSearchable (true); goalsF.setDisplayAsBullets (true); /* @@ -572,7 +667,7 @@ public void initLegacyObjectTypes () //Chapter.GOALS_LEGACY_FIELD_FORM_NAME); goalsF.setLegacyFieldId (Chapter.GOALS_LEGACY_FIELD_ID); - chapterType.addConfigurableField (goalsF); + chapterType.setConfigurableFields (Arrays.asList (descF, planF, goalsF)); Environment.addUserConfigurableObjectType (chapterType); @@ -583,16 +678,24 @@ public void initLegacyObjectTypes () //characterType.setObjectTypeNamePlural (Environment.getObjectTypeNamePlural (QCharacter.OBJECT_TYPE)); characterType.setLayout (null); characterType.setAssetObjectType (true); - characterType.setCreateShortcutKeyStroke (KeyStroke.getKeyStroke ("ctrl shift C")); + // TODO DO! characterType.setCreateShortcutKeyStroke (KeyStroke.getKeyStroke ("ctrl shift C")); + characterType.setIcon16x16 (new Image (Utils.getResourceStream (Constants.LEGACY_CHARACTER_SMALL_ICON_IMAGE_NAME))); + characterType.setIcon24x24 (new Image (Utils.getResourceStream (Constants.LEGACY_CHARACTER_LARGE_ICON_IMAGE_NAME))); + + /* + TODO characterType.setIcon24x24 (Environment.getObjectIcon (QCharacter.OBJECT_TYPE, Constants.ICON_TITLE)); characterType.setIcon16x16 (Environment.getObjectIcon (QCharacter.OBJECT_TYPE, Constants.ICON_SIDEBAR)); + */ characterType.setUserObjectType (QCharacter.OBJECT_TYPE); // Name ObjectNameUserConfigurableObjectTypeField nameF = new ObjectNameUserConfigurableObjectTypeField (); + nameF.setUserConfigurableObjectType (characterType); + /* nameF.setFormName (Environment.getUIString (LanguageStrings.assets, LanguageStrings.legacyfields, @@ -601,11 +704,10 @@ public void initLegacyObjectTypes () //LegacyUserConfigurableObject.NAME_LEGACY_FIELD_FORM_NAME); nameF.setLegacyFieldId (LegacyUserConfigurableObject.NAME_LEGACY_FIELD_ID); - characterType.addConfigurableField (nameF); - // Aliases UserConfigurableObjectTypeField aliasesF = UserConfigurableObjectTypeField.Type.getNewFieldForType (UserConfigurableObjectTypeField.Type.multitext); + aliasesF.setUserConfigurableObjectType (characterType); aliasesF.setNameField (true); aliasesF.setSearchable (true); /* @@ -616,11 +718,10 @@ public void initLegacyObjectTypes () //LegacyUserConfigurableObject.ALIASES_LEGACY_FIELD_FORM_NAME); aliasesF.setLegacyFieldId (LegacyUserConfigurableObject.ALIASES_LEGACY_FIELD_ID); - characterType.addConfigurableField (aliasesF); - // Description ObjectDescriptionUserConfigurableObjectTypeField cdescF = new ObjectDescriptionUserConfigurableObjectTypeField (); + cdescF.setUserConfigurableObjectType (characterType); cdescF.setLegacyFieldId (LegacyUserConfigurableObject.DESCRIPTION_LEGACY_FIELD_ID); cdescF.setSearchable (true); /* @@ -630,7 +731,7 @@ public void initLegacyObjectTypes () */ //LegacyUserConfigurableObject.DESCRIPTION_LEGACY_FIELD_FORM_NAME); - characterType.addConfigurableField (cdescF); + characterType.setConfigurableFields (Arrays.asList (nameF, aliasesF, cdescF)); Environment.addUserConfigurableObjectType (characterType); @@ -641,16 +742,24 @@ public void initLegacyObjectTypes () //locType.setObjectTypeNamePlural (Environment.getObjectTypeNamePlural (Location.OBJECT_TYPE)); locType.setLayout (null); locType.setAssetObjectType (true); - locType.setCreateShortcutKeyStroke (KeyStroke.getKeyStroke ("ctrl shift L")); + // TODO DO! locType.setCreateShortcutKeyStroke (KeyStroke.getKeyStroke ("ctrl shift L")); + locType.setIcon16x16 (new Image (Utils.getResourceStream (Constants.LEGACY_LOCATION_SMALL_ICON_IMAGE_NAME))); + locType.setIcon24x24 (new Image (Utils.getResourceStream (Constants.LEGACY_LOCATION_LARGE_ICON_IMAGE_NAME))); + + /* + TODO? locType.setIcon24x24 (Environment.getObjectIcon (Location.OBJECT_TYPE, Constants.ICON_TITLE)); locType.setIcon16x16 (Environment.getObjectIcon (Location.OBJECT_TYPE, Constants.ICON_SIDEBAR)); + */ locType.setUserObjectType (Location.OBJECT_TYPE); // Name nameF = new ObjectNameUserConfigurableObjectTypeField (); + nameF.setUserConfigurableObjectType (locType); + /* nameF.setFormName (Environment.getUIString (LanguageStrings.assets, LanguageStrings.legacyfields, @@ -659,11 +768,10 @@ public void initLegacyObjectTypes () //LegacyUserConfigurableObject.NAME_LEGACY_FIELD_FORM_NAME); nameF.setLegacyFieldId (LegacyUserConfigurableObject.NAME_LEGACY_FIELD_ID); - locType.addConfigurableField (nameF); - // Description cdescF = new ObjectDescriptionUserConfigurableObjectTypeField (); + cdescF.setUserConfigurableObjectType (locType); cdescF.setSearchable (true); /* cdescF.setFormName (Environment.getUIString (LanguageStrings.assets, @@ -673,7 +781,7 @@ public void initLegacyObjectTypes () //LegacyUserConfigurableObject.DESCRIPTION_LEGACY_FIELD_FORM_NAME); cdescF.setLegacyFieldId (LegacyUserConfigurableObject.DESCRIPTION_LEGACY_FIELD_ID); - locType.addConfigurableField (cdescF); + locType.setConfigurableFields (Arrays.asList (nameF, cdescF)); Environment.addUserConfigurableObjectType (locType); @@ -684,16 +792,22 @@ public void initLegacyObjectTypes () //qobjType.setObjectTypeNamePlural (Environment.getObjectTypeNamePlural (QObject.OBJECT_TYPE)); qobjType.setLayout (null); qobjType.setAssetObjectType (true); - qobjType.setCreateShortcutKeyStroke (KeyStroke.getKeyStroke ("ctrl shift I")); + // TODO DO! qobjType.setCreateShortcutKeyStroke (KeyStroke.getKeyStroke ("ctrl shift I")); + qobjType.setIcon16x16 (new Image (Utils.getResourceStream (Constants.LEGACY_OBJECT_SMALL_ICON_IMAGE_NAME))); + qobjType.setIcon24x24 (new Image (Utils.getResourceStream (Constants.LEGACY_OBJECT_LARGE_ICON_IMAGE_NAME))); + + /* + TODO qobjType.setIcon24x24 (Environment.getObjectIcon (QObject.OBJECT_TYPE, Constants.ICON_TITLE)); qobjType.setIcon16x16 (Environment.getObjectIcon (QObject.OBJECT_TYPE, Constants.ICON_SIDEBAR)); + */ qobjType.setUserObjectType (QObject.OBJECT_TYPE); // Name nameF = new ObjectNameUserConfigurableObjectTypeField (); - + nameF.setUserConfigurableObjectType (qobjType); /* nameF.setFormName (Environment.getUIString (LanguageStrings.assets, LanguageStrings.legacyfields, @@ -702,11 +816,10 @@ public void initLegacyObjectTypes () //LegacyUserConfigurableObject.NAME_LEGACY_FIELD_FORM_NAME); nameF.setLegacyFieldId (LegacyUserConfigurableObject.NAME_LEGACY_FIELD_ID); - qobjType.addConfigurableField (nameF); - // Type SelectUserConfigurableObjectTypeField typeF = new SelectUserConfigurableObjectTypeField (); + typeF.setUserConfigurableObjectType (qobjType); typeF.setLegacyFieldId (QObject.TYPE_LEGACY_FIELD_ID); /* typeF.setFormName (Environment.getUIString (LanguageStrings.assets, @@ -746,11 +859,10 @@ public void initLegacyObjectTypes () typeF.setItems (ts); - qobjType.addConfigurableField (typeF); - // Description cdescF = new ObjectDescriptionUserConfigurableObjectTypeField (); + cdescF.setUserConfigurableObjectType (qobjType); cdescF.setSearchable (true); /* cdescF.setFormName (Environment.getUIString (LanguageStrings.assets, @@ -760,7 +872,7 @@ public void initLegacyObjectTypes () //LegacyUserConfigurableObject.DESCRIPTION_LEGACY_FIELD_FORM_NAME); cdescF.setLegacyFieldId (LegacyUserConfigurableObject.DESCRIPTION_LEGACY_FIELD_ID); - qobjType.addConfigurableField (cdescF); + qobjType.setConfigurableFields (Arrays.asList (nameF, typeF, cdescF)); Environment.addUserConfigurableObjectType (qobjType); @@ -771,16 +883,23 @@ public void initLegacyObjectTypes () //riType.setObjectTypeNamePlural (Environment.getObjectTypeNamePlural (ResearchItem.OBJECT_TYPE)); riType.setLayout (null); riType.setAssetObjectType (true); - riType.setCreateShortcutKeyStroke (KeyStroke.getKeyStroke ("ctrl shift R")); + // TODO DO! riType.setCreateShortcutKeyStroke (KeyStroke.getKeyStroke ("ctrl shift R")); + riType.setIcon16x16 (new Image (Utils.getResourceStream (Constants.LEGACY_RESEARCHITEM_SMALL_ICON_IMAGE_NAME))); + riType.setIcon24x24 (new Image (Utils.getResourceStream (Constants.LEGACY_RESEARCHITEM_LARGE_ICON_IMAGE_NAME))); + + /* + TODO riType.setIcon24x24 (Environment.getObjectIcon (ResearchItem.OBJECT_TYPE, Constants.ICON_TITLE)); riType.setIcon16x16 (Environment.getObjectIcon (ResearchItem.OBJECT_TYPE, Constants.ICON_SIDEBAR)); + */ riType.setUserObjectType (ResearchItem.OBJECT_TYPE); // Name nameF = new ObjectNameUserConfigurableObjectTypeField (); + nameF.setUserConfigurableObjectType (riType); /* nameF.setFormName (Environment.getUIString (LanguageStrings.assets, LanguageStrings.legacyfields, @@ -789,11 +908,10 @@ public void initLegacyObjectTypes () //LegacyUserConfigurableObject.NAME_LEGACY_FIELD_FORM_NAME); nameF.setLegacyFieldId (LegacyUserConfigurableObject.NAME_LEGACY_FIELD_ID); - riType.addConfigurableField (nameF); - // Web link WebpageUserConfigurableObjectTypeField webF = new WebpageUserConfigurableObjectTypeField (); + webF.setUserConfigurableObjectType (riType); webF.setLegacyFieldId (ResearchItem.WEB_PAGE_LEGACY_FIELD_ID); /* webF.setFormName (Environment.getUIString (LanguageStrings.assets, @@ -802,11 +920,10 @@ public void initLegacyObjectTypes () */ //ResearchItem.WEB_PAGE_LEGACY_FIELD_FORM_NAME); - riType.addConfigurableField (webF); - // Description cdescF = new ObjectDescriptionUserConfigurableObjectTypeField (); + cdescF.setUserConfigurableObjectType (riType); cdescF.setSearchable (true); /* cdescF.setFormName (Environment.getUIString (LanguageStrings.assets, @@ -816,7 +933,7 @@ public void initLegacyObjectTypes () //LegacyUserConfigurableObject.DESCRIPTION_LEGACY_FIELD_FORM_NAME); cdescF.setLegacyFieldId (LegacyUserConfigurableObject.DESCRIPTION_LEGACY_FIELD_ID); - riType.addConfigurableField (cdescF); + riType.setConfigurableFields (Arrays.asList (nameF, webF, cdescF)); Environment.addUserConfigurableObjectType (riType); diff --git a/src/com/quollwriter/db/ProjectVersionDataHandler.java b/src/main/java/com/quollwriter/db/ProjectVersionDataHandler.java similarity index 83% rename from src/com/quollwriter/db/ProjectVersionDataHandler.java rename to src/main/java/com/quollwriter/db/ProjectVersionDataHandler.java index 7a58b737..e7084fb5 100644 --- a/src/com/quollwriter/db/ProjectVersionDataHandler.java +++ b/src/main/java/com/quollwriter/db/ProjectVersionDataHandler.java @@ -51,7 +51,7 @@ private ProjectVersion getProjectVersion (ResultSet rs) pv.setId (rs.getString (ind++)); pv.setVersion (rs.getString (ind++)); pv.setLatest (rs.getBoolean (ind++)); - + return pv; } catch (Exception e) @@ -64,7 +64,7 @@ private ProjectVersion getProjectVersion (ResultSet rs) } - @Override + @Override public List getObjects (Project proj, Connection conn, boolean loadChildObjects) @@ -73,43 +73,43 @@ public List getObjects (Project proj, try { - - List ret = new ArrayList (); - + + List ret = new ArrayList<> (); + ResultSet rs = this.objectManager.executeQuery (STD_SELECT_PREFIX + " ORDER BY datecreated", null, conn); - + while (rs.next ()) { - + ret.add (this.getProjectVersion (rs)); - + } - + if (loadChildObjects) { - + // Get all the chapters with the version. - + } - + try { - + rs.close (); - + } catch (Exception e) { } return ret; - + } catch (Exception e) { - + throw new GeneralException ("Uanble to get all project versions", e); - + } } @@ -124,40 +124,37 @@ public ProjectVersion getObjectByKey (long key, try { - + ProjectVersion pv = null; - - List params = new ArrayList (); - params.add (key); - + ResultSet rs = this.objectManager.executeQuery (STD_SELECT_PREFIX + " WHERE dbkey = ?", - params, + Arrays.asList (key), conn); - + if (rs.next ()) { - + pv = this.getProjectVersion (rs); - + } - + try { - + rs.close (); - + } catch (Exception e) { } - + return pv; - + } catch (Exception e) { - + throw new GeneralException ("Unable to get project version: " + key, e); - + } } @@ -166,38 +163,35 @@ public ProjectVersion getById (String id) throws GeneralException { - Connection conn = this.objectManager.getConnection (); - + Connection conn = this.objectManager.getConnection (); + try { - + ProjectVersion pv = null; - - List params = new ArrayList (); - params.add (id); - + ResultSet rs = this.objectManager.executeQuery (STD_SELECT_PREFIX + " WHERE id = ?", - params, + Arrays.asList (id), conn); - + if (rs.next ()) { - + pv = this.getProjectVersion (rs); - + } - + try { - + rs.close (); - + } catch (Exception e) { } - + return pv; - + } catch (Exception e) { this.objectManager.throwException (conn, @@ -206,11 +200,11 @@ public ProjectVersion getById (String id) e); } finally { - + this.objectManager.releaseConnection (conn); - + } - + return null; } @@ -218,44 +212,44 @@ public ProjectVersion getById (String id) public ProjectVersion getLatest (Connection conn) throws GeneralException { - + boolean closeConn = false; - + if (conn == null) { - + conn = this.objectManager.getConnection (); closeConn = true; - + } - + try { - + ProjectVersion pv = null; - + ResultSet rs = this.objectManager.executeQuery (STD_SELECT_PREFIX + " WHERE latest = TRUE", null, conn); - + if (rs.next ()) { - + pv = this.getProjectVersion (rs); - + } - + try { - + rs.close (); - + } catch (Exception e) { } - + return pv; - + } catch (Exception e) { this.objectManager.throwException (conn, @@ -263,16 +257,16 @@ public ProjectVersion getLatest (Connection conn) e); } finally { - + if (closeConn) { - + this.objectManager.releaseConnection (conn); - + } - + } - + return null; } @@ -283,29 +277,23 @@ public void createObject (ProjectVersion pv, throws GeneralException { - List params = new ArrayList (); - params.add (ProjectVersion.OBJECT_TYPE); - // Mark all other versions as previous. this.objectManager.executeStatement ("UPDATE dataobject SET latest = FALSE WHERE objecttype = ?", - params, + Arrays.asList (ProjectVersion.OBJECT_TYPE), conn); - - params = new ArrayList (); - params.add (pv.getKey ()); - params.add (pv.getDueDate ()); - + this.objectManager.executeStatement ("INSERT INTO projectversion (dbkey, due) VALUES (?, ?)", - params, + Arrays.asList (pv.getKey (), + pv.getDueDate ()), conn); this.objectManager.setLatestVersion (pv, true, conn); - + } - @Override + @Override public void deleteObject (ProjectVersion pv, boolean deleteChildObjects, Connection conn) @@ -315,18 +303,18 @@ public void deleteObject (ProjectVersion pv, throw new UnsupportedOperationException ("Not supported for project versions."); /* ProjectVersion pv = (ProjectVersion) d; - + ChapterDataHandler cdh = (ChapterDataHandler) this.objectManager.getHandler (Chapter.class); List params = new ArrayList (); params.add (pv.getKey ()); - + this.objectManager.executeStatement ("DELETE FROM projectversion WHERE dbkey = ?", params, conn); this.versions.remove (pv.getKey ()); - */ + */ } @Override @@ -336,7 +324,7 @@ public void updateObject (ProjectVersion pv, { throw new UnsupportedOperationException ("Not supported for project versions."); - + } } diff --git a/src/com/quollwriter/db/ResearchItemDataHandler.java b/src/main/java/com/quollwriter/db/ResearchItemDataHandler.java similarity index 82% rename from src/com/quollwriter/db/ResearchItemDataHandler.java rename to src/main/java/com/quollwriter/db/ResearchItemDataHandler.java index 8d3a71e4..17ca2212 100644 --- a/src/com/quollwriter/db/ResearchItemDataHandler.java +++ b/src/main/java/com/quollwriter/db/ResearchItemDataHandler.java @@ -37,7 +37,7 @@ private ResearchItem getResearchItem (ResultSet rs, ResearchItem l = new ResearchItem (); l.setKey (key); - + // Load the object fields. this.objectManager.setUserConfigurableObjectFields (l, rs.getStatement ().getConnection ()); @@ -45,33 +45,33 @@ private ResearchItem getResearchItem (ResultSet rs, l.setName (rs.getString (ind++)); l.setDescription (new StringWithMarkup (rs.getString (ind++), rs.getString (ind++))); - + l.setFiles (Utils.getFilesFromXML (rs.getString (ind++))); l.setLastModified (rs.getTimestamp (ind++)); l.setDateCreated (rs.getTimestamp (ind++)); l.setPropertiesAsString (rs.getString (ind++)); - + if (l.getLegacyField (ResearchItem.WEB_PAGE_LEGACY_FIELD_ID) == null) { - + l.setUrl (rs.getString (ind++)); - + } else { - + ind++; - + } - + l.setId (rs.getString (ind++)); - l.setVersion (rs.getString (ind++)); - + l.setVersion (rs.getString (ind++)); + if (proj != null) { - + proj.addAsset (l); - + } - + // Get all the notes. if (loadChildObjects) { @@ -106,12 +106,8 @@ public ResearchItem getObjectByKey (long key, try { - List params = new ArrayList (); - params.add (key); - //params.add (proj.getKey ()); - ResultSet rs = this.objectManager.executeQuery (STD_SELECT_PREFIX + " WHERE latest = TRUE AND dbkey = ?", // AND projectdbkey = ?", - params, + Arrays.asList (key), conn); if (rs.next ()) @@ -152,16 +148,13 @@ public List getObjects (Project parent, throws GeneralException { - List ret = new ArrayList (); + List ret = new ArrayList<> (); try { - List params = new ArrayList (); - params.add (parent.getKey ()); - ResultSet rs = this.objectManager.executeQuery (STD_SELECT_PREFIX + " WHERE latest = TRUE AND projectdbkey = ?", - params, + Arrays.asList (parent.getKey ()), conn); while (rs.next ()) @@ -201,29 +194,23 @@ public void createObject (ResearchItem r, throws GeneralException { - List params = new ArrayList (); - params.add (r.getKey ()); - params.add (r.getUrl ()); - params.add (r.getProject ().getKey ()); - this.objectManager.executeStatement ("INSERT INTO researchitem (dbkey, url, projectdbkey) VALUES (?, ?, ?)", - params, + Arrays.asList (r.getKey (), + r.getUrl (), + r.getProject ().getKey ()), conn); } @Override public void deleteObject (ResearchItem r, - boolean deleteChildObjects, + boolean deleteChildObjects, Connection conn) throws GeneralException { - List params = new ArrayList (); - params.add (r.getKey ()); - this.objectManager.executeStatement ("DELETE FROM researchitem WHERE dbkey = ?", - params, + Arrays.asList (r.getKey ()), conn); } @@ -234,12 +221,9 @@ public void updateObject (ResearchItem r, throws GeneralException { - List params = new ArrayList (); - params.add (r.getUrl ()); - params.add (r.getKey ()); - this.objectManager.executeStatement ("UPDATE researchitem SET url = ? WHERE dbkey = ?", - params, + Arrays.asList (r.getUrl (), + r.getKey ()), conn); } diff --git a/src/com/quollwriter/db/SceneDataHandler.java b/src/main/java/com/quollwriter/db/SceneDataHandler.java similarity index 83% rename from src/com/quollwriter/db/SceneDataHandler.java rename to src/main/java/com/quollwriter/db/SceneDataHandler.java index d67f9643..71bffa59 100644 --- a/src/com/quollwriter/db/SceneDataHandler.java +++ b/src/main/java/com/quollwriter/db/SceneDataHandler.java @@ -50,11 +50,11 @@ private Scene getScene (ResultSet rs, if (parent != null) { - + parent.addScene (s); - + } - + // Get all the notes. if (loadChildObjects) @@ -66,7 +66,7 @@ private Scene getScene (ResultSet rs, s, conn, loadChildObjects); - + } return s; @@ -91,13 +91,10 @@ public List getObjects (Chapter parent, try { - List ret = new ArrayList (); - - List params = new ArrayList (); - params.add (parent.getKey ()); - + List ret = new ArrayList<> (); + ResultSet rs = this.objectManager.executeQuery (STD_SELECT_PREFIX + " WHERE chapterdbkey = ?", - params, + Arrays.asList (parent.getKey ()), conn); while (rs.next ()) @@ -119,7 +116,7 @@ public List getObjects (Chapter parent, } return ret; - + } catch (Exception e) { @@ -141,31 +138,28 @@ public Scene getObjectByKey (long key, try { - - List params = new ArrayList (); - params.add (key); - + ResultSet rs = this.objectManager.executeQuery (STD_SELECT_PREFIX + " WHERE dbkey = ?", - params, + Arrays.asList (key), conn); - + if (rs.next ()) { - + return this.getScene (rs, parent, loadChildObjects); - + } - + return null; - + } catch (Exception e) { - + throw new GeneralException ("Unable to get scene with key: " + key, e); - + } } @@ -176,13 +170,10 @@ public void createObject (Scene s, throws GeneralException { - List params = new ArrayList (); - params.add (s.getKey ()); - params.add (s.getChapter ().getKey ()); - params.add (s.getPosition ()); - this.objectManager.executeStatement ("INSERT INTO scene (dbkey, chapterdbkey, position) VALUES (?, ?, ?)", - params, + Arrays.asList (s.getKey (), + s.getChapter ().getKey (), + s.getPosition ()), conn); for (OutlineItem i : s.getOutlineItems ()) @@ -208,34 +199,32 @@ public void deleteObject (Scene s, // Delete the outline items. for (OutlineItem i : s.getOutlineItems ()) { - + this.objectManager.deleteObject (i, true, conn); - + } } else { - + + Set its = new LinkedHashSet<> (s.getOutlineItems ()); + // Remove the scene from the item. - for (OutlineItem i : s.getOutlineItems ()) + for (OutlineItem i : its) { - + i.setScene (null); - + this.objectManager.saveObject (i, conn); - + } - - - } - List params = new ArrayList (); - params.add (s.getKey ()); + } this.objectManager.executeStatement ("DELETE FROM scene WHERE dbkey = ?", - params, + Arrays.asList (s.getKey ()), conn); } @@ -246,13 +235,10 @@ public void updateObject (Scene s, throws GeneralException { - List params = new ArrayList (); - params.add (s.getPosition ()); - params.add (s.getChapter ().getKey ()); - params.add (s.getKey ()); - this.objectManager.executeStatement ("UPDATE scene SET position = ?, chapterdbkey = ? WHERE dbkey = ?", - params, + Arrays.asList (s.getPosition (), + s.getChapter ().getKey (), + s.getKey ()), conn); for (OutlineItem i : s.getOutlineItems ()) diff --git a/src/com/quollwriter/db/TagDataHandler.java b/src/main/java/com/quollwriter/db/TagDataHandler.java similarity index 100% rename from src/com/quollwriter/db/TagDataHandler.java rename to src/main/java/com/quollwriter/db/TagDataHandler.java diff --git a/src/com/quollwriter/db/UserConfigurableObjectFieldDataHandler.java b/src/main/java/com/quollwriter/db/UserConfigurableObjectFieldDataHandler.java similarity index 89% rename from src/com/quollwriter/db/UserConfigurableObjectFieldDataHandler.java rename to src/main/java/com/quollwriter/db/UserConfigurableObjectFieldDataHandler.java index 2db47f01..b0cd977f 100644 --- a/src/com/quollwriter/db/UserConfigurableObjectFieldDataHandler.java +++ b/src/main/java/com/quollwriter/db/UserConfigurableObjectFieldDataHandler.java @@ -31,13 +31,10 @@ public void deleteAllFieldsForObject (UserConfigurableObject obj, try { - List params = new ArrayList (); - params.add (obj.getKey ()); - ResultSet rs = this.objectManager.executeQuery ("SELECT dbkey FROM userobjectfield_v WHERE namedobjectdbkey = ?", - params, + Arrays.asList (obj.getKey ()), conn); - + // Create a fake field. UserConfigurableObjectType _t = new UserConfigurableObjectType (); _t.setAssetObjectType (true); @@ -99,6 +96,9 @@ private UserConfigurableObjectField getUserConfigurableObjectField (ResultSet String v = rs.getString (ind++); + f.setValue (v); + /* + TODO Remove if (v != null) { @@ -107,7 +107,7 @@ private UserConfigurableObjectField getUserConfigurableObjectField (ResultSet null).stringToValue (v)); } - +*/ f.setName (rs.getString (ind++)); f.setDescription (new StringWithMarkup (rs.getString (ind++), @@ -137,16 +137,13 @@ public List getObjects (UserConfigurableObject pare throws GeneralException { - List ret = new ArrayList (); + List ret = new ArrayList<> (); try { - List params = new ArrayList (); - params.add (parent.getKey ()); - ResultSet rs = this.objectManager.executeQuery (STD_SELECT_PREFIX + " WHERE latest = TRUE AND namedobjectdbkey = ?", - params, + Arrays.asList (parent.getKey ()), conn); while (rs.next ()) @@ -201,11 +198,8 @@ public UserConfigurableObjectField getObjectByKey (long key, try { - List params = new ArrayList (); - params.add (key); - ResultSet rs = this.objectManager.executeQuery (STD_SELECT_PREFIX + " WHERE latest = TRUE AND dbkey = ?", - params, + Arrays.asList (key), conn); if (rs.next ()) @@ -260,15 +254,18 @@ public void createObject (UserConfigurableObjectField t, } - List params = new ArrayList (); + List params = new ArrayList<> (); params.add (t.getKey ()); params.add (t.getUserConfigurableObjectTypeField ().getKey ()); params.add (t.getParent ().getKey ()); - - params.add (t.getUserConfigurableObjectTypeField ().getViewEditHandler (t.getParentObject (), + params.add (t.getValue ()); +/* +TODO Remove + params.add (t.getUserConfigurableObjectTypeField ().getViewEditHandler2 (t.getParentObject (), t, - null).valueToString (t.getValue ())); - + null, + null).valueToString ((t != null ? t.getValue () : null))); +*/ this.objectManager.executeStatement ("INSERT INTO userobjectfield (dbkey, userobjecttypefielddbkey, namedobjectdbkey, value) VALUES (?, ?, ?, ?)", params, conn); @@ -281,7 +278,7 @@ public void deleteObject (UserConfigurableObjectField t, throws GeneralException { - Set filesToDelete = new HashSet (); + Set filesToDelete = new HashSet<> (); for (String fn : t.getProjectFileNames ()) { @@ -297,11 +294,8 @@ public void deleteObject (UserConfigurableObjectField t, } - List params = new ArrayList (); - params.add (t.getKey ()); - this.objectManager.executeStatement ("DELETE FROM userobjectfield WHERE dbkey = ?", - params, + Arrays.asList (t.getKey ()), conn); for (String fn : filesToDelete) @@ -317,19 +311,15 @@ public void updateObject (UserConfigurableObjectField t, Connection conn) throws GeneralException { - - List params = new ArrayList (); - - - String val = t.getUserConfigurableObjectTypeField ().getViewEditHandler (t.getParentObject (), +/* +TODO Remove + String val = t.getUserConfigurableObjectTypeField ().getViewEditHandler2 (t.getParentObject (), t, - null).valueToString (t.getValue ()); - params.add (val); - - params.add (t.getKey ()); - + null, + null).valueToString ((t != null ? t.getValue (): null)); +*/ this.objectManager.executeStatement ("UPDATE userobjectfield SET value = ? WHERE dbkey = ?", - params, + Arrays.asList (t.getValue (), t.getKey ()), conn); } diff --git a/src/main/java/com/quollwriter/db/UserConfigurableObjectTypeDataHandler.java b/src/main/java/com/quollwriter/db/UserConfigurableObjectTypeDataHandler.java new file mode 100644 index 00000000..ac34e02b --- /dev/null +++ b/src/main/java/com/quollwriter/db/UserConfigurableObjectTypeDataHandler.java @@ -0,0 +1,298 @@ +package com.quollwriter.db; + +import java.sql.*; + +import java.util.*; + +import com.quollwriter.*; + +import com.quollwriter.ui.fx.*; +import com.quollwriter.data.*; + +public class UserConfigurableObjectTypeDataHandler implements DataHandler +{ + + private static final String STD_SELECT_PREFIX = "SELECT dbkey, userobjtype, name, pluralname, description, markup, icon24x24, icon16x16, layout, assetobjtype, createshortcutkey, lastmodified, datecreated, properties, id, version FROM userobjecttype_v "; + + private ObjectManager objectManager = null; + + /** + * A cache, since the same type can be used in multiple places + * we need a single object so that we have one object -> multiple uses. + */ + private Map cache = new HashMap (); + + public UserConfigurableObjectTypeDataHandler (ObjectManager om) + { + + this.objectManager = om; + + } + + private UserConfigurableObjectType getUserConfigurableObjectType (ResultSet rs, + NamedObject parent, + boolean loadChildObjects) + throws GeneralException + { + + try + { + + int ind = 1; + + long key = rs.getLong (ind++); + + UserConfigurableObjectType t = this.cache.get (key); + + if (t != null) + { + + return t; + + } + + t = new UserConfigurableObjectType (); + t.setKey (key); + t.setUserObjectType (rs.getString (ind++)); + + String n = rs.getString (ind++); + t.setName (n); + t.setObjectTypeName (n); + t.setObjectTypeNamePlural (rs.getString (ind++)); + t.setDescription (new StringWithMarkup (rs.getString (ind++), + rs.getString (ind++))); + + t.setIcon24x24 (UIUtils.getImage (rs.getBytes (ind++))); + t.setIcon16x16 (UIUtils.getImage (rs.getBytes (ind++))); + t.setLayout (rs.getString (ind++)); + t.setAssetObjectType (rs.getBoolean (ind++)); + // TODO Need to remove this. + rs.getString (ind++); + // TODO t.setCreateShortcutKeyStroke (KeyStroke.getKeyStroke (rs.getString (ind++))); + t.setLastModified (rs.getTimestamp (ind++)); + t.setDateCreated (rs.getTimestamp (ind++)); + t.setPropertiesAsString (rs.getString (ind++)); + t.setId (rs.getString (ind++)); + t.setVersion (rs.getString (ind++)); + + Connection conn = rs.getStatement ().getConnection (); + + t.setConfigurableFields ((List) this.objectManager.getObjects (UserConfigurableObjectTypeField.class, + t, + conn, + true)); + + Environment.addUserConfigurableObjectType (t); + + this.cache.put (key, + t); + + return t; + + } catch (Exception e) + { + + throw new GeneralException ("Unable to load user configurable object type", + e); + + } + + } + + public List getObjects (NamedObject parent, + Connection conn, + boolean loadChildObjects) + throws GeneralException + { + + List ret = new ArrayList<> (); + + try + { + + List params = new ArrayList<> (); + + ResultSet rs = this.objectManager.executeQuery (STD_SELECT_PREFIX + " WHERE latest = TRUE", + params, + conn); + + while (rs.next ()) + { + + ret.add (this.getUserConfigurableObjectType (rs, + parent, + loadChildObjects)); + + } + + try + { + + rs.close (); + + } catch (Exception e) + { + } + + } catch (Exception e) + { + + throw new GeneralException ("Unable to load user configurable object types for: " + + parent, + e); + + } + + return ret; + + } + + public UserConfigurableObjectType getObjectByKey (long key, + NamedObject parent, + Connection conn, + boolean loadChildObjects) + throws GeneralException + { + + UserConfigurableObjectType t = null; + + try + { + + ResultSet rs = this.objectManager.executeQuery (STD_SELECT_PREFIX + " WHERE latest = TRUE AND dbkey = ?", + Arrays.asList (key), + conn); + + if (rs.next ()) + { + + t = this.getUserConfigurableObjectType (rs, + parent, + loadChildObjects); + + } + + try + { + + rs.close (); + + } catch (Exception e) + { + } + + } catch (Exception e) + { + + throw new GeneralException ("Unable to load user configurable object type for key: " + + key, + e); + + } + + return t; + + } + + public void createObject (UserConfigurableObjectType t, + Connection conn) + throws GeneralException + { + + this.objectManager.executeStatement ("INSERT INTO userobjecttype (dbkey, userobjtype, pluralname, icon24x24, icon16x16, layout, assetobjtype, createshortcutkey) VALUES (?, ?, ?, ?, ?, ?, ?, ?)", + Arrays.asList (t.getKey (), + t.getUserObjectType (), + t.getActualObjectTypeNamePlural (), + UIUtils.getImageBytes (t.getIcon24x24 ()), + UIUtils.getImageBytes (t.getIcon16x16 ()), + t.getLayout (), + t.isAssetObjectType (), + Utils.keyStrokeToString (t.getCreateShortcutKeyStroke ())), + conn); + + // Save the fields. + this.objectManager.saveObjects (t.getConfigurableFields (), + conn); + + } + + public void deleteObject (UserConfigurableObjectType t, + boolean deleteChildObjects, + Connection conn) + throws GeneralException + { + + // Delete the fields first. + this.objectManager.deleteObjects (t.getConfigurableFields (), + conn); + + this.objectManager.executeStatement ("DELETE FROM userobjecttype WHERE dbkey = ?", + Arrays.asList (t.getKey ()), + conn); + + } + + public void updateObject (UserConfigurableObjectType t, + Connection conn) + throws GeneralException + { + + this.objectManager.executeStatement ("UPDATE userobjecttype SET pluralname = ?, icon24x24 = ?, icon16x16 = ?, layout = ?, createshortcutkey = ? WHERE dbkey = ?", + Arrays.asList (t.getActualObjectTypeNamePlural (), + UIUtils.getImageBytes (t.getIcon24x24 ()), + UIUtils.getImageBytes (t.getIcon16x16 ()), + t.getLayout (), + Utils.keyStrokeToString (t.getCreateShortcutKeyStroke ()), + t.getKey ()), + conn); + + // Save the fields. + this.objectManager.saveObjects (t.getConfigurableFields (), + conn); + + } +/* +TODO Remove + public void updateFieldOrdering (UserConfigurableObjectType t) + throws GeneralException + { + + Connection conn = null; + + try + { + + conn = this.objectManager.getConnection (); + + this.objectManager.executeStatement ("UPDATE userobjecttypefield SET orderby = NULL WHERE userobjecttypedbkey = ?", + Arrays.asList (t.getKey ()), + conn); + + for (UserConfigurableObjectTypeField f : t.getConfigurableFields ()) + { + + this.objectManager.executeStatement ("UPDATE userobjecttypefield SET orderby = ? WHERE dbkey = ? AND userobjecttypedbkey = ?", + Arrays.asList (f.getOrder (), + f.getKey (), + t.getKey ()), + conn); + + } + + } catch (Exception e) { + + this.objectManager.throwException (conn, + "Unable to update field orderbys for type: " + + t.getKey (), + e); + + } finally { + + this.objectManager.releaseConnection (conn); + + + } + + } +*/ +} diff --git a/src/com/quollwriter/db/UserConfigurableObjectTypeFieldDataHandler.java b/src/main/java/com/quollwriter/db/UserConfigurableObjectTypeFieldDataHandler.java similarity index 86% rename from src/com/quollwriter/db/UserConfigurableObjectTypeFieldDataHandler.java rename to src/main/java/com/quollwriter/db/UserConfigurableObjectTypeFieldDataHandler.java index 6d49079d..2c24bc8d 100644 --- a/src/com/quollwriter/db/UserConfigurableObjectTypeFieldDataHandler.java +++ b/src/main/java/com/quollwriter/db/UserConfigurableObjectTypeFieldDataHandler.java @@ -11,14 +11,14 @@ public class UserConfigurableObjectTypeFieldDataHandler implements DataHandler { - private static final String STD_SELECT_PREFIX = "SELECT dbkey, type, orderby, name, definition, description, markup, lastmodified, datecreated, properties, id, version, userobjecttypedbkey FROM userobjecttypefield_v "; + private static final String STD_SELECT_PREFIX = "SELECT dbkey, type, name, definition, description, markup, lastmodified, datecreated, properties, id, version, userobjecttypedbkey FROM userobjecttypefield_v "; /** * A cache, since the same field can be used in multiple places * we need a single object so that we have one object -> multiple uses. */ private Map cache = new HashMap (); - + private ObjectManager objectManager = null; public UserConfigurableObjectTypeFieldDataHandler (ObjectManager om) @@ -40,33 +40,41 @@ private UserConfigurableObjectTypeField getUserConfigurableObjectTypeField (Resu int ind = 1; long key = rs.getLong (ind++); - + UserConfigurableObjectTypeField f = this.cache.get (key); - + if (f != null) { - + return f; - - } - + + } + String t = rs.getString (ind++); - - f = UserConfigurableObjectTypeField.Type.getNewFieldForType (UserConfigurableObjectTypeField.Type.valueOf (t)); + + try + { + + f = UserConfigurableObjectTypeField.Type.getNewFieldForType (UserConfigurableObjectTypeField.Type.valueOf (t)); + + } catch (Exception e) { + + return null; + + } if (f == null) { - + throw new GeneralException ("Type: " + t + " is not supported."); - + } - + f.setKey (key); - f.setOrder (rs.getInt (ind++)); f.setFormName (rs.getString (ind++)); - + String d = rs.getString (ind++); - + f.setDefinition ((Map) JSONDecoder.decode (d));//rs.getString (ind++))); f.setDescription (new StringWithMarkup (rs.getString (ind++), rs.getString (ind++))); @@ -77,33 +85,35 @@ private UserConfigurableObjectTypeField getUserConfigurableObjectTypeField (Resu f.setVersion (rs.getString (ind++)); long typekey = rs.getLong (ind++); - + if (type == null) { - + type = (UserConfigurableObjectType) this.objectManager.getObjectByKey (UserConfigurableObjectType.class, typekey, null, rs.getStatement ().getConnection (), true); - + if (type == null) { - + throw new GeneralException ("Unable to get config object type for: " + typekey + " and type field: " + key); - - } - + + } + } - - type.addConfigurableField (f); - + + f.setUserConfigurableObjectType (type); + + //TODO Remove type.addConfigurableField (f); + this.cache.put (key, f); - + return f; } catch (Exception e) @@ -122,7 +132,7 @@ public List getObjects (UserConfigurableObjectT throws GeneralException { - List ret = new ArrayList (); + List ret = new ArrayList<> (); try { @@ -130,16 +140,25 @@ public List getObjects (UserConfigurableObjectT List params = new ArrayList (); params.add (type.getKey ()); - ResultSet rs = this.objectManager.executeQuery (STD_SELECT_PREFIX + " WHERE latest = TRUE AND userobjecttypedbkey = ? ORDER BY orderby", + ResultSet rs = this.objectManager.executeQuery (STD_SELECT_PREFIX + " WHERE latest = TRUE AND userobjecttypedbkey = ?", params, conn); while (rs.next ()) { - ret.add (this.getUserConfigurableObjectTypeField (rs, - type, - loadChildObjects)); + UserConfigurableObjectTypeField t = this.getUserConfigurableObjectTypeField (rs, + type, + loadChildObjects); + + if (t == null) + { + + continue; + + } + + ret.add (t); } @@ -222,19 +241,18 @@ public void createObject (UserConfigurableObjectTypeField t, List params = new ArrayList (); params.add (t.getKey ()); - params.add (t.getOrder ()); params.add (t.getUserConfigurableObjectType ().getKey ()); params.add (t.getType ().getType ()); - params.add (JSONEncoder.encode (t.getDefinition ())); + params.add (JSONEncoder.encode (t.getDefinition ())); - this.objectManager.executeStatement ("INSERT INTO userobjecttypefield (dbkey, orderby, userobjecttypedbkey, type, definition) VALUES (?, ?, ?, ?, ?)", + this.objectManager.executeStatement ("INSERT INTO userobjecttypefield (dbkey, userobjecttypedbkey, type, definition) VALUES (?, ?, ?, ?)", params, conn); } public void deleteObject (UserConfigurableObjectTypeField t, - boolean deleteChildObjects, + boolean deleteChildObjects, Connection conn) throws GeneralException { @@ -254,12 +272,11 @@ public void updateObject (UserConfigurableObjectTypeField t, { List params = new ArrayList (); - - params.add (t.getOrder ()); + params.add (JSONEncoder.encode (t.getDefinition ())); params.add (t.getKey ()); - this.objectManager.executeStatement ("UPDATE userobjecttypefield SET orderby = ?, definition = ? WHERE dbkey = ?", + this.objectManager.executeStatement ("UPDATE userobjecttypefield SET definition = ? WHERE dbkey = ?", params, conn); diff --git a/src/com/quollwriter/db/WarmupDataHandler.java b/src/main/java/com/quollwriter/db/WarmupDataHandler.java similarity index 100% rename from src/com/quollwriter/db/WarmupDataHandler.java rename to src/main/java/com/quollwriter/db/WarmupDataHandler.java diff --git a/src/main/java/com/quollwriter/editors/DefaultEditorMessageProcessor.java b/src/main/java/com/quollwriter/editors/DefaultEditorMessageProcessor.java new file mode 100644 index 00000000..494fe827 --- /dev/null +++ b/src/main/java/com/quollwriter/editors/DefaultEditorMessageProcessor.java @@ -0,0 +1,547 @@ +package com.quollwriter.editors; + +import java.awt.event.*; +import java.awt.image.*; + +import java.util.*; + +//import javafx.embed.swing.*; + +import org.bouncycastle.openpgp.*; + +import com.quollwriter.data.editors.*; +import com.quollwriter.data.*; +import com.quollwriter.editors.ui.*; +import com.quollwriter.ui.fx.*; +import com.quollwriter.editors.messages.*; +import com.quollwriter.*; + +import static com.quollwriter.LanguageStrings.*; +import static com.quollwriter.Environment.getUIString; + +public class DefaultEditorMessageProcessor implements EditorMessageProcessor +{ + + public boolean processMessage (final EditorMessage mess) + throws Exception + { + + boolean showPopup = EditorsEnvironment.isShowPopupWhenNewMessageReceived (); + + EditorEditor ed = mess.getEditor (); + + if (mess instanceof EditorInfoMessage) + { + + return this.handleEditorInfoMessage ((EditorInfoMessage) mess, + ed, + showPopup); + + } + + if (mess instanceof EditorChatMessage) + { + + return this.handleChatMessage ((EditorChatMessage) mess, + ed, + showPopup); + + } + + if (mess instanceof InviteMessage) + { + + return this.handleInviteMessage ((InviteMessage) mess, + ed, + showPopup); + + } + + if (mess instanceof InviteResponseMessage) + { + + return this.handleInviteResponseMessage ((InviteResponseMessage) mess, + ed, + showPopup); + + } + + if (mess instanceof NewProjectMessage) + { + + return this.handleNewProjectMessage ((NewProjectMessage) mess, + ed, + showPopup); + + } + + if (mess instanceof NewProjectResponseMessage) + { + + return this.handleNewProjectResponseMessage ((NewProjectResponseMessage) mess, + ed, + showPopup); + + } + + if (mess instanceof UpdateProjectMessage) + { + + return this.handleUpdateProjectMessage ((UpdateProjectMessage) mess, + ed, + showPopup); + + } + + if (mess instanceof ProjectCommentsMessage) + { + + return this.handleProjectCommentsMessage ((ProjectCommentsMessage) mess, + ed, + showPopup); + + } + + if (mess instanceof EditorRemovedMessage) + { + + return this.handleEditorRemovedMessage ((EditorRemovedMessage) mess, + ed, + showPopup); + + } + + if (mess instanceof ProjectEditStopMessage) + { + + return this.handleProjectEditStopMessage ((ProjectEditStopMessage) mess, + ed, + showPopup); + + } + + if (mess instanceof InteractionMessage) + { + + return this.handleInteractionMessage ((InteractionMessage) mess, + ed, + showPopup); + + } + + if (mess instanceof ErrorMessage) + { + + return this.handleErrorMessage ((ErrorMessage) mess, + ed, + showPopup); + + } + + return false; + + } + + private boolean handleInteractionMessage (InteractionMessage im, + EditorEditor ed, + boolean showPopup) + throws Exception + { + + EditorsEnvironment.fireEditorInteractionEvent (im.getEditor (), + im.getAction ()); + + // Fire a status update. + return false; + + } + + private boolean handleEditorRemovedMessage (EditorRemovedMessage mess, + EditorEditor ed, + boolean showPopup) + throws Exception + { + + // Unsubscribe. + EditorsEnvironment.getMessageHandler ().unsubscribeFromEditor (ed); +/* + if (showPopup) + { + + AbstractViewer viewer = Environment.getFocusedViewer (); + + mess.setDealtWith (true); + + UIUtils.showMessage ((PopupsSupported) viewer, + "You have been removed as {an editor}", + String.format ("%s has removed you as {an editor}.

    Note you will no longer be able to send them messages and/or {projects}.", + mess.getEditor ().getShortName ())); + + } +*/ + return true; + + } + + private boolean handleProjectEditStopMessage (ProjectEditStopMessage mess, + EditorEditor ed, + boolean showPopup) + throws Exception + { + + if (ed.isPending ()) + { + + // TODO: Make this nicer, maybe set new project response message to dealt with? + + // This is the rare case where someone has been invited, they accepted the project then deleted it + // before the user could find out. + + // Get the NewProjectResponseMessage and set it as dealt with so the user doesn't have to bother with it. + + } + +/* + Project p = Environment.getProjectById (mess.getForProjectId (), + Project.NORMAL_PROJECT_TYPE); + + ProjectEditor pe = EditorsEnvironment.getProjectEditor (p, + mess.getEditor ()); + + pe.setCurrent (false); + pe.setEditorTo (new Date ()); + pe.setStatusMessage (String.format ("Stopped editing: %s", + Environment.formatDate (pe.getEditorTo ()))); + + EditorsEnvironment.updateProjectEditor (pe); +*/ +/* + if (showPopup) + { + + AbstractViewer viewer = Environment.getFocusedViewer (); + + UIUtils.showMessage ((PopupsSupported) viewer, + "An {editor} has stopped editing your {project}", + String.format ("%s has decided to stop editing %s.", + mess.getEditor ().getShortName (), + mess.getForProjectName ())); + + mess.setDealtWith (true); + + } +*/ + return true; + + } + + private boolean handleProjectCommentsMessage (final ProjectCommentsMessage mess, + final EditorEditor ed, + final boolean showPopup) + throws Exception + { + + String projId = mess.getForProjectId (); + + ProjectInfo proj = null; + + try + { + + proj = Environment.getProjectById (projId, + Project.NORMAL_PROJECT_TYPE); + + } catch (Exception e) { + + throw new GeneralException ("Unable to get project for id: " + + projId, + e); + + } + + ProjectEditor pe = EditorsEnvironment.getProjectEditor (proj, + ed); + + if (pe == null) + { + + throw new IllegalArgumentException ("Editor is not a project editor for project: " + projId + ", editor: " + ed); + + } + + // It may be that we get some comments before the user acknowledged the editor's acceptance of the + // project. In which case we need to update the project editor to current. + if (pe.isInvited ()) + { + + pe.setEditorFrom (mess.getWhen ()); + pe.setCurrent (true); + + pe.setStatus (ProjectEditor.Status.accepted); + + } + + int c = mess.getComments ().size (); + + pe.setStatusMessage (Arrays.asList (editors,user,commentsreceived,editorstatus), + //"Received %s {comment%s}: %s", + Arrays.asList (Environment.formatNumber (c), + Environment.formatDate (mess.getWhen ()))); + + EditorsEnvironment.updateProjectEditor (pe); +/* + if (showPopup) + { + + AbstractViewer viewer = Environment.getFocusedViewer (); + + UIUtils.createQuestionPopup (viewer, + "{Comments} received about a {project}", + Constants.COMMENT_ICON_NAME, + String.format ("%s has sent %s {comments} about version %s of your {project} %s.

    Would you like to view the {comments} now?", + mess.getEditor ().getShortName (), + mess.getForProjectName ()), + "Yes, show me them", + "No, I'll do it later", + new ActionListener () + { + + public void actionPerformed (ActionEvent ev) + { + + AbstractViewer viewer = Environment.getFocusedViewer (); + + EditorsUIUtils.showProjectComments (mess, + viewer, + null); + + } + + }, + null, + null, + null); + + mess.setDealtWith (true); + + } +*/ + return true; + + } + + private boolean handleInviteMessage (final InviteMessage inv, + final EditorEditor ed, + final boolean showPopup) + throws Exception + { + + ed.setName (inv.getEditorName ()); + + if (inv.getEditorAvatar () != null) + { + + ed.setAvatar (inv.getEditorAvatar ()); + + } + + // TODO: Need a nicer way of doing this. + if (ed.getKey () != null) + { + + EditorsEnvironment.updateEditor (ed); + + } else { + + EditorsEnvironment.addNewEditor (ed); + + } + + return true; + + } + + private boolean handleInviteResponseMessage (InviteResponseMessage rm, + EditorEditor ed, + boolean showPopup) + throws Exception + { + + if (ed.getEditorStatus () != EditorEditor.EditorStatus.pending) + { + + // Actually an error, but probably ok to just ignore? + Environment.logError ("Invalid statue, received invite response message from editor: " + + ed); + + return false; + + } + + if (rm.isAccepted ()) + { + + EditorsEnvironment.getMessageHandler ().subscribeToEditor (ed); + + } + + return true; + + } + + private boolean handleErrorMessage (ErrorMessage error, + EditorEditor ed, + boolean showPopup) + throws Exception + { + + // Check the type and decide what to do... + if (error.getErrorType () == ErrorMessage.ErrorType.projectnotexists) + { + + // Eerk! + + } + + return false; + + } + + private boolean handleEditorInfoMessage (EditorInfoMessage info, + EditorEditor ed, + boolean showPopup) + throws Exception + { + + return true; + + } + + private boolean handleChatMessage (EditorChatMessage mess, + EditorEditor ed, + boolean showPopup) + throws Exception + { + + return true; + + } + + private boolean handleNewProjectResponseMessage (NewProjectResponseMessage res, + EditorEditor ed, + boolean showPopup) + throws Exception + { + + if (ed.isPending ()) + { + + if (res.isAccepted ()) + { + + EditorsEnvironment.getMessageHandler ().subscribeToEditor (ed); + + } + + } + + // Set the response in the new project message we have stored. + // Get the message. + NewProjectMessage npmess = EditorsEnvironment.getNewProjectMessage (ed, + res.getForProjectId (), + true); + + if (npmess == null) + { + + // Return an error saying that the project no longer exists. + EditorsEnvironment.sendError (res, + ErrorMessage.ErrorType.invalidstate, + "No new project message found for project: " + res.getForProjectId ()); + + return false; + + } + + boolean accepted = res.isAccepted (); + + npmess.setAccepted (accepted); + npmess.setResponseMessage (res.getResponseMessage ()); + + EditorsEnvironment.updateMessage (npmess); + return true; + + + } + + private boolean handleNewProjectMessage (NewProjectMessage proj, + EditorEditor ed, + boolean showPopup) + throws Exception + { + + // TODO: Need a nicer way of doing this. + if (ed.getKey () != null) + { + + EditorsEnvironment.updateEditor (ed); + + } else { + + // Only set the name/avatar for new editors. + ed.setName (proj.getEditorName ()); + ed.setAvatar (proj.getEditorAvatar ()); + + EditorsEnvironment.addNewEditor (ed); + + } + + NewProjectMessage npmess = EditorsEnvironment.getNewProjectMessage (ed, + proj.getForProjectId (), + false); + + ProjectInfo pr = Environment.getProjectById (proj.getForProjectId (), + Project.EDITOR_PROJECT_TYPE); + + ProjectEditor pe = EditorsEnvironment.getProjectEditor (pr, + ed); + + if ((npmess != null) + && + (pe != null) + && + (pe.isCurrent ()) + ) + { + + // Return an error saying that it can only be sent once. + EditorsEnvironment.sendError (proj, + ErrorMessage.ErrorType.invalidstate, + "Already received a new project message for: " + proj.getForProjectId ()); + + Environment.logError ("Received duplicate new project message from: " + + ed + + " for project: " + + proj.getForProjectId ()); + + return false; + + } + + return true; + + + } + + private boolean handleUpdateProjectMessage (UpdateProjectMessage mess, + EditorEditor ed, + boolean showPopup) + throws Exception + { + + // Save the message. + return true; + + } + +} diff --git a/src/main/java/com/quollwriter/editors/DefaultEditorsWebServiceErrorAction.java b/src/main/java/com/quollwriter/editors/DefaultEditorsWebServiceErrorAction.java new file mode 100644 index 00000000..06735185 --- /dev/null +++ b/src/main/java/com/quollwriter/editors/DefaultEditorsWebServiceErrorAction.java @@ -0,0 +1,177 @@ +package com.quollwriter.editors; + +import java.awt.event.*; + +import java.net.*; + +import com.quollwriter.*; +//import com.quollwriter.ui.*; +import com.quollwriter.editors.ui.*; +import com.quollwriter.data.editors.*; +import com.quollwriter.ui.fx.viewers.*; +import com.quollwriter.ui.fx.*; + +import static com.quollwriter.LanguageStrings.*; +import static com.quollwriter.Environment.getUIString; + +import static com.quollwriter.uistrings.UILanguageStringsManager.getUILanguageStringProperty; +import static com.quollwriter.LanguageStrings.*; + +public class DefaultEditorsWebServiceErrorAction implements EditorsWebServiceAction +{ + + private EditorsWebServiceHandler handler = null; + + public DefaultEditorsWebServiceErrorAction (EditorsWebServiceHandler handler) + { + + this.handler = handler; + + } + + protected void handleForbiddenResponse () + { + + EditorsEnvironment.clearUserPassword (); + + UIUtils.runLater (() -> + { + + EditorsUIUtils.showLoginError (getUILanguageStringProperty (editors,login,errors,maxloginattempts)); + //"You have reached the maximum number of login attempts possible. Please try logging in again in a few minutes."); + + }); + + } + + protected void handleUnauthorizedResponse (EditorsWebServiceResult res, + Runnable onLogin, + Runnable onCancel) + { + + AbstractViewer viewer = Environment.getFocusedViewer (); + + if (viewer == null) + { + + throw new IllegalStateException ("Unable to handle response, no viewer available."); + + } + + if (res.getErrorType ().equals ("InvalidCredentials")) + { + + EditorsEnvironment.clearUserPassword (); + + // Need to login again, probably the password has been changed. + EditorsUIUtils.showLoginError (getUILanguageStringProperty (editors,login,errors,invalidcredentials), + //"Your login details do not appear to be correct.", + onLogin, + onCancel); + + return; + + } + + if (res.getErrorType ().equals ("AccountNotActive")) + { + + // Need to activate the account first. + EditorsUIUtils.showLoginError (getUILanguageStringProperty (editors,login,errors,inactiveaccount)); + //"You must activate your account (check your email) first."); + + return; + + } + + // See if we have login credentials, if so try getting a new session. + if ((res.getErrorType ().equals ("SessionExpired")) + || + (res.getErrorType ().equals ("UnknownSessionId")) + ) + { + + EditorAccount acc = EditorsEnvironment.getUserAccount (); + + if (acc.getPassword () == null) + { + + // How did we wind up here? + EditorsUIUtils.showLoginError (getUILanguageStringProperty (editors,login,errors,invalidcredentials), + //"Your login details do not appear to be correct.", + onLogin, + onCancel); + + return; + + } + + acc.setWebServiceSessionId (null); + + this.handler.login (onLogin, + null); + + return; + + } + + EditorsEnvironment.clearUserPassword (); + + // Something unexpected happened, just show the login again. + EditorsUIUtils.showLoginError (getUILanguageStringProperty (editors,login,errors,invalidcredentials), + //"Your login details do not appear to be correct.", + onLogin, + onCancel); + + } + + public void processResult (final EditorsWebServiceResult res) + { + + if (!res.isError ()) + { + + + + } + + // Has the current session expired? + if (res.code == HttpURLConnection.HTTP_UNAUTHORIZED) + { + + this.handleUnauthorizedResponse (res, + () -> + { + + EditorAccount acc = EditorsEnvironment.getUserAccount (); + + // Recall. + res.getCall ().sessionId (acc.getWebServiceSessionId ()).call (); + + }, + null); + + return; + + } + + if (res.code == HttpURLConnection.HTTP_FORBIDDEN) + { + + this.handleForbiddenResponse (); + + return; + + } + + // Get the response code. + if (res.code != HttpURLConnection.HTTP_OK) + { + + EditorsUIUtils.showResultError (res); + + } + + } + +} diff --git a/src/com/quollwriter/editors/EditorChangedEvent.java b/src/main/java/com/quollwriter/editors/EditorChangedEvent.java similarity index 100% rename from src/com/quollwriter/editors/EditorChangedEvent.java rename to src/main/java/com/quollwriter/editors/EditorChangedEvent.java diff --git a/src/com/quollwriter/editors/EditorChangedListener.java b/src/main/java/com/quollwriter/editors/EditorChangedListener.java similarity index 100% rename from src/com/quollwriter/editors/EditorChangedListener.java rename to src/main/java/com/quollwriter/editors/EditorChangedListener.java diff --git a/src/com/quollwriter/editors/EditorEvent.java b/src/main/java/com/quollwriter/editors/EditorEvent.java similarity index 100% rename from src/com/quollwriter/editors/EditorEvent.java rename to src/main/java/com/quollwriter/editors/EditorEvent.java diff --git a/src/com/quollwriter/editors/EditorInteractionEvent.java b/src/main/java/com/quollwriter/editors/EditorInteractionEvent.java similarity index 100% rename from src/com/quollwriter/editors/EditorInteractionEvent.java rename to src/main/java/com/quollwriter/editors/EditorInteractionEvent.java diff --git a/src/com/quollwriter/editors/EditorInteractionListener.java b/src/main/java/com/quollwriter/editors/EditorInteractionListener.java similarity index 100% rename from src/com/quollwriter/editors/EditorInteractionListener.java rename to src/main/java/com/quollwriter/editors/EditorInteractionListener.java diff --git a/src/com/quollwriter/editors/EditorMessageEvent.java b/src/main/java/com/quollwriter/editors/EditorMessageEvent.java similarity index 100% rename from src/com/quollwriter/editors/EditorMessageEvent.java rename to src/main/java/com/quollwriter/editors/EditorMessageEvent.java diff --git a/src/com/quollwriter/editors/EditorMessageListener.java b/src/main/java/com/quollwriter/editors/EditorMessageListener.java similarity index 100% rename from src/com/quollwriter/editors/EditorMessageListener.java rename to src/main/java/com/quollwriter/editors/EditorMessageListener.java diff --git a/src/com/quollwriter/editors/EditorMessageProcessor.java b/src/main/java/com/quollwriter/editors/EditorMessageProcessor.java similarity index 100% rename from src/com/quollwriter/editors/EditorMessageProcessor.java rename to src/main/java/com/quollwriter/editors/EditorMessageProcessor.java diff --git a/src/main/java/com/quollwriter/editors/EditorsEnvironment.java b/src/main/java/com/quollwriter/editors/EditorsEnvironment.java new file mode 100644 index 00000000..2c97a214 --- /dev/null +++ b/src/main/java/com/quollwriter/editors/EditorsEnvironment.java @@ -0,0 +1,3676 @@ +package com.quollwriter.editors; + +import java.io.*; +import java.nio.file.*; +import java.nio.file.attribute.*; +import java.awt.image.*; +import java.net.*; +import java.util.*; +import java.util.function.*; +import java.util.logging.*; +import java.sql.*; + +import javafx.collections.*; +import javafx.scene.input.*; +import javafx.scene.*; +import javafx.beans.property.*; +import javafx.scene.image.*; + +import org.bouncycastle.openpgp.*; + +import com.quollwriter.*; +import com.quollwriter.data.*; +import com.quollwriter.events.*; +import com.quollwriter.db.*; +import com.quollwriter.data.editors.*; +import com.quollwriter.editors.messages.*; +import com.quollwriter.editors.ui.*; +import com.quollwriter.ui.fx.viewers.*; +import com.quollwriter.ui.fx.*; + +import com.quollwriter.ui.fx.components.ComponentUtils; +import com.quollwriter.ui.fx.components.Notification; +import com.quollwriter.ui.fx.components.QuollPopup; +import com.quollwriter.ui.fx.StyleClassNames; + +import static com.quollwriter.LanguageStrings.*; +import static com.quollwriter.uistrings.UILanguageStringsManager.getUIString; +import static com.quollwriter.uistrings.UILanguageStringsManager.getUILanguageStringProperty; + +public class EditorsEnvironment +{ + + private static EditorsObjectManager editorsManager = null; + private static EditorsWebServiceHandler editorsHandler = null; + private static EditorsMessageHandler messageHandler = null; + private static EditorAccount editorAccount = null; + //private static boolean hasRegisteredForEditorService = false; + public static boolean serviceAvailable = true; + private static ObservableSet editors = FXCollections.observableSet (new HashSet<> ()); + private static ObservableList invitesForMe = FXCollections.observableList (new ArrayList<> ()); + private static ObservableList invitesIveSent = FXCollections.observableList (new ArrayList<> ()); + private static ObservableList currentEditors = FXCollections.observableList (new ArrayList<> ()); + private static ObservableList previousEditors = FXCollections.observableList (new ArrayList<> ()); + + // TODO: This is *NOT* the way to handle this but is ok for now and saves faffing with dirs and files. + protected static int schemaVersion = 0; + private static com.gentlyweb.properties.Properties editorsProps = new com.gentlyweb.properties.Properties (); + //private static EditorEditor.OnlineStatus currentOnlineStatus = EditorEditor.OnlineStatus.offline; + private static ObjectProperty userOnlineStatusProp = new SimpleObjectProperty (EditorEditor.OnlineStatus.offline); + private static EditorEditor.OnlineStatus lastOnlineStatus = null; + + private static Map editorChangedListeners = null; + private static Map projectEditorChangedListeners = null; + private static Map editorMessageListeners = null; + private static Map userStatusListeners = null; + private static Map editorInteractionListeners = null; + + private static boolean startupLoginTried = false; + + // Just used in the maps above as a placeholder for the listeners. + private static final Object listenerFillObj = new Object (); + + // We create the listener containers here to allow others to listen for events even though the service + // may not be running or ever available. This is sort of wasteful but prevents clients having to bother + // about checking for the service being available, they just won't receive events. + static + { + + // We use a synchronized weak hash map here so that we don't have to worry about all the + // references since they will be transient compared to the potential length of the service + // running. + + // Where possible listeners should de-register as normal but this just ensure that objects + // that don't have a controlled pre-defined lifecycle (as opposed say to AbstractSideBar) + // won't leak. + EditorsEnvironment.editorChangedListeners = Collections.synchronizedMap (new WeakHashMap ()); + + EditorsEnvironment.projectEditorChangedListeners = Collections.synchronizedMap (new WeakHashMap ()); + + EditorsEnvironment.editorMessageListeners = Collections.synchronizedMap (new WeakHashMap ()); + + EditorsEnvironment.userStatusListeners = Collections.synchronizedMap (new WeakHashMap ()); + + EditorsEnvironment.editorInteractionListeners = Collections.synchronizedMap (new WeakHashMap<> ()); + + } + + public static void logEditorMessages (boolean v) + { + + EditorsEnvironment.messageHandler.logMessages (v); + + } + + public static void init (com.gentlyweb.properties.Properties props) + throws Exception + { + + if (!EditorsEnvironment.serviceAvailable) + { + + return; + + } + + if (props == null) + { + + throw new GeneralException ("Properties must be provided."); + + } + + EditorsEnvironment.editorsProps = props; + + try + { + + EditorsEnvironment.schemaVersion = Integer.parseInt (Utils.getResourceFileAsString (Constants.EDITORS_SCHEMA_VERSION_FILE).trim ()); + + } catch (Exception e) + { + + Environment.logError ("Unable to read editors schema version file", + e); + + EditorsEnvironment.serviceAvailable = false; + + return; + + } + + EditorsEnvironment.editorsHandler = new EditorsWebServiceHandler (); + EditorsEnvironment.editorsHandler.init (); + + EditorsEnvironment.messageHandler = new EditorsMessageHandler (); + + //EditorsEnvironment.logEditorMessages (true); + + + EditorsEnvironment.messageHandler.init (); + + String eddir = EditorsEnvironment.editorsProps.getProperty (Constants.QW_EDITORS_DB_DIR_PROPERTY_NAME); + + if (eddir != null) + { + + File dir = new File (eddir); + + if ((dir.exists ()) + && + (dir.isDirectory ()) + ) + { + + EditorsEnvironment.initDB (dir); + + } + + } + + // Bit of spelunking anyone??? + Environment.startupCompleteProperty ().addListener ((p, oldv, newv) -> + { + + if ((newv) + && + (!EditorsEnvironment.startupLoginTried) + ) + { + + if (EditorsEnvironment.getEditorsPropertyAsBoolean (Constants.QW_EDITORS_SERVICE_LOGIN_AT_QW_START_PROPERTY_NAME)) + { + + Environment.scheduleImmediately (() -> + { + + String pwd = EditorsEnvironment.getEditorsProperty (Constants.QW_EDITORS_SERVICE_PASSWORD_PROPERTY_NAME); + + String email = null; + + if (EditorsEnvironment.editorAccount != null) + { + + email = EditorsEnvironment.editorAccount.getEmail (); + + } + + if (email == null) + { + + // Can't login, no account, this can happen if the user used to have an account and has + // deleted it with the setting enabled. + return; + + } + + UIUtils.runLater (() -> + { + + // Add a notification to the project viewer saying we are logging in. + final AbstractViewer viewer = Environment.getFocusedViewer (); + + Notification _n = null; + + // We may not have a viewer if we are opening an encrypted project. + if (viewer != null) + { + + _n = viewer.addNotification (getUILanguageStringProperty (LanguageStrings.editors,login,auto,notification), + //"Logging in to the Editors service...", + Constants.EDITORS_ICON_NAME, + 30); + _n.setId ("editorsloginnotification"); + + } + + }); + + EditorsEnvironment.setLoginCredentials (email, + pwd); + + EditorsEnvironment.startupLoginTried = true; + + EditorsEnvironment.goOnline (null, + () -> + { + + UIUtils.runLater (() -> + { + + final AbstractViewer viewer = Environment.getFocusedViewer (); + + if (viewer != null) + { + + Node nn = viewer.lookup ("#editorsloginnotification"); + + if (nn != null) + { + + viewer.removeNotification ((Notification) nn); + + } + + } + + }); + + }, + // On cancel + () -> + { + + UIUtils.runLater (() -> + { + + final AbstractViewer viewer = Environment.getFocusedViewer (); + + if (viewer != null) + { + + Node nn = viewer.lookup ("#editorsloginnotification"); + + if (nn != null) + { + + viewer.removeNotification ((Notification) nn); + + } + + } + + }); + + }, + // On error + exp -> + { + + EditorsEnvironment.setLoginCredentials (EditorsEnvironment.editorAccount.getEmail (), + null); + + UIUtils.runLater (() -> + { + + final AbstractViewer viewer = Environment.getFocusedViewer (); + + if (viewer != null) + { + + Node nn = viewer.lookup ("#editorsloginnotification"); + + if (nn != null) + { + + viewer.removeNotification ((Notification) nn); + + } + + } + + }); + + EditorsUIUtils.showLoginError (getUILanguageStringProperty (LanguageStrings.editors,login,auto,actionerror), + //"Unable to automatically login, please check your email and password.", + () -> + { + + EditorsEnvironment.goOnline (null, + null, + null, + null); + + }, + null); + + }); + + }); + + } + + } + + }); + + } + + public static void removeEditorInteractionListener (EditorInteractionListener l) + { + + EditorsEnvironment.editorInteractionListeners.remove (l); + + } + + public static void addEditorInteractionListener (EditorInteractionListener l) + { + + EditorsEnvironment.editorInteractionListeners.put (l, + EditorsEnvironment.listenerFillObj); + + } + + public static void fireEditorInteractionEvent (final EditorEditor ed, + final InteractionMessage.Action action) + { + + // TODO Get rid? + UIUtils.runLater (() -> + { + + Set ls = null; + + EditorInteractionEvent ev = new EditorInteractionEvent (ed, + action); + + // Get a copy of the current valid listeners. + synchronized (EditorsEnvironment.editorInteractionListeners) + { + + ls = new LinkedHashSet<> (EditorsEnvironment.editorInteractionListeners.keySet ()); + + } + + for (EditorInteractionListener l : ls) + { + + l.handleInteraction (ev); + + } + + }); + + } + + public static void removeUserOnlineStatusListener (UserOnlineStatusListener l) + { + + EditorsEnvironment.userStatusListeners.remove (l); + + } + + public static void addUserOnlineStatusListener (UserOnlineStatusListener l) + { + + EditorsEnvironment.userStatusListeners.put (l, + EditorsEnvironment.listenerFillObj); + + } + + private static void fireUserOnlineStatusChanged (final EditorEditor.OnlineStatus status) + { + + // TODO Get rid? + UIUtils.runLater (() -> + { + + Set ls = null; + + UserOnlineStatusEvent ev = new UserOnlineStatusEvent (status); + + // Get a copy of the current valid listeners. + synchronized (EditorsEnvironment.userStatusListeners) + { + + ls = new LinkedHashSet (EditorsEnvironment.userStatusListeners.keySet ()); + + } + + for (UserOnlineStatusListener l : ls) + { + + l.userOnlineStatusChanged (ev); + + } + + }); + + } + + public static void setDefaultUserOnlineStatus () + { + + EditorEditor.OnlineStatus status = null; + + String defOnlineStatus = EditorsEnvironment.getEditorsProperty (Constants.QW_EDITORS_SERVICE_DEFAULT_ONLINE_STATUS_PROPERTY_NAME); + + if (defOnlineStatus != null) + { + + try + { + + status = EditorEditor.OnlineStatus.valueOf (defOnlineStatus); + + } catch (Exception e) { + + Environment.logError ("Unable to set default online status to: " + + defOnlineStatus, + e); + + } + + } + + if (status == null) + { + + status = EditorEditor.OnlineStatus.online; + + } + + try + { + + EditorsEnvironment.setUserOnlineStatus (status); + + } catch (Exception e) { + + Environment.logError ("Unable to set default online status to: " + + status, + e); + + } + + } + + public static void setUserOnlineStatus (EditorEditor.OnlineStatus status) + throws Exception + { + + if (!EditorsEnvironment.messageHandler.isLoggedIn ()) + { + + throw new IllegalStateException ("Cant set user online status if they are not logged in."); + + } + + if (EditorsEnvironment.userOnlineStatusProp.getValue () == status) + { + + return; + + } + + EditorsEnvironment.userOnlineStatusProp.setValue (status); + + // Send the presence. + EditorsEnvironment.messageHandler.setOnlineStatus (status); + + EditorsEnvironment.fireUserOnlineStatusChanged (EditorsEnvironment.userOnlineStatusProp.getValue ()); + + } + + public static EditorEditor.OnlineStatus getUserOnlineStatus () + { + + return EditorsEnvironment.userOnlineStatusProp.getValue (); + + } + + public static ObjectProperty userOnlineStatusProperty () + { + + return EditorsEnvironment.userOnlineStatusProp; + + } + + public static boolean isUserLoggedIn () + { + + return EditorsEnvironment.messageHandler.isLoggedIn (); + + } + + public static boolean isEditorsDBDir (Path dir) + { + + return EditorsEnvironment.isEditorsDBDir (dir.toFile ()); + + } + + public static boolean isEditorsDBDir (File dir) + { + + if (dir == null) + { + + return false; + + } + + if (dir.isFile ()) + { + + return false; + + } + + if (!dir.exists ()) + { + + return false; + + } + + File f = new File (dir, Constants.EDITORS_DB_FILE_NAME_PREFIX + Constants.H2_DB_FILE_SUFFIX); + + if ((f.exists ()) + && + (f.isFile ()) + ) + { + + return true; + + } + + return false; + + } + + public static void initDB (Path dir) + throws Exception + { + + EditorsEnvironment.initDB (dir.toFile ()); + + } + + public static void initDB (File dir) + throws Exception + { + + if (EditorsEnvironment.editorsProps == null) + { + + throw new IllegalStateException ("Editors properties has not yet been set, try init(Properties) first."); + + } + + // Get the username and password. + String username = EditorsEnvironment.editorsProps.getProperty (Constants.DB_USERNAME_PROPERTY_NAME); + String password = EditorsEnvironment.editorsProps.getProperty (Constants.DB_PASSWORD_PROPERTY_NAME); + + EditorsEnvironment.editorsManager = new EditorsObjectManager (); + + File f = EditorsEnvironment.getEditorsDBFile (dir); + + EditorsEnvironment.editorsManager.init (f, + username, + password, + null, + EditorsEnvironment.getSchemaVersion (dir)); + + // Create a file that indicates that the directory can be deleted. + Utils.createQuollWriterDirFile (dir); + + EditorsEnvironment.editorAccount = EditorsEnvironment.editorsManager.getUserAccount (); + + if (EditorsEnvironment.editorAccount != null) + { + + // Load up the editors. + Set eds = new LinkedHashSet<> ((List) EditorsEnvironment.editorsManager.getObjects (EditorEditor.class, + null, + null, + true)); + EditorsEnvironment.editors = FXCollections.observableSet (eds); + + for (EditorEditor ed : EditorsEnvironment.editors) + { + + if (ed.isPrevious ()) + { + + EditorsEnvironment.previousEditors.add (ed); + continue; + + } + + if (ed.isRejected ()) + { + + continue; + + } + + ed.getBinder ().addChangeListener (ed.editorStatusProperty (), + (pr, oldv, newv) -> + { + + if ((newv == EditorEditor.EditorStatus.current) + && + (oldv != EditorEditor.EditorStatus.current) + ) + { + + EditorsEnvironment.invitesForMe.remove (ed); + EditorsEnvironment.invitesIveSent.remove (ed); + EditorsEnvironment.currentEditors.add (ed); + EditorsEnvironment.previousEditors.remove (ed); + + } + + if (newv == EditorEditor.EditorStatus.previous) + { + + EditorsEnvironment.invitesForMe.remove (ed); + EditorsEnvironment.invitesIveSent.remove (ed); + EditorsEnvironment.currentEditors.remove (ed); + EditorsEnvironment.previousEditors.add (ed); + + } + + }); + + if (ed.isPending ()) + { + + if (!ed.isInvitedByMe ()) + { + + EditorsEnvironment.invitesForMe.add (ed); + + } else { + + EditorsEnvironment.invitesIveSent.add (ed); + + } + + } else { + + EditorsEnvironment.currentEditors.add (ed); + + } + + } + + } + + } + + public static boolean hasUserSentAProjectBefore () + throws Exception + { + + if (EditorsEnvironment.editorsManager == null) + { + + return false; + + } + + return EditorsEnvironment.editorsManager.hasUserSentAProjectBefore (); + + } + + public static void fireEditorMessageEvent (final EditorMessageEvent ev) + { + + // TODO Get rid? + UIUtils.runLater (() -> + { + + Set ls = null; + + // Get a copy of the current valid listeners. + synchronized (EditorsEnvironment.editorMessageListeners) + { + + ls = new LinkedHashSet (EditorsEnvironment.editorMessageListeners.keySet ()); + + } + + for (EditorMessageListener l : ls) + { + + l.handleMessage (ev); + + } + + }); + + } + + public static NewProjectMessage getNewProjectMessage (EditorEditor ed, + String projectId, + boolean sentByMe) + throws Exception + { + + return EditorsEnvironment.editorsManager.getNewProjectMessage (ed, + projectId, + sentByMe); + + } + + public static boolean hasMyPublicKeyBeenSentToEditor (EditorEditor ed) + throws Exception + { + + return EditorsEnvironment.editorsManager.hasMyPublicKeyBeenSentToEditor (ed); + + } + + public static boolean hasSentMessageOfTypeToEditor (EditorEditor ed, + String messageType) + throws Exception + { + + return EditorsEnvironment.editorsManager.hasSentMessageOfTypeToEditor (ed, + messageType); + + } + + public static boolean hasEditorSentInfo (EditorEditor ed) + throws Exception + { + + if (ed.messagesLoaded ()) + { + + return ed.hasSentInfo (); + + } + + return EditorsEnvironment.editorsManager.hasEditorSentInfo (ed); + + } + + public static void removeEditorMessageListener (EditorMessageListener l) + { + + EditorsEnvironment.editorMessageListeners.remove (l); + + } + + public static void addEditorMessageListener (EditorMessageListener l) + { + + EditorsEnvironment.editorMessageListeners.put (l, + EditorsEnvironment.listenerFillObj); + + } + + public static void fireEditorChangedEvent (EditorEditor ed, + int changeType) + { + + EditorsEnvironment.fireEditorChangedEvent (new EditorChangedEvent (ed, + changeType)); + + } + + public static void fireEditorChangedEvent (final EditorChangedEvent ev) + { + + // TODO Get rid? + UIUtils.runLater (() -> + { + + Set ls = null; + + // Get a copy of the current valid listeners. + synchronized (EditorsEnvironment.editorChangedListeners) + { + + ls = new LinkedHashSet (EditorsEnvironment.editorChangedListeners.keySet ()); + + } + + for (EditorChangedListener l : ls) + { + + l.editorChanged (ev); + + } + + }); + + } + + public static void removeEditorChangedListener (EditorChangedListener l) + { + + EditorsEnvironment.editorChangedListeners.remove (l); + + } + + public static void addEditorChangedListener (EditorChangedListener l) + { + + EditorsEnvironment.editorChangedListeners.put (l, + EditorsEnvironment.listenerFillObj); + + } + + public static void fireProjectEditorChangedEvent (ProjectEditor pe, + int changeType) + { + + EditorsEnvironment.fireProjectEditorChangedEvent (new ProjectEditorChangedEvent (pe, + changeType)); + + } + + public static void fireProjectEditorChangedEvent (final ProjectEditorChangedEvent ev) + { + + // TODO Get rid? + UIUtils.runLater (() -> + { + + Set ls = null; + + // Get a copy of the current valid listeners. + synchronized (EditorsEnvironment.projectEditorChangedListeners) + { + + ls = new LinkedHashSet (EditorsEnvironment.projectEditorChangedListeners.keySet ()); + + } + + for (ProjectEditorChangedListener l : ls) + { + + l.projectEditorChanged (ev); + + } + + }); + + } + + public static void removeProjectEditorChangedListener (ProjectEditorChangedListener l) + { + + EditorsEnvironment.projectEditorChangedListeners.remove (l); + + } + + public static void addProjectEditorChangedListener (ProjectEditorChangedListener l) + { + + EditorsEnvironment.projectEditorChangedListeners.put (l, + EditorsEnvironment.listenerFillObj); + + } + + public static boolean isEditorsServiceAvailable () + { + + return EditorsEnvironment.serviceAvailable; + + } + + public static void setUserInformation (String name, + Image avatarImage) + throws GeneralException + { + + if (EditorsEnvironment.editorsManager == null) + { + + throw new IllegalStateException ("Editor object manager not inited."); + + } +/* +TODO Remove + if (avatarImage != null) + { + + if (avatarImage.getWidth () > 300) + { + + avatarImage = UIUtils.getScaledImage (avatarImage, + 300); + + } + + } +*/ + EditorsEnvironment.editorAccount.setName (name); + EditorsEnvironment.editorAccount.setAvatar (avatarImage); + + EditorsEnvironment.editorsManager.setUserInformation (EditorsEnvironment.editorAccount); + + } + + private static File getEditorsDBFile (File dir) + { + + return new File (dir, Constants.EDITORS_DB_FILE_NAME_PREFIX); + + } + + public static int getSchemaVersion (File dir) + { + + File dbf = new File (EditorsEnvironment.getEditorsDBFile (dir).getPath () + Constants.H2_DB_FILE_SUFFIX); + + if (!dbf.exists ()) + { + + return 0; + + } + + return EditorsEnvironment.schemaVersion; + + } + + public static EditorAccount getUserAccount () + { + + return EditorsEnvironment.editorAccount; + + } + + public static EditorsMessageHandler getMessageHandler () + { + + return EditorsEnvironment.messageHandler; + + } + + public static Set getWritingGenres () + { + + String gt = EditorsEnvironment.editorsProps.getProperty (Constants.WRITING_GENRES_PROPERTY_NAME); + + Set gitems = new LinkedHashSet (); + + StringTokenizer t = new StringTokenizer (gt, + ","); + + while (t.hasMoreTokens ()) + { + + gitems.add (t.nextToken ().trim ()); + + } + + return gitems; + + } + + public static EditorsWebServiceHandler getEditorsWebServiceHandler () + { + + return EditorsEnvironment.editorsHandler; + + } + + public static Set getAllUndealtWithMessages () + throws Exception + { + + if (EditorsEnvironment.editorsManager == null) + { + + return null; + + } + + return EditorsEnvironment.editorsManager.getAllUndealtWithMessages (); + + } + + public static Set getProjectMessages (String projId, + String... messageTypes) + throws Exception + { + + return EditorsEnvironment.editorsManager.getProjectMessages (projId, + messageTypes); + + } + + /** + * Get a count of all the messages the user hasn't dealt with. + * + * @return The count. + */ + public static int getUndealtWithMessageCount () + throws Exception + { + + if (EditorsEnvironment.editorsManager == null) + { + + return 0; + + } + + return EditorsEnvironment.editorsManager.getUndealtWithMessageCount (); + + } + + public static File getEditorsAuthorAvatarImageFile (String suffix) + { + + if (suffix == null) + { + + return null; + + } + + File f = new File (Environment.getUserQuollWriterDirPath ().toFile (), + Constants.EDITORS_AUTHOR_AVATAR_IMAGE_FILE_NAME_PREFIX + "." + suffix); + + f.getParentFile ().mkdirs (); + + return f; + + } + + public static File getEditorsAuthorAvatarImageFile () + { + + if (EditorsEnvironment.editorsHandler == null) + { + + return null; + + } + + if (EditorsEnvironment.editorAccount == null) + { + + return null; + + } + + EditorAuthor au = EditorsEnvironment.editorAccount.getAuthor (); + + if (au == null) + { + + return null; + + } + + String t = EditorsEnvironment.editorsProps.getProperty (Constants.EDITORS_AUTHOR_AVATAR_IMAGE_FILE_TYPE_PROPERTY_NAME); + + return EditorsEnvironment.getEditorsAuthorAvatarImageFile (t); + + } + + public static File getEditorsAuthorFile () + { + + File f = new File (Environment.getUserQuollWriterDirPath ().toFile (), + Constants.EDITORS_AUTHOR_FILE_NAME); + + f.getParentFile ().mkdirs (); + + return f; + + } + + public static File getEditorsEditorAvatarImageFile (String suffix) + { + + if (suffix == null) + { + + return null; + + } + + File f = new File (Environment.getUserQuollWriterDirPath ().toFile (), + Constants.EDITORS_EDITOR_AVATAR_IMAGE_FILE_NAME_PREFIX + "." + suffix); + + f.getParentFile ().mkdirs (); + + return f; + + } + + public static File getEditorsEditorAvatarImageFile () + { + + if (EditorsEnvironment.editorsHandler == null) + { + + return null; + + } + + if (EditorsEnvironment.editorAccount == null) + { + + return null; + + } + + EditorEditor ed = EditorsEnvironment.editorAccount.getEditor (); + + if (ed == null) + { + + return null; + + } + + String t = EditorsEnvironment.editorsProps.getProperty (Constants.EDITORS_EDITOR_AVATAR_IMAGE_FILE_TYPE_PROPERTY_NAME); + + return EditorsEnvironment.getEditorsEditorAvatarImageFile (t); + + } + + public static File getEditorsEditorFile () + { + + File f = new File (Environment.getUserQuollWriterDirPath ().toFile (), + Constants.EDITORS_EDITOR_FILE_NAME); + + f.getParentFile ().mkdirs (); + + return f; + + } + + public static void clearUserPassword () + { + + if (EditorsEnvironment.editorAccount != null) + { + + EditorsEnvironment.editorAccount.setPassword (null); + + } + + } + + public static void getInvite (EditorEditor editor, + EditorsWebServiceAction onComplete, + EditorsWebServiceAction onError) + { + + EditorsEnvironment.editorsHandler.getInvite (editor, + onComplete, + onError); + + } + + public static void getInvite (String fromEmail, + EditorsWebServiceAction onComplete, + EditorsWebServiceAction onError) + { + + EditorsEnvironment.editorsHandler.getInvite (fromEmail, + onComplete, + onError); + + } + + public static void deleteMessages (Set messages) + throws Exception + { + + // TODO: Clean up the Set/List mess. + EditorsEnvironment.editorsManager.deleteObjects (new ArrayList (messages), + null); + + } + + public static void acceptInvite (final EditorEditor editor, + final EditorMessage message, + final Runnable onComplete) + { + + final String email = editor.getEmail (); + + EditorsEnvironment.editorsHandler.updateInvite (email, + Invite.Status.accepted, + new EditorsWebServiceAction () + { + + public void processResult (EditorsWebServiceResult res) + { + + try + { + + editor.setEditorStatus (EditorEditor.EditorStatus.current); + + EditorsEnvironment.updateEditor (editor); + + } catch (Exception e) { + + Environment.logError ("Unable to update editor: " + + editor + + " to accepted", + e); + + ComponentUtils.showErrorMessage (getUILanguageStringProperty (LanguageStrings.editors,LanguageStrings.editor,edit,actionerror)); + //"Unable to update {editor} information in local database."); + + return; + + } + + // Send an invite response message. + EditorsEnvironment.getMessageHandler ().subscribeToEditor (editor); + + EditorsEnvironment.sendMessageToEditor (message, + onComplete, + null, + null); + + } + }, + null); + + } + + public static void rejectInvite (final EditorEditor editor, + final EditorMessage message, + final Runnable onComplete) + { + + final String email = editor.getEmail (); + + EditorsEnvironment.editorsHandler.updateInvite (email, + Invite.Status.rejected, + new EditorsWebServiceAction () + { + + public void processResult (EditorsWebServiceResult res) + { + + try + { + + editor.setEditorStatus (EditorEditor.EditorStatus.rejected); + + EditorsEnvironment.updateEditor (editor); + + } catch (Exception e) { + + ComponentUtils.showErrorMessage (getUILanguageStringProperty (LanguageStrings.editors,LanguageStrings.editor,edit,actionerror)); + //"Unable to update {editor} information in local database."); + + Environment.logError ("Unable to update editor: " + + editor + + " to rejected", + e); + + return; + + } + + EditorsEnvironment.sendMessageToEditor (message, + onComplete, + null, + null); + + } + }, + null); + + } + + public static void updateInvite (final String email, + final Invite.Status newStatus, + final Runnable onUpdateComplete) + { + + EditorsEnvironment.editorsHandler.updateInvite (email, + newStatus, + new EditorsWebServiceAction () + { + + public void processResult (EditorsWebServiceResult res) + { + + EditorEditor ed = EditorsEnvironment.getEditorByEmail (email); + + EditorEditor.EditorStatus status = null; + + if (newStatus == Invite.Status.accepted) + { + + status = EditorEditor.EditorStatus.current; + + } else { + + status = EditorEditor.EditorStatus.valueOf (newStatus.getType ()); + + } + + try + { + + if (ed != null) + { + + ed.setEditorStatus (status); + + EditorsEnvironment.updateEditor (ed); + + } else { + + ed = new EditorEditor (); + + ed.setEmail (email); + ed.setEditorStatus (status); + + // Add to our editors. + EditorsEnvironment.addNewEditor (ed); + + } + + } catch (Exception e) { + + Environment.logError ("Unable to update editor: " + + email + + " to status: " + + status, + e); + + ComponentUtils.showErrorMessage (getUILanguageStringProperty (LanguageStrings.editors,editor,edit,actionerror)); + //"Unable to update {editor} information in local database."); + + return; + + } + + if (onUpdateComplete != null) + { + + Environment.scheduleImmediately (onUpdateComplete); + + } + + } + }, + null); + + } + + public static void closeDown () + { + + EditorsEnvironment.goOffline (); + + // Close all the db connections. + if (EditorsEnvironment.editorsManager != null) + { + + EditorsEnvironment.editorsManager.closeConnectionPool (); + + } + + } + public static void goOffline () + { + + EditorsEnvironment.editorsHandler.logout (); + + EditorsEnvironment.messageHandler.logout (null); + + EditorsEnvironment.userOnlineStatusProp.setValue (EditorEditor.OnlineStatus.offline); + + EditorsEnvironment.fireUserOnlineStatusChanged (EditorsEnvironment.userOnlineStatusProp.getValue ()); + + for (EditorEditor ed : EditorsEnvironment.editors) + { + + ed.setOnlineStatus (null); + + EditorsEnvironment.fireEditorChangedEvent (new EditorChangedEvent (ed, + EditorChangedEvent.EDITOR_CHANGED)); + + } + + } + + public static boolean isMessageSendInProgress () + { + + return EditorsEnvironment.messageHandler.isMessageSendInProgress (); + + } + + public static void updateUserPassword (final String newPassword) + { + + EditorsEnvironment.editorsHandler.changePassword (newPassword, + new EditorsWebServiceAction () + { + + @Override + public void processResult (EditorsWebServiceResult res) + { + + EditorsEnvironment.messageHandler.changePassword (newPassword, + () -> + { + + try + { + + EditorsEnvironment.editorAccount.setPassword (newPassword); + + if (EditorsEnvironment.getEditorsProperty (Constants.QW_EDITORS_SERVICE_PASSWORD_PROPERTY_NAME) != null) + { + + EditorsEnvironment.setEditorsProperty (Constants.QW_EDITORS_SERVICE_PASSWORD_PROPERTY_NAME, + newPassword); + + } + + } catch (Exception e) { + + Environment.logError ("Unable to update password", + e); + + } + + UIUtils.runLater (() -> + { + + QuollPopup.messageBuilder () + .inViewer (Environment.getFocusedViewer ()) + .title (LanguageStrings.editors,user,edit,password,confirmpopup,title) + .message (LanguageStrings.editors,user,edit,password,confirmpopup,text) + .closeButton () + .build (); + + }); + + }, + null, + exp -> + { + + ComponentUtils.showErrorMessage (getUILanguageStringProperty (LanguageStrings.editors,user,edit,password,actionerror)); + //"Unable to update your password, please contact Quoll Writer support for assistance."); + + }); + + } + + }, + new EditorsWebServiceAction () + { + + @Override + public void processResult (EditorsWebServiceResult res) + { + + ComponentUtils.showErrorMessage (getUILanguageStringProperty (LanguageStrings.editors,user,edit,password,actionerror)); + + } + + }); + + } + + private static void checkForUndealtWithMessages () + { + + final AbstractViewer viewer = Environment.getFocusedViewer (); + + if (viewer == null) + { + + return; + + } + + if (!viewer.isEditorsSideBarVisible ()) + { + + int c = 0; + + try + { + + c = EditorsEnvironment.getUndealtWithMessageCount (); + + } catch (Exception e) { + + Environment.logError ("Unable to get undealt with message count", + e); + + return; + + } + + if (c > 0) + { + +/* + String s = "There are %s {Editor} messages requiring your attention."; + + if (c == 1) + { + + s = "There is 1 {Editor} message that requires your attention."; + + } +*/ + + int _c = c; + + //xxx get notification by name. + UIUtils.runLater (() -> + { + + final Notification n = viewer.addNotification (getUILanguageStringProperty (Arrays.asList (LanguageStrings.editors,messages,undealtwith,notification), + //+ " Click here to view the message(s).", + _c), + StyleClassNames.EDITORS, + 60); + + Node nn = n.getContent (); + + nn.addEventHandler (MouseEvent.MOUSE_CLICKED, + ev -> + { + + viewer.removeNotification (n); + + }); + + }); + + } + + } + + } + + private static void startMessageNotificationThread () + { + + // Start the listener for messages. + // Display a notification is there are undealt with messages. + // Only show if the editors side bar isn't visible. + Environment.schedule (() -> + { + + // TODO Remove t.setName ("editors-service-check-for-undealt-with-messages"); + //t.setPriority (Thread.MIN_PRIORITY); + + if (EditorsEnvironment.editorAccount != null) + { + + try + { + + EditorsEnvironment.checkForUndealtWithMessages (); + + } catch (Exception e) { + + Environment.logError ("Unable to get undealt with messages", + e); + + } + + } + + }, + 1, + 10 * Constants.MIN_IN_MILLIS); + + } + + public static void goOnline (final StringProperty loginReason, + final Runnable onLogin, + final Runnable onCancel, + final Consumer onError) + { + + final com.quollwriter.ui.fx.viewers.AbstractViewer viewer = Environment.getFocusedViewer (); + + final StringProperty reason = (loginReason != null ? loginReason : getUILanguageStringProperty (LanguageStrings.editors,login,reasons,_default)); + //"To go online you must first login."); + + Runnable login = () -> + { + + EditorsEnvironment.editorsHandler.login (() -> + { + + EditorsEnvironment.messageHandler.login (() -> + { + + EditorsUIUtils.hideLogin (); + + try + { + + EditorsEnvironment.setEditorsProperty (Constants.QW_EDITORS_SERVICE_HAS_LOGGED_IN_PROPERTY_NAME, + true); + + } catch (Exception e) { + + Environment.logError ("Unable to set property", + e); + + } + + if (EditorsEnvironment.editorAccount.getLastLogin () == null) + { + + EditorsEnvironment.getEditorsWebServiceHandler ().checkPendingInvites (); + + } + + EditorsEnvironment.setDefaultUserOnlineStatus (); + + //EditorsEnvironment.currentOnlineStatus = EditorEditor.OnlineStatus.online; + + //EditorsEnvironment.fireUserOnlineStatusChanged (EditorsEnvironment.currentOnlineStatus); + + java.util.Date d = new java.util.Date (); + + EditorsEnvironment.editorAccount.setLastLogin (d); + + try + { + + EditorsEnvironment.editorsManager.setLastLogin (d); + + } catch (Exception e) { + + Environment.logError ("Unable to set last login date", + e); + + } + + EditorsEnvironment.startMessageNotificationThread (); + + if (onLogin != null) + { + + Environment.scheduleImmediately (onLogin); + + } + + }, + onError); + + }, + onError); + + }; + + if (EditorsEnvironment.hasLoginCredentials ()) + { + + Environment.scheduleImmediately (login); + + } else { + + EditorsUIUtils.showLogin (viewer, + reason, + login, + onCancel); + + } + + } +/* +TODO Remove + public static void goOnline (final String loginReason, + final ActionListener onLogin, + final ActionListener onCancel, + final ActionListener onError) + { + + final AbstractViewer viewer = null; // TODO Environment.getFocusedViewer (); + + final String reason = (loginReason != null ? loginReason : getUIString (LanguageStrings.editors,login,reasons,_default)); + //"To go online you must first login."); + + ActionListener login = new ActionListener () + { + + public void actionPerformed (ActionEvent ev) + { + + EditorsEnvironment.editorsHandler.login (new ActionListener () + { + + public void actionPerformed (ActionEvent ev) + { + + EditorsEnvironment.messageHandler.login (new ActionListener () + { + + public void actionPerformed (ActionEvent ev) + { + + EditorsUIUtils.hideLogin (); + + try + { + + EditorsEnvironment.setEditorsProperty (Constants.QW_EDITORS_SERVICE_HAS_LOGGED_IN_PROPERTY_NAME, + true); + + } catch (Exception e) { + + Environment.logError ("Unable to set property", + e); + + } + + //EditorsEnvironment.getEditorsWebServiceHandler ().checkPendingInvites (); + + if (EditorsEnvironment.editorAccount.getLastLogin () == null) + { + + EditorsEnvironment.getEditorsWebServiceHandler ().checkPendingInvites (); + + } + + EditorsEnvironment.setDefaultUserOnlineStatus (); + + //EditorsEnvironment.currentOnlineStatus = EditorEditor.OnlineStatus.online; + + //EditorsEnvironment.fireUserOnlineStatusChanged (EditorsEnvironment.currentOnlineStatus); + + java.util.Date d = new java.util.Date (); + + EditorsEnvironment.editorAccount.setLastLogin (d); + + try + { + + EditorsEnvironment.editorsManager.setLastLogin (d); + + } catch (Exception e) { + + Environment.logError ("Unable to set last login date", + e); + + } + + EditorsEnvironment.startMessageNotificationThread (); + + if (onLogin != null) + { + + onLogin.actionPerformed (ev); + + } + + } + + }, + onError); + + } + + }, + onError); + + } + + }; + + if (EditorsEnvironment.hasLoginCredentials ()) + { + + login.actionPerformed (new ActionEvent ("login", 1, "login")); + + } else { + + EditorsUIUtils.showLogin (viewer, + reason, + login, + onCancel); + + } + + } +*/ + public static void sendMessageToAllEditors (StringProperty loginReason, + EditorMessage mess, + Runnable onSend, + Runnable onLoginCancel, + Consumer onError) + { + + EditorsEnvironment.sendMessageToAllEditors (new ArrayDeque (EditorsEnvironment.editors), + loginReason, + mess, + onSend, + onLoginCancel, + onError); + + } + + private static void sendMessageToAllEditors (final Deque eds, + final StringProperty loginReason, + final EditorMessage mess, + final Runnable onSend, + final Runnable onLoginCancel, + final Consumer onError) + { + + if (eds.size () == 0) + { + + if (onSend != null) + { + + Environment.scheduleImmediately (onSend); + + } + + } else { + + EditorEditor ed = eds.pop (); + + if (ed.isPrevious ()) + { + + EditorsEnvironment.sendMessageToAllEditors (eds, + loginReason, + mess, + onSend, + onLoginCancel, + onError); + + return; + + } + + Runnable onSendComplete = () -> + { + + EditorsEnvironment.sendMessageToAllEditors (eds, + loginReason, + mess, + onSend, + onLoginCancel, + onError); + + }; + + EditorsEnvironment.messageHandler.sendMessage (loginReason, + mess, + ed, + onSendComplete, + onLoginCancel, + onError); + + } + + } + + + public static void sendUserInformationToAllEditors (Runnable onSend, + Runnable onLoginCancel, + Consumer onError) + { + + StringProperty loginReason = getUILanguageStringProperty (LanguageStrings.editors,login,reasons,updateinfotoall); + + EditorsEnvironment.sendMessageToAllEditors (loginReason, + new EditorInfoMessage (EditorsEnvironment.getUserAccount ()), + onSend, + onLoginCancel, + onError); + + } + + public static void sendUserInformationToEditor (EditorEditor ed, + Runnable onSend, + Runnable onLoginCancel, + Consumer onError) + { + + EditorsEnvironment.messageHandler.sendMessage (getUILanguageStringProperty (Arrays.asList (LanguageStrings.editors,login,reasons,updateinfotocontact), + ed.getMainName ()), + //"To send your information to " + ed.getMainName () + " you must first login to the Editors Service.", + new EditorInfoMessage (EditorsEnvironment.getUserAccount ()), + ed, + onSend, + onLoginCancel, + onError); + + } + + public static void sendInteractionMessageToEditor (InteractionMessage.Action action, + EditorEditor ed, + Runnable onSend) + { + + if (!EditorsEnvironment.messageHandler.isLoggedIn ()) + { + + return; + + } + + // Only send if editor is online. + if (ed.isOffline ()) + { + + return; + + } + + EditorsEnvironment.sendMessageToEditor (new InteractionMessage (action, + ed), + onSend, + null, + null); + + } + + public static void sendMessageToEditor (final EditorMessage mess, + final Runnable onSend, + final Runnable onLoginCancel, + final Consumer onError) + { + + EditorsEnvironment.messageHandler.sendMessage (getUILanguageStringProperty (Arrays.asList (LanguageStrings.editors,login,reasons,sendmessagetocontact), + mess.getEditor ().getMainName ()), + //"To send a message to " + mess.getEditor ().getMainName () + " you must first login to the Editors service.", + mess, + mess.getEditor (), + onSend, + onLoginCancel, + onError); + + } + + public static void sendInvite (String toEmail, + AbstractViewer viewer) + { + + EditorsEnvironment.editorsHandler.sendInvite (toEmail, + new EditorsWebServiceAction () + { + + public void processResult (EditorsWebServiceResult res) + { + + boolean add = false; + + // See if we already have this editor and this is a resend. + EditorEditor fed = EditorsEnvironment.getEditorByEmail (toEmail); + + if (fed == null) + { + + fed = new EditorEditor (); + add = true; + + } + + final EditorEditor ed = fed; + + // Add the invite to our local editors. + try + { + + ed.setEmail (toEmail.trim ().toLowerCase ()); + ed.setInvitedByMe (true); + + //String resS = res.getReturnObjectAsString (); + + Invite inv = Invite.createFrom ((Map) res.getReturnObject ()); + /* + if (resS != null) + { + + // Need a better way of handling this. + if (!res.isSuccess ()) + { + + // This is the public key of the editor. + ed.setTheirPublicKey (EditorsUtils.convertToPGPPublicKey (Base64.decode (resS))); + + } + + } + */ + + + ed.setTheirPublicKey (inv.getToPublicKey ()); + ed.setMessagingUsername (inv.getToMessagingUsername ()); + ed.setServiceName (inv.getToServiceName ()); + + if (add) + { + + // Add as new. + EditorsEnvironment.addNewEditor (ed); + + } + + // If they have a public key then send an invite message. + if (ed.getTheirPublicKey () != null) + { + + Runnable onCancel = new Runnable () + { + + private boolean inviteSent = false; + + @Override + public void run () + { + + if (this.inviteSent) + { + + return; + + } + + this.inviteSent = true; + + InviteMessage invite = new InviteMessage (EditorsEnvironment.editorAccount); + + invite.setEditor (ed); + + // Send an invite. + EditorsEnvironment.sendMessageToEditor (invite, + () -> + { + + UIUtils.runLater (() -> + { + + List prefix = Arrays.asList (LanguageStrings.editors,user,invitesent,popup); + + AbstractViewer viewer = Environment.getFocusedViewer (); + + QuollPopup.messageBuilder () + .withViewer (viewer) + .title (Utils.newList (prefix,title)) + .closeButton () + .message (getUILanguageStringProperty (Utils.newList (prefix,text), + toEmail)) + .build (); + + }); + + }, + null, + null); + + } + + }; + + if (viewer instanceof AbstractProjectViewer) + { + + UIUtils.runLater (() -> + { + + List prefix = Arrays.asList (LanguageStrings.editors,user,sendprojectoninvite,popup); + + QuollPopup p = QuollPopup.questionBuilder () + .withViewer (viewer) + .styleClassName (StyleClassNames.PROJECT) + .title (Utils.newList (prefix,title)) + .message (getUILanguageStringProperty (Utils.newList (prefix,text), + ed.getMainName ())) + .confirmButtonLabel (Utils.newList (prefix,buttons,confirm)) + .cancelButtonLabel (Utils.newList (prefix,buttons,cancel)) + .onConfirm (ev -> + { + + EditorsUIUtils.showSendProject ((AbstractProjectViewer) viewer, + ed, + null); + + }) + .onCancel (ev -> + { + + UIUtils.runLater (onCancel); + + }) + .build (); + + }); + + return; + + } else { + + Environment.scheduleImmediately (onCancel); + + return; + + } + + } + + } catch (Exception e) { + + Environment.logError ("Unable to add new editor to local", + e); + + // Show an error. + // Can't uninvite, what to do? + ComponentUtils.showErrorMessage (getUILanguageStringProperty (LanguageStrings.editors,user,sendinvite,actionerror)); + //"An internal error has occurred while saving the invite to local storage. Please contact Quoll Writer support for assistance."); + + return; + + } + + QuollPopup.messageBuilder () + .withViewer (viewer) + .title (LanguageStrings.editors,user,invitesent,popup,title) + .closeButton () + .message (getUILanguageStringProperty (Arrays.asList (LanguageStrings.editors,user,invitesent,popup,text), + toEmail)) + .build (); + + } + + }, + null); + + } + + public static boolean hasLoginCredentials () + { + + if (EditorsEnvironment.editorAccount == null) + { + + return false; + + } + + return ((EditorsEnvironment.editorAccount.getEmail () != null) + && + (EditorsEnvironment.editorAccount.getPassword () != null)); + + } + + public static void setLoginCredentials (String email, + String password) + { + + if (EditorsEnvironment.editorAccount == null) + { + + throw new IllegalStateException ("No account available."); + + } + + EditorsEnvironment.editorAccount.setEmail (email); + EditorsEnvironment.editorAccount.setPassword (password); + + } + + public static void initUserCredentials (String email, + String password, + String serviceName, + String messagingUsername, + PGPPublicKey publicKey, + PGPPrivateKey privateKey) + throws GeneralException + { + + if (EditorsEnvironment.editorAccount != null) + { + + throw new GeneralException ("Already have an editor account"); + + } + + EditorsEnvironment.editorAccount = new EditorAccount (); + + EditorsEnvironment.editorAccount.setEmail (email); + EditorsEnvironment.editorAccount.setPassword (password); + EditorsEnvironment.editorAccount.setPublicKey (publicKey); + EditorsEnvironment.editorAccount.setPrivateKey (privateKey); + EditorsEnvironment.editorAccount.setServiceName (serviceName); + EditorsEnvironment.editorAccount.setMessagingUsername (messagingUsername); + + EditorsEnvironment.editorsManager.setUserInformation (EditorsEnvironment.editorAccount); + + } + + public static boolean hasRegistered () + { + + return EditorsEnvironment.editorAccount != null; + + } + + public synchronized static void loadMessagesForEditor (EditorEditor ed) + throws GeneralException + { + + if (ed == null) + { + + throw new NullPointerException ("Expected an editor"); + + } + + if (ed.messagesLoaded ()) + { + + return; + + } + + synchronized (ed) + { + + // Oh java why you so kooky... + ed.setMessages (new LinkedHashSet ((List) EditorsEnvironment.editorsManager.getObjects (EditorMessage.class, + ed, + null, + true))); + + } + + } + /* + public static void sendNewProjectResponse (final NewProjectMessage mess, + final boolean accepted, + final String responseMessage) + throws GeneralException + { + + NewProjectResponseMessage res = new NewProjectResponseMessage (mess.getForProjectId (), + accepted, + responseMessage, + mess.getEditor ()); + + res.setDealtWith (true); + + // For now just return rejected. + EditorsEnvironment.sendMessageToEditor (res, + new ActionListener () + { + + public void actionPerformed (ActionEvent ev) + { + + try + { + + mess.setAccepted (accepted); + mess.setDealtWith (true); + mess.setResponseMessage (responseMessage); + + // Update the original message. + EditorsEnvironment.updateMessage (mess); + + } catch (Exception e) { + + UIUtils.showErrorMessage (null, + "Unable to update {project} message, please contact Quoll Writer support for assistance."); + + Environment.logError ("Unable to update new project message: " + + mess, + e); + + } + + } + + }, + null, + null); + + } + */ + public static void sendError (EditorMessage mess, + ErrorMessage.ErrorType errorType, + String reason) + { + + try + { + + EditorsEnvironment.sendMessageToEditor (new ErrorMessage (mess, + errorType, + reason), + null, + null, + null); + + } catch (Exception e) { + + Environment.logError ("Unable to send error message for message: " + + mess.getMessageId () + + " to editor: " + + mess.getEditor () + + " with error type: " + + errorType.getType (), + e); + + } + + } + + public static Map getOriginalMessageAsMap (EditorMessage m) + throws Exception + { + + if (m.isSentByMe ()) + { + + throw new IllegalArgumentException ("Not supported for messages sent by me."); + + } + + byte[] bytes = EditorsEnvironment.editorsManager.getOriginalMessage (m); + + // Decrypt first. + try + { + + bytes = EditorsUtils.decrypt (bytes, + EditorsEnvironment.editorAccount.getPrivateKey (), + m.getEditor ().getTheirPublicKey ()); + + } catch (Exception e) { + + throw new GeneralException ("Unable to decrypt message from editor: " + + m.getEditor (), + e); + + } + + String messageData = null; + + try + { + + messageData = new String (bytes, + "utf-8"); + + } catch (Exception e) { + + throw new GeneralException ("Unable to convert decrypted message to a string from editor: " + + m.getEditor (), + e); + + } + + // JSON decode + Map data = (Map) JSONDecoder.decode (messageData); + + return data; + + } + + public static ProjectEditor getProjectEditor (Project p, + EditorEditor ed) + throws Exception + { + + return EditorsEnvironment.getProjectEditor (Environment.getProjectById (p.getId (), + p.getType ()), + ed); + + } + + public static ProjectEditor getProjectEditor (ProjectInfo p, + EditorEditor ed) + throws GeneralException + { + + if (EditorsEnvironment.editorAccount == null) + { + + return null; + + } + + if (p == null) + { + + return null; + + } + + if (ed == null) + { + + return null; + + } + + List pes = (List) EditorsEnvironment.editorsManager.getObjects (ProjectEditor.class, + p, + null, + false); + + for (ProjectEditor pe : pes) + { + + if (pe.getEditor () == ed) + { + + return pe; + + } + + } + + return null; + + } + + public static List getProjectEditors (String projectId) + throws GeneralException + { + + if (EditorsEnvironment.editorAccount == null) + { + + return null; + + } + + ProjectInfo p = new ProjectInfo (); + p.setId (projectId); + + return (List) EditorsEnvironment.editorsManager.getObjects (ProjectEditor.class, + p, + null, + false); + + } + /* + public static String getUserPublicKeyBase64EncodedX () + { + + if (this.userPublicKey == null) + { + + return null; + + } + + RSAPublicBCPGKey pubKey = (RSAPublicBCPGKey) this.myPublicKey.getPublicKeyPacket ().getKey (); + + return Base64.encodeBytes (pubKey.getEncoded ()); + + } + */ + + public static void sendProjectEditStopMessage (final Project p, + final Runnable onComplete) + { + + EditorsEnvironment.sendProjectEditStopMessage (Environment.getProjectInfo (p), + onComplete); + + } + + public static void sendProjectEditStopMessage (final ProjectInfo p, + final Runnable onComplete) + { + + if (!p.isEditorProject ()) + { + + throw new IllegalArgumentException ("Only editor projects can be deleted."); + + } + + // Send message saying no longer editing. + ProjectEditStopMessage message = new ProjectEditStopMessage (p, + null, + p.getForEditor ()); + + EditorsEnvironment.sendMessageToEditor (message, + onComplete, + null, + null); + + } + + public static void addProjectEditor (ProjectEditor pe) + throws GeneralException + { + + EditorsEnvironment.editorsManager.saveObject (pe, + null); + + // Fire an event. + EditorsEnvironment.fireProjectEditorChangedEvent (pe, + ProjectEditorChangedEvent.PROJECT_EDITOR_ADDED); + + } + + public static void removeProjectEditors (Project p) + throws GeneralException + { + + if (EditorsEnvironment.editorsManager == null) + { + + return; + + } + + List pes = EditorsEnvironment.getProjectEditors (p.getId ()); + + EditorsEnvironment.editorsManager.deleteObjects (pes, + null); + + for (ProjectEditor pe : pes) + { + + // Fire an event. + EditorsEnvironment.fireProjectEditorChangedEvent (pe, + ProjectEditorChangedEvent.PROJECT_EDITOR_DELETED); + + } + + } + + public static void removeProjectEditor (ProjectEditor pe) + throws GeneralException + { + + if (EditorsEnvironment.editorsManager == null) + { + + return; + + } + + EditorsEnvironment.editorsManager.deleteObject (pe, + false, + null); + + // Remove from any project tied to a project viewer. + ProjectInfo proj = null; + + try + { + + proj = Environment.getProjectById (pe.getForProjectId (), + Project.NORMAL_PROJECT_TYPE); + + } catch (Exception e) { + + Environment.logError ("Unable to get project for id: " + + pe.getForProjectId (), + e); + + } + + if (proj != null) + { + + AbstractProjectViewer pv = Environment.getProjectViewer (proj); + + if (proj != null) + { + + pv.getProject ().removeProjectEditor (pe); + + } + + } +/* + if (pe.isAccepted ()) + { + + // Only send this if the editor has already accepted the project. + ProjectEditStopMessage mess = new ProjectEditStopMessage (pe.getProject (), + null, + pe.getEditor ()); + + EditorsEnvironment.sendMessageToEditor (mess); + + } + */ + // Fire an event. + EditorsEnvironment.fireProjectEditorChangedEvent (pe, + ProjectEditorChangedEvent.PROJECT_EDITOR_DELETED); + + } + + public static Set getProjectsSentToEditor (EditorEditor ed) + throws Exception + { + + if (EditorsEnvironment.editorsManager == null) + { + + return null; + + } + + return EditorsEnvironment.editorsManager.getProjectsSentToEditor (ed); + + } + + public static Set getProjectsForEditor (EditorEditor ed) + throws Exception + { + + Set projs = new LinkedHashSet (); + + for (ProjectInfo p : Environment.getAllProjectInfos ()) + { + + if (p.getForEditor () == null) + { + + continue; + + } + + if (p.getForEditor ().getEmail ().equals (ed.getEmail ())) + { + + projs.add (p); + + } + + } + + return projs; + + } +/* +TODO Remove, never used. + public static void setProjectEditorStatus (final String projId, + final EditorEditor ed, + final String newStatus) + throws Exception + { + + ProjectInfo proj = null; + + try + { + + proj = Environment.getProjectById (projId, + Project.NORMAL_PROJECT_TYPE); + + } catch (Exception e) { + + throw new GeneralException ("Unable to get project for id: " + + projId, + e); + + } + + ProjectEditor pe = EditorsEnvironment.getProjectEditor (proj, + ed); + + if (pe == null) + { + + throw new IllegalArgumentException ("Editor is not a project editor for project: " + projId + ", editor: " + ed); + + } + + pe.setStatusMessage (newStatus); + + EditorsEnvironment.updateProjectEditor (pe); + + } +*/ + public static void removeEditorAsProjectEditorForAllProjects (final EditorEditor ed) + throws Exception + { + + Set projs = Environment.getAllProjectInfos (); + + for (ProjectInfo p : projs) + { + + ProjectEditor pe = EditorsEnvironment.getProjectEditor (p, + ed); + + if (pe == null) + { + + continue; + + } + + pe.setEditorTo (new java.util.Date ()); + pe.setCurrent (false); + pe.setStatusMessage (Arrays.asList (LanguageStrings.editors,editor,remove,editorstatus), + null); + //"Removed"); + + EditorsEnvironment.updateProjectEditor (pe); + + } + + } + + public static void removePendingEditor (final EditorEditor ed, + final Runnable onDeleteComplete) + { + + if (!ed.isPending ()) + { + + throw new IllegalStateException ("Only pending editors can be deleted using this method."); + + } + + final Runnable doDelete = () -> + { + + EditorsEnvironment.removeEditor (ed, + onDeleteComplete); + + }; + + EditorsEnvironment.editorsHandler.deleteInvite (ed, + new EditorsWebServiceAction () + { + + public void processResult (EditorsWebServiceResult res) + { + + Environment.scheduleImmediately (doDelete); + + } + }, + new EditorsWebServiceAction () + { + + public void processResult (EditorsWebServiceResult res) + { + + // If the invite couldn't be found then just delete the editor anyway since it's + // probably been removed from the QW end. + if (res.isNoDataFoundError ()) + { + + Environment.scheduleImmediately (doDelete); + + } else { + + EditorsEnvironment.editorsHandler.getDefaultEditorsWebServiceErrorAction ().processResult (res); + + } + + } + + }); + + } + + public static void removeEditor (final EditorEditor ed, + final Runnable onComplete) + { + + if (ed.isPrevious ()) + { + + if (onComplete != null) + { + + Environment.scheduleImmediately (onComplete); + return; + + } + + } + + // It may be that the user deletes their account and the editor is in a pending + // state but doesn't have an account so we can't send them a message. Instead just + // delete the invite. + if ((ed.isPending ()) + && + (ed.getTheirPublicKey () == null) + ) + { + + try + { + + // Uupdate the editor to be previous. + ed.setEditorStatus (EditorEditor.EditorStatus.previous); + + EditorsEnvironment.updateEditor (ed); + + } catch (Exception e) { + + Environment.logError ("Unable to update editor: " + + ed, + e); + + ComponentUtils.showErrorMessage (getUILanguageStringProperty (LanguageStrings.editors,editor,edit,actionerror)); + //"Unable to update {editor}, please contact Quoll Writer support for assistance."); + + return; + + } + + if (onComplete != null) + { + + Environment.scheduleImmediately (onComplete); + + } + + return; + + } + + // Send the editor removed message + EditorRemovedMessage mess = new EditorRemovedMessage (ed); + + EditorsEnvironment.sendMessageToEditor (mess, + () -> + { + + UIUtils.runLater (() -> + { + + try + { + + // Uupdate the editor to be previous. + ed.setEditorStatus (EditorEditor.EditorStatus.previous); + + EditorsEnvironment.updateEditor (ed); + + } catch (Exception e) { + + Environment.logError ("Unable to update editor: " + + ed, + e); + + ComponentUtils.showErrorMessage (getUILanguageStringProperty (LanguageStrings.editors,editor,edit,actionerror)); + //"Unable to update {editor}, please contact Quoll Writer support for assistance."); + + return; + + } + + try + { + + EditorsEnvironment.removeEditorAsProjectEditorForAllProjects (ed); + + } catch (Exception e) { + + Environment.logError ("Unable to remove editor as project editor: " + + ed, + e); + + ComponentUtils.showErrorMessage (getUILanguageStringProperty (LanguageStrings.editors,editor,edit,actionerror)); + //"Unable to update {editor}, please contact Quoll Writer support for assistance."); + + return; + + } + + }); + + // Unsubscribe. + EditorsEnvironment.messageHandler.unsubscribeFromEditor (ed); + + if (onComplete != null) + { + + Environment.scheduleImmediately (onComplete); + + } + + }, + null, + null); + + } + + public static EditorMessage getMessageByKey (int key) + throws GeneralException + { + + if (EditorsEnvironment.editorsManager == null) + { + + return null; + + } + + return (EditorMessage) (DataObject) EditorsEnvironment.editorsManager.getObjectByKey (EditorMessage.class, + key, + null, // parent object + null, // connection + true); + + } + + public static void addMessage (EditorMessage mess) + throws GeneralException + { + + // TODO: This needs to be changed, ok for now. + if (mess instanceof InteractionMessage) + { + + return; + + } + + EditorsEnvironment.editorsManager.saveObject (mess, + null); + + mess.getEditor ().addMessage (mess); + + EditorsEnvironment.fireEditorMessageEvent (new EditorMessageEvent (mess.getEditor (), + mess, + EditorMessageEvent.MESSAGE_ADDED)); + + } + + public static void updateMessage (EditorMessage mess) + throws GeneralException + { + + EditorsEnvironment.editorsManager.saveObject (mess, + null); + + // Fire an event. + EditorsEnvironment.fireEditorMessageEvent (new EditorMessageEvent (mess.getEditor (), + mess, + EditorMessageEvent.MESSAGE_CHANGED)); + + } + + public static void updateProjectEditor (ProjectEditor pe) + throws GeneralException + { + + EditorsEnvironment.editorsManager.saveObject (pe, + null); + + // Fire an event. + EditorsEnvironment.fireProjectEditorChangedEvent (pe, + ProjectEditorChangedEvent.PROJECT_EDITOR_CHANGED); + + } + + public static void updateEditor (EditorEditor ed) + throws GeneralException + { + + EditorsEnvironment.editorsManager.saveObject (ed, + null); + + // Fire an event. + EditorsEnvironment.fireEditorChangedEvent (ed, + EditorChangedEvent.EDITOR_CHANGED); + + } + + public static void addNewEditor (EditorEditor ed) + throws GeneralException + { + + EditorsEnvironment.editorsManager.saveObject (ed, + null); + + UIUtils.runLater (() -> + { + + EditorsEnvironment.editors.add (ed); + + if (ed.isInvitedByMe ()) + { + + EditorsEnvironment.invitesIveSent.add (ed); + + } else { + + EditorsEnvironment.invitesForMe.add (ed); + + } + + }); + + ed.getBinder ().addChangeListener (ed.editorStatusProperty (), + (pr, oldv, newv) -> + { + + if ((newv == EditorEditor.EditorStatus.current) + && + (oldv != EditorEditor.EditorStatus.current) + ) + { + + EditorsEnvironment.invitesForMe.remove (ed); + EditorsEnvironment.invitesIveSent.remove (ed); + EditorsEnvironment.currentEditors.add (ed); + EditorsEnvironment.previousEditors.remove (ed); + + } + + if (newv == EditorEditor.EditorStatus.previous) + { + + EditorsEnvironment.invitesForMe.remove (ed); + EditorsEnvironment.invitesIveSent.remove (ed); + EditorsEnvironment.currentEditors.remove (ed); + EditorsEnvironment.previousEditors.add (ed); + + } + + }); + + // Fire an event. + EditorsEnvironment.fireEditorChangedEvent (ed, + EditorChangedEvent.EDITOR_ADDED); + + } + + public static void deleteEditor (EditorEditor ed) + throws GeneralException + { + + ed.getBinder ().dispose (); + + // Delete from the project editor. + EditorsEnvironment.editorsManager.deleteEditor (ed); + + EditorsEnvironment.editors.remove (ed); + + EditorsEnvironment.invitesForMe.remove (ed); + EditorsEnvironment.invitesIveSent.remove (ed); + EditorsEnvironment.currentEditors.remove (ed); + EditorsEnvironment.previousEditors.remove (ed); + + // Fire an event. + EditorsEnvironment.fireEditorChangedEvent (ed, + EditorChangedEvent.EDITOR_DELETED); + + } + + public static EditorEditor getEditorByEmail (String em) + { + + if (em == null) + { + + return null; + + } + + em = em.toLowerCase (); + + for (EditorEditor ed : EditorsEnvironment.editors) + { + + if ((ed.getEmail () != null) + && + (ed.getEmail ().equals (em)) + ) + { + + return ed; + + } + + } + + return null; + + } + + public static EditorEditor getEditorByMessagingUsername (String u) + { + + if (u == null) + { + + return null; + + } + + for (EditorEditor ed : EditorsEnvironment.editors) + { + + if ((ed.getMessagingUsername () != null) + && + (ed.getMessagingUsername ().equals (u)) + ) + { + + return ed; + + } + + } + + return null; + + } + + public static EditorEditor getEditorByKey (long key) + { + + if (key < 1) + { + + return null; + + } + + for (EditorEditor ed : EditorsEnvironment.editors) + { + + if (ed.getKey () == key) + { + + return ed; + + } + + } + + return null; + + } + + /** + * Return a count of the number of editors with a status of "pending". + * + * @return The count. + */ + public static int getPendingEditorsCount () + { + + int c = 0; + + for (EditorEditor ed : EditorsEnvironment.editors) + { + + if (ed.getEditorStatus () == EditorEditor.EditorStatus.pending) + { + + c++; + + } + + } + + return c; + + } + + public static ObservableList getPendingInvites () + { + + return EditorsEnvironment.invitesIveSent; + + } + + public static ObservableList getCurrentEditors () + { + + return EditorsEnvironment.currentEditors; + + } + + public static ObservableList getPreviousEditors () + { + + return EditorsEnvironment.previousEditors; + + } + + public static ObservableSet getEditors () + { + + return EditorsEnvironment.editors; + + } + + public static void fireProjectEvent (ProjectEvent ev) + { + + // We'll see? + // Fire to all project viewers? + + } + + public static String getNewMessageId (EditorEditor ed, + String messageType) + throws Exception + { + + return EditorsEnvironment.editorsManager.getNewMessageId (ed, + messageType); + + } + + /* + public static com.gentlyweb.properties.Properties getUserEditorsProperties () + { + + return Environment.userEditorsProperties; + + } +*/ + public static void setEditorsProperty (String name, + com.gentlyweb.properties.AbstractProperty prop) + throws Exception + { + + EditorsEnvironment.editorsProps.setProperty (name, + prop); + + EditorsEnvironment.saveEditorsProperties (null); + + } + + public static void setEditorsProperty (String name, + String value) + throws Exception + { + + EditorsEnvironment.editorsProps.setProperty (name, + new com.gentlyweb.properties.StringProperty (name, + value)); + + EditorsEnvironment.saveEditorsProperties (null); + + } + + public static void setEditorsProperty (String name, + boolean value) + throws Exception + { + + EditorsEnvironment.editorsProps.setProperty (name, + new com.gentlyweb.properties.BooleanProperty (name, + value)); + + EditorsEnvironment.saveEditorsProperties (null); + + } + + public static void removeEditorsProperty (String name) + throws Exception + { + + EditorsEnvironment.editorsProps.removeProperty (name); + + EditorsEnvironment.saveEditorsProperties (null); + + } + + public static void saveEditorsProperties (com.gentlyweb.properties.Properties props) + throws Exception + { + + if (props == null) + { + + props = EditorsEnvironment.editorsProps; + + } + + // Load the per user properties. + DOM4JUtils.writeToFile (props.getAsElement (), + UserProperties.getUserEditorsPropertiesPath (), + true); + + } + + public static boolean getEditorsPropertyAsBoolean (String name) + { + + return EditorsEnvironment.editorsProps.getPropertyAsBoolean (name); + + } + + public static String getEditorsProperty (String name) + { + + return EditorsEnvironment.editorsProps.getProperty (name); + + } + + public static boolean isShowPopupWhenNewMessageReceived () + { + + // Never show popups in full screen mode. + if (Environment.isInFullScreen ()) + { + + return false; + + } + + return false; + //return EditorsEnvironment.getEditorsPropertyAsBoolean (Constants.EDITORS_SHOW_POPUP_WHEN_NEW_MESSAGE_RECEIVED_PROPERTY_NAME); + + } +/* + public static void setShowPopupWhenNewMessageReceived (boolean v) + throws Exception + { + + BooleanProperty prop = new BooleanProperty (Constants.EDITORS_SHOW_POPUP_WHEN_NEW_MESSAGE_RECEIVED_PROPERTY_NAME, + v); + EditorsEnvironment.setEditorsProperty (Constants.EDITORS_SHOW_POPUP_WHEN_NEW_MESSAGE_RECEIVED_PROPERTY_NAME, + prop); + + } +*/ + public static void fullScreenEntered () + { + + // Get the current status. + if (EditorsEnvironment.isUserLoggedIn ()) + { + + if (EditorsEnvironment.getEditorsPropertyAsBoolean (Constants.QW_EDITORS_SERVICE_SET_BUSY_ON_FULL_SCREEN_ENTERED_PROPERTY_NAME)) + { + + // Get the current status, if it's not "busy" then change it to busy. + if (EditorsEnvironment.getUserOnlineStatus () != EditorEditor.OnlineStatus.busy) + { + + EditorsEnvironment.lastOnlineStatus = EditorsEnvironment.getUserOnlineStatus (); + + try + { + + EditorsEnvironment.setUserOnlineStatus (EditorEditor.OnlineStatus.busy); + + } catch (Exception e) { + + Environment.logError ("Unable to set user online status to busy", + e); + + } + + } + + } + + } + + } + + public static void fullScreenExited () + { + + if (EditorsEnvironment.lastOnlineStatus != null) + { + + try + { + + EditorsEnvironment.setUserOnlineStatus (EditorsEnvironment.lastOnlineStatus); + + } catch (Exception e) { + + Environment.logError ("Unable to set user online status to last: " + + EditorsEnvironment.lastOnlineStatus, + e); + + } + + EditorsEnvironment.lastOnlineStatus = null; + + } + + // Check for new messages and show a notification if there are any. + EditorsEnvironment.checkForUndealtWithMessages (); + + } + + /** + * Show a warning message if the editor is offline when the user is trying to send them a message. + * + * @param ed The editor the user is sending a message to. + */ + public static void showMessageSendWarningIfEditorOfflineMessage (EditorEditor ed) + { + + if (ed.isOffline ()) + { + + // TODO: Next release change this to be more in context. + // Has the user seen this before? + //if (!EditorsEnvironment.getEditorsPropertyAsBoolean (Constants.EDITORS_SEEN_OFFLINE_SEND_MESSAGE_PROPERTY_NAME)) + //{ + + AbstractViewer viewer = Environment.getFocusedViewer (); + + QuollPopup.messageBuilder () + .inViewer (viewer) + .title (LanguageStrings.editors,messages,editoroffline,popup,title) + .message (getUILanguageStringProperty (Arrays.asList (LanguageStrings.editors,messages,editoroffline,popup,text), + ed.mainNameProperty ())) + .build (); + + try + { + + EditorsEnvironment.setEditorsProperty (Constants.EDITORS_SEEN_OFFLINE_SEND_MESSAGE_PROPERTY_NAME, + true); + + } catch (Exception e) { + + Environment.logError ("Unable to set property", + e); + + } + + //} + + } + + + } + + public static URL getReportMessageURL () + throws Exception + { + + return new URL (Environment.getQuollWriterWebsite () + UserProperties.get (Constants.EDITORS_SERVICE_REPORT_MESSAGE_PAGE_PROPERTY_NAME)); + + } + + private static void removeAllEditors (final Deque eds, + final Runnable onComplete) + { + + if (eds.size () == 0) + { + + if (onComplete != null) + { + + Environment.scheduleImmediately (onComplete); + + } + + } else { + + EditorEditor ed = eds.pop (); + + Runnable onDeleteComplete = () -> + { + + EditorsEnvironment.removeAllEditors (eds, + onComplete); + + }; + + if (ed.isPending ()) + { + + EditorsEnvironment.removePendingEditor (ed, + onDeleteComplete); + + } else { + + EditorsEnvironment.removeEditor (ed, + onDeleteComplete); + + } + + } + + } + + public static void deleteUserAccount (final Runnable onComplete, + final Consumer onError) + { + + // Send EditorRemoved messages for all editors (but don't remove them). + EditorsEnvironment.goOnline (getUILanguageStringProperty (LanguageStrings.editors,login,reasons,deleteaccount), + //"To delete your account you must first go online.", + () -> + { + + EditorsEnvironment.removeAllEditors (new ArrayDeque (EditorsEnvironment.editors), + () -> + { + + Runnable deleteAcc = () -> + { + + // Delete the account. + EditorsEnvironment.editorsHandler.deleteAccount (new EditorsWebServiceAction () + { + + public void processResult (EditorsWebServiceResult res) + { + + // Sign out. + EditorsEnvironment.goOffline (); + + // Remove saved values (if present). + try + { + + EditorsEnvironment.removeEditorsProperty (Constants.QW_EDITORS_SERVICE_PASSWORD_PROPERTY_NAME); + + } catch (Exception e) { + + Environment.logError ("Unable to remove editors property", + e); + + } + + // Close all the db connections. + EditorsEnvironment.editorsManager.closeConnectionPool (); + + EditorsEnvironment.editorAccount = null; + + try + { + + EditorsEnvironment.removeEditorsProperty (Constants.QW_EDITORS_DB_DIR_PROPERTY_NAME); + + } catch (Exception e) { + + Environment.logError ("Unable to remove editors database location", + e); + + } + + if (onComplete != null) + { + + Environment.scheduleImmediately (onComplete); + + } + + } + }, + new EditorsWebServiceAction () + { + + public void processResult (EditorsWebServiceResult res) + { + + Environment.logError ("Unable to delete user account: " + + res); + + if (onError != null) + { + + Environment.scheduleImmediately (() -> + { + + onError.accept (new Exception (res.getErrorMessage ())); + + }); + + } else { + + ComponentUtils.showErrorMessage (getUILanguageStringProperty (LanguageStrings.editors,user,deleteaccount,actionerror)); + //"Unable to delete your account, please contact Quoll Writer support for assistance."); + + } + + } + + }); + + }; + + // Offer to remove all the editor projects. + UIUtils.runLater (() -> + { + + EditorsUIUtils.showDeleteProjectsForAllEditors (Environment.getFocusedViewer (), + deleteAcc); + + }); + + }); + + }, + null, + onError); + + } + + public static File getEditorsMessageLogFile () + throws IOException + { + + return Environment.getLogDir ().resolve (Constants.EDITOR_MESSAGES_LOG_NAME).toFile (); + + } + + public static ObservableList getInvitesForMe () + { + + return EditorsEnvironment.invitesForMe; + + } + + public static boolean isAutoLoginAtQWStart () + { + + return EditorsEnvironment.getEditorsPropertyAsBoolean (Constants.QW_EDITORS_SERVICE_LOGIN_AT_QW_START_PROPERTY_NAME); + + } + +} diff --git a/src/main/java/com/quollwriter/editors/EditorsMessageHandler.java b/src/main/java/com/quollwriter/editors/EditorsMessageHandler.java new file mode 100644 index 00000000..67432e75 --- /dev/null +++ b/src/main/java/com/quollwriter/editors/EditorsMessageHandler.java @@ -0,0 +1,1850 @@ +package com.quollwriter.editors; + +import java.io.*; +import java.util.*; +import java.util.function.*; +import java.util.concurrent.atomic.*; +import java.util.logging.*; + +import javax.net.ssl.*; + +import javafx.beans.property.*; + +import org.jxmpp.jid.*; +import org.jxmpp.jid.impl.*; +import org.jxmpp.util.*; +import org.jxmpp.stringprep.XmppStringprepException; +import org.jivesoftware.smack.*; +import org.jivesoftware.smack.chat.*; +import org.jivesoftware.smack.roster.*; +import org.jivesoftware.smack.packet.*; +import org.jivesoftware.smack.filter.*; +import org.jivesoftware.smack.provider.*; +import org.jivesoftware.smack.util.*; +import org.jivesoftware.smack.tcp.*; + +import org.jivesoftware.smackx.iqregister.*; +import org.jivesoftware.smackx.offline.*; + +//import com.gentlyweb.utils.*; + +import com.quollwriter.*; +//import com.quollwriter.ui.*; +//import com.quollwriter.ui.components.QPopup; +import com.quollwriter.data.editors.*; +import com.quollwriter.editors.ui.*; +import com.quollwriter.ui.fx.*; +import com.quollwriter.ui.fx.viewers.*; +import com.quollwriter.ui.fx.components.ComponentUtils; +import com.quollwriter.editors.messages.*; + +import static com.quollwriter.LanguageStrings.*; +import static com.quollwriter.uistrings.UILanguageStringsManager.getUILanguageStringProperty; + +public class EditorsMessageHandler implements ChatMessageListener +{ + + private static String SERVER_SUFFIX = null; + + private XMPPTCPConnection conn = null; + + private EntityFullJid userJID = null; + private boolean loggedIn = false; + private EditorMessageProcessor messageProcessor = null; + private boolean logMessages = false; + + // We use an atomic integer here (rather than volatile which has problems with value increment/decrement) + // to keep track of how many messages we are in the process of sending. This is most useful when sending a + // large message and the user has closed down the last project viewer. For example if they send their project + // then close QW straight after. + private AtomicInteger messageSendInProgressCount = new AtomicInteger (0); + + private volatile boolean logoutRequested = false; + + public EditorsMessageHandler () + { + + this.messageProcessor = new DefaultEditorMessageProcessor (); + + } + + public void init () + throws Exception + { + + if (EditorsMessageHandler.SERVER_SUFFIX == null) + { + + EditorsMessageHandler.SERVER_SUFFIX = EditorsEnvironment.getEditorsProperty (Constants.EDITORS_JID_SUFFIX_PROPERTY_NAME); + + if (EditorsMessageHandler.SERVER_SUFFIX == null) + { + + EditorsMessageHandler.SERVER_SUFFIX = "@www.quollwriter.com"; + + } + + } + + } + + private void logMessage (String text) + { + + this.logMessage (text, + null); + + } + + private void logMessage (String text, + EditorMessage mess) + { + + if ((this.logMessages) + || + (Environment.isDebugModeEnabled ()) + ) + { + + String t = text + (mess != null ? ": " + mess : ""); + + Environment.logMessage (t); + + } + + } + + public void logMessages (boolean v) + { + + this.logMessages = v; + + } + + public boolean isMessageSendInProgress () + { + + return this.messageSendInProgressCount.intValue () > 0; + + } + + public boolean isLoggedIn () + { + + return this.loggedIn; + + } + + public EditorEditor.OnlineStatus getOnlineStatus (EditorEditor ed) + throws XmppStringprepException + { + + if ((this.conn == null) + || + (ed == null) + || + (!this.loggedIn) + ) + { + + return null; + + } + + Roster r = Roster.getInstanceFor (this.conn); + + if (r == null) + { + + return null; + + } + + return this.getOnlineStatus (r.getPresence (this.getJID (ed))); + + } + + public EditorEditor.OnlineStatus getOnlineStatus (Presence p) + { + + EditorEditor.OnlineStatus status = EditorEditor.OnlineStatus.offline; + + if (p == null) + { + + return status; + + } + + if (!p.isAvailable ()) + { + + return status; + + } + + switch (p.getMode ()) + { + + case available : + { + + return EditorEditor.OnlineStatus.online; + + } + + case away : + { + + return EditorEditor.OnlineStatus.away; + + } + + case dnd : + { + + return EditorEditor.OnlineStatus.busy; + + } + + case xa : + { + + return EditorEditor.OnlineStatus.snooze; + + } + + } + + return null; + + } + + public void setOnlineStatus (EditorEditor.OnlineStatus status) + throws Exception + { + + Presence.Type type = Presence.Type.available; + Presence.Mode mode = Presence.Mode.available; + + switch (status) + { + + case online : + { + + break; + + } + + case away : + { + + mode = Presence.Mode.away; + break; + + } + + case busy : + { + + mode = Presence.Mode.dnd; + break; + + } + + case snooze : + { + + mode = Presence.Mode.xa; + break; + + } + + } + + Presence presence = new Presence (type); + presence.setMode (mode); + this.conn.sendStanza (presence); + + } + + /** + * Set the object that will deal with the message once it has been received and built. + * We only allow a single instance, as opposed to a listener to prevent handling/displaying + * the message multiple times. The processor is basically responsible for updating the UI and/or + * bringing the message to the user's attention, usually via event firing or displaying popups. + * The processor should NOT save the message, this class handles that. + * + * Where a processor is not specified then an instance of {@link DefaultEditorMessageProcessor} + * will be used. + * + * @param p The processor. + */ + public void setMessageProcessor (EditorMessageProcessor p) + { + + this.messageProcessor = p; + + } + + private void handleMessageForUnknownEditor (final String fromUsername, + final Message message) + { + + final EditorsMessageHandler _this = this; + + this.logMessage ("Processing message for unknown editor: " + fromUsername); + + EditorsEnvironment.getInvite (fromUsername, + new EditorsWebServiceAction () + { + + @Override + public void processResult (EditorsWebServiceResult res) + { + + Map m = (Map) res.getReturnObject (); + + if (m == null) + { + + _this.logMessage ("No invite from unknown editor: " + fromUsername); + + // No invite. + return; + + } + + Invite invite = null; + + try + { + + invite = Invite.createFrom (m); + + } catch (Exception e) { + + Environment.logError ("Unable to create invite from: " + + m + + " from username: " + + fromUsername, + e); + + return; + + } + + // Is the invite deleted? If so just ignore the message. + if (invite.getStatus () == Invite.Status.deleted) + { + + return; + + } + + // Did I send the invite or receive it? + if (invite.getFromEmail ().equals (EditorsEnvironment.getUserAccount ().getEmail ())) + { + + // Send by me. + // Get the editor by their email. + EditorEditor ed = EditorsEnvironment.getEditorByEmail (invite.getToEmail ()); + + if (ed == null) + { + + Environment.logError ("Unable to find editor with email: " + + invite.getToEmail ()); + + return; + + } + + // Update the editor. + ed.setTheirPublicKey (invite.getToPublicKey ()); + + ed.setMessagingUsername (invite.getToMessagingUsername ()); + ed.setServiceName (invite.getToServiceName ()); + + try + { + + _this.processMessageForEditor (ed, + message); + + } catch (Exception e) { + + Environment.logError ("Unable to process message for editor: " + + ed, + e); + + } + + } else { + + // Invite I've received. + if ((invite.getStatus () == Invite.Status.rejected) + || + (invite.getStatus () == Invite.Status.accepted) + ) + { + + Environment.logError ("Illegal state, received invite from: " + + fromUsername + + " but invite status is: " + + invite.getStatus ().getType ()); + + // Already accepted/rejected the invite. + // Need to report. + return; + + } + + final Invite finvite = invite; + + if (invite.getStatus () == Invite.Status.pending) + { + + // Create a new holding editor. + EditorEditor ed = new EditorEditor (); + ed.setEmail (invite.getFromEmail ()); + ed.setTheirPublicKey (invite.getFromPublicKey ()); + + ed.setMessagingUsername (invite.getFromMessagingUsername ()); + ed.setServiceName (invite.getFromServiceName ()); + + try + { + + _this.processMessageForEditor (ed, + message); + + } catch (Exception e) { + + Environment.logError ("Unable to process message for editor: " + + ed, + e); + + } + + } + + } + + } + + }, + null); + + } + + private void processMessageForEditor (EditorEditor ed, + Message message) + throws Exception + { + + // All messages should be encrypted. + String body = message.getBody (); + + EditorMessage mess = null; + + try + { + + mess = MessageFactory.getMessage (body, + ed, + true); + + } catch (Exception e) { + + throw new GeneralException ("Unable to convert message", + e); + + } + + this.logMessage ("<<< Received", + mess); + + boolean saveMessage = false; + + try + { + + if (this.messageProcessor == null) + { + + this.messageProcessor = new DefaultEditorMessageProcessor (); + + } + + try + { + + saveMessage = this.messageProcessor.processMessage (mess); + + } catch (Exception e) { + + throw new GeneralException ("Unable to process message: " + + mess + + ", using: " + + this.messageProcessor, + e); + + } + + } finally { + + if ((saveMessage) + && + // May have a "fake" editor so don't save. + (ed.getKey () > 0) + ) + { + + try + { + + EditorsEnvironment.addMessage (mess); + + } catch (Exception e) { + + throw new GeneralException ("Unable to save message: " + + mess, + e); + + } + + } + + } + + } + + public void processMessage (final Chat chat, + final Message message) + { + + // Check to make sure we know who this is. + final String username = this.getUsernameFromJID (message.getFrom ()); + + this.logMessage ("Received message from user: " + username); + + final EditorEditor ed = EditorsEnvironment.getEditorByMessagingUsername (username); + + final EditorsMessageHandler _this = this; + + if (ed == null) + { + + // We don't know about this editor, get any invite from them. + this.handleMessageForUnknownEditor (username, + message); + + return; + + } + + if (ed.isRejected ()) + { + + // Send an unsubscribed, this user shouldn't be contacting us. + this.sendUnsubscribed (ed); + return; + + } + + if (ed.isPrevious ()) + { + + // They are a previous editor, this shouldn't be contacting us. + this.sendUnsubscribed (ed); + return; + + } + + if (ed.getTheirPublicKey () == null) + { + + // Get the invite and their public key. + EditorsEnvironment.getInvite (ed, + new EditorsWebServiceAction () + { + + @Override + public void processResult (EditorsWebServiceResult res) + { + + Map m = (Map) res.getReturnObject (); + + if (m == null) + { + + Environment.logError ("Unable to get invite for editor: " + + ed); + + // No invite. + return; + + } + + Invite invite = null; + + try + { + + invite = Invite.createFrom (m); + + } catch (Exception e) { + + Environment.logError ("Unable to create invite from: " + + m + + " from editor: " + + ed, + e); + + return; + + } + + if (invite.getStatus () == Invite.Status.rejected) + { + + Environment.logError ("Received message from: " + + ed + + " even though associated invite is rejected."); + + return; + + } + + if (invite.getStatus () == Invite.Status.pending) + { + + Environment.logError ("Received message from: " + + ed + + " even though invite is pending."); + + return; + + } + + // We are interested in the to public key here since "we" sent the + // invite. + ed.setTheirPublicKey (invite.getToPublicKey ()); + + try + { + + EditorsEnvironment.updateEditor (ed); + + } catch (Exception e) + { + + Environment.logError ("Unable to update editor: " + + ed, + e); + + return; + + } + + // Now process the message. + try + { + + _this.processMessageForEditor (ed, + message); + + } catch (Exception e) { + + Environment.logError ("Unable to process message for editor: " + + ed, + e); + + } + + } + + }, + null); + + return; + + } + + try + { + + this.processMessageForEditor (ed, + message); + + } catch (Exception e) { + + Environment.logError ("Unable to process message for editor: " + + ed, + e); + + } + + } + + private boolean shouldShowLogin () + { + + return (EditorsEnvironment.getUserAccount () == null) + || + (EditorsEnvironment.getUserAccount ().getPassword () == null); + + } + + private void doLogin (final StringProperty loginReason, + final Runnable onLogin, + final Runnable onCancel) + { + + final EditorsMessageHandler _this = this; + + if (!this.shouldShowLogin ()) + { + + this.login (onLogin, + null); + + return; + + } + + EditorsEnvironment.goOnline (loginReason, + onLogin, + onCancel, + null); + + } + + public void logout (final Runnable onLogout) + { + + if (this.isMessageSendInProgress ()) + { + + this.logoutRequested = true; + + return; + + } + + this.logoutRequested = false; + + this.userJID = null; + this.loggedIn = false; + + final EditorsMessageHandler _this = this; + + if (_this.conn != null) + { + + try + { + + _this.conn.disconnect (); + + _this.conn = null; + + } catch (Exception e) { } + + if (onLogout != null) + { + + Environment.scheduleImmediately (onLogout); + + } + + } + + } + + public void changePassword (final String newPassword, + final Runnable onComplete, + final Runnable onCancel, + final java.util.function.Consumer onError) + { + + final EditorsMessageHandler _this = this; + + this.doLogin (getUILanguageStringProperty (editors,login,reasons,changepassword), + //"To change your password you must first login to the Editors service.", + () -> + { + + try + { + + AccountManager.getInstance (_this.conn).changePassword (newPassword); + + if (onComplete != null) + { + + Environment.scheduleImmediately (onComplete); + + } + + } catch (Exception e) { + + Environment.logError ("Unable to change password", + e); + + if (onError != null) + { + + Environment.scheduleImmediately (() -> + { + + onError.accept (e); + + }); + + return; + + } + + ComponentUtils.showErrorMessage (getUILanguageStringProperty (editors,user,changepassword,actionerror)); + //"Unable to change password, please contact Quoll Writer support for assistance."); + + } + + }, + onCancel); + + } + + public void login (final Runnable onLogin, + final java.util.function.Consumer onError) + { + + final EditorsMessageHandler _this = this; + + this.logoutRequested = false; + + if ((this.conn != null) + && + (this.conn.isConnected ())//this.loggedIn) + ) + { + + if (onLogin != null) + { + + Environment.scheduleImmediately (onLogin); + + } + + return; + + } + + Environment.scheduleImmediately (() -> + { + + try + { + + EditorAccount acc = EditorsEnvironment.getUserAccount (); + + int port = 5222; + + try + { + + port = Integer.parseInt (EditorsEnvironment.getEditorsProperty (Constants.EDITORS_SERVICE_PORT_PROPERTY_NAME)); + + } catch (Exception e) { + + // ??? + + } + + XMPPTCPConnectionConfiguration config = XMPPTCPConnectionConfiguration.builder () + .setUsernameAndPassword (acc.getMessagingUsername (), + acc.getPassword ()) + .setServiceName (JidCreate.domainBareFrom (acc.getServiceName ())) + .setConnectTimeout (10 * 1000) + .setCompressionEnabled (true) + .setSendPresence (true) + //.setDebuggerEnabled (true) + .setPort (port) + .build (); + + _this.conn = new XMPPTCPConnection (config); + + _this.conn.setUseStreamManagement (true); + _this.conn.setReplyTimeout (30 * 3000); + + try + { + + _this.conn.connect (); + + } catch (Exception e) { + + this.conn = null; + + Environment.logError ("Unable to connect to Editors service", + e); + + if (onError != null) + { + + Environment.scheduleImmediately (() -> + { + + onError.accept (e); + + }); + + } else { + + EditorsUIUtils.showLoginError (getUILanguageStringProperty (editors,login,errors,other)); + //"Unable to connect to the Editors service, please contact Quoll Writer support for assistance."); + + } + + return; + + } + + _this.userJID = _this.conn.getUser (); + + final Roster roster = Roster.getInstanceFor (_this.conn); + + roster.setSubscriptionMode (Roster.SubscriptionMode.manual); + + ChatManager chatMan = ChatManager.getInstanceFor (_this.conn); + + chatMan.addChatListener (new ChatManagerListener () + { + + public void chatCreated (Chat chat, boolean createdLocally) + { + + if (!createdLocally) + { + + chat.addMessageListener (_this); + + } + + } + + }); + + // Add a check for subscriptions. + _this.conn.addAsyncStanzaListener (new StanzaListener () + { + + public void processStanza (Stanza p) + { + + if (p instanceof Presence) + { + + Presence pp = (Presence) p; + + final Presence pre = (Presence) p; + + final String username = EditorsMessageHandler.getUsernameFromJID (pre.getFrom ()); + + final EditorEditor ed = EditorsEnvironment.getEditorByMessagingUsername (username); + + if (pre.getType () == Presence.Type.unsubscribe) + { + + // Send unsubscribe. + _this.sendPresence (Presence.Type.unsubscribed, + pre.getFrom ()); + + return; + + + } + + if (pre.getType () == Presence.Type.subscribed) + { + + } + + if (pre.getType () == Presence.Type.subscribe) + { + + if ((ed == null) + || + (ed.getEditorStatus () == EditorEditor.EditorStatus.rejected) + ) + { + + // No idea who this is, just return unsubscribed. + _this.sendPresence (Presence.Type.unsubscribed, + pre.getFrom ()); + + return; + + } + + _this.sendSubscribedToEditor (ed); + + + } + + } + + } + + }, + new StanzaFilter () + { + + public boolean accept (Stanza p) + { + + if (p instanceof Presence) + { + + return true; + + } + /* + if (super.accept (p)) + { + + Presence pp = (Presence) p; + + return true; + + } + */ + return false; + + } + + }); + + // Enable automatic reconnection. + ReconnectionManager.getInstanceFor (_this.conn).enableAutomaticReconnection (); + + try + { + + _this.conn.login (); + + } catch (Exception e) { + + this.conn = null; + + Environment.logError ("User: " + + acc.getEmail () + + " is unable to login to editors service.", + e); + + EditorsUIUtils.showLoginError (getUILanguageStringProperty (editors,login,errors,invalidcredentials)); + //"Unable to login. Please check your email and password."); + + if (onError != null) + { + + Environment.scheduleImmediately (() -> + { + + onError.accept (e); + + }); + + } + + return; + + } + + for (EditorEditor ed : EditorsEnvironment.getEditors ()) + { + + Presence p = roster.getPresence (_this.getJID (ed)); + + EditorEditor.OnlineStatus status = _this.getOnlineStatus (p); + + ed.setOnlineStatus (status); + + EditorsEnvironment.fireEditorChangedEvent (new EditorChangedEvent (ed, + EditorChangedEvent.EDITOR_CHANGED)); + + } + + roster.addRosterListener (new RosterListener () + { + + public void entriesAdded (Collection addrs) + { + + } + + public void entriesDeleted (Collection addrs) + { + + } + + public void entriesUpdated (Collection addrs) + { + + } + + public void presenceChanged (Presence p) + { + + try + { + + // Get the editor associated with the presence. + Jid jid = p.getFrom (); + + String username = EditorsMessageHandler.getUsernameFromJID (jid); + + EditorEditor ed = EditorsEnvironment.getEditorByMessagingUsername (username); + + if (ed != null) + { + + ed.setOnlineStatus (_this.getOnlineStatus (p)); + + EditorsEnvironment.fireEditorChangedEvent (new EditorChangedEvent (ed, + EditorChangedEvent.EDITOR_CHANGED)); + + } + + } catch (Exception e) { + + Environment.logError ("Unable to update editor", + e); + + } + + } + + }); + + _this.loggedIn = true; + + if (onLogin != null) + { + + Environment.scheduleImmediately (onLogin); + + } + + } catch (Exception e) { + + Environment.logError ("Unable to login", + e); + + if (onError != null) + { + + Environment.scheduleImmediately (() -> + { + + onError.accept (e); + + }); + + } else { + + EditorsUIUtils.showLoginError (getUILanguageStringProperty (editors,login,errors,other)); + //"Unable to login to the Editors service, please contact Quoll Writer support for assistance."); + + } + + } + + }); + + } +/* +TODO Remove + public void login (final ActionListener onLogin, + final ActionListener onError) + { + + final EditorsMessageHandler _this = this; + + this.logoutRequested = false; + + if (this.loggedIn) + { + + if (onLogin != null) + { + + onLogin.actionPerformed (new ActionEvent ("login", 1, "login")); + + } + + return; + + } + + new Thread (new Runnable () + { + + public void run () + { + + try + { + + EditorAccount acc = EditorsEnvironment.getUserAccount (); + + int port = 5222; + + try + { + + port = Integer.parseInt (EditorsEnvironment.getEditorsProperty (Constants.EDITORS_SERVICE_PORT_PROPERTY_NAME)); + + } catch (Exception e) { + + // ??? + + } + + XMPPTCPConnectionConfiguration config = XMPPTCPConnectionConfiguration.builder () + .setUsernameAndPassword (acc.getMessagingUsername (), + acc.getPassword ()) + .setServiceName (JidCreate.domainBareFrom (acc.getServiceName ())) + .setConnectTimeout (10 * 1000) + .setCompressionEnabled (true) + //.setDebuggerEnabled (true) + .setPort (port) + .build (); + + _this.conn = new XMPPTCPConnection (config); + + _this.conn.setUseStreamManagement (true); + _this.conn.setReplyTimeout (30 * 3000); + + try + { + + _this.conn.connect (); + + } catch (Exception e) { + + Environment.logError ("Unable to connect to Editors service", + e); + + if (onError != null) + { + + UIUtils.doLater (onError); + + } else { + + EditorsUIUtils.showLoginError (getUIString (editors,login,errors,other)); + //"Unable to connect to the Editors service, please contact Quoll Writer support for assistance."); + + } + + return; + + } + + _this.userJID = _this.conn.getUser (); + + final Roster roster = Roster.getInstanceFor (_this.conn); + + roster.setSubscriptionMode (Roster.SubscriptionMode.manual); + + ChatManager chatMan = ChatManager.getInstanceFor (_this.conn); + + chatMan.addChatListener (new ChatManagerListener () + { + + public void chatCreated (Chat chat, boolean createdLocally) + { + + if (!createdLocally) + { + + chat.addMessageListener (_this); + + } + + } + + }); + + // Add a check for subscriptions. + _this.conn.addAsyncStanzaListener (new StanzaListener () + { + + public void processStanza (Stanza p) + { + + if (p instanceof Presence) + { + + Presence pp = (Presence) p; + + final Presence pre = (Presence) p; + + final String username = EditorsMessageHandler.getUsernameFromJID (pre.getFrom ()); + + final EditorEditor ed = EditorsEnvironment.getEditorByMessagingUsername (username); + + if (pre.getType () == Presence.Type.unsubscribe) + { + + // Send unsubscribe. + _this.sendPresence (Presence.Type.unsubscribed, + pre.getFrom ()); + + return; + + + } + + if (pre.getType () == Presence.Type.subscribed) + { + + } + + if (pre.getType () == Presence.Type.subscribe) + { + + if ((ed == null) + || + (ed.getEditorStatus () == EditorEditor.EditorStatus.rejected) + ) + { + + // No idea who this is, just return unsubscribed. + _this.sendPresence (Presence.Type.unsubscribed, + pre.getFrom ()); + + return; + + } + + _this.sendSubscribedToEditor (ed); + + + } + + } + + } + + }, + new StanzaFilter () + { + + public boolean accept (Stanza p) + { + + if (p instanceof Presence) + { + + return true; + + } + + //if (super.accept (p)) + //{ + + // Presence pp = (Presence) p; + + // return true; + + //} + + return false; + + } + + }); + + // Enable automatic reconnection. + ReconnectionManager.getInstanceFor (_this.conn).enableAutomaticReconnection (); + + try + { + + _this.conn.login (); + + } catch (Exception e) { + + Environment.logError ("User: " + + acc.getEmail () + + " is unable to login to editors service.", + e); + + EditorsUIUtils.showLoginError (getUIString (editors,login,errors,invalidcredentials)); + //"Unable to login. Please check your email and password."); + + if (onError != null) + { + + UIUtils.doLater (onError); + + } + + return; + + } + + for (EditorEditor ed : EditorsEnvironment.getEditors ()) + { + + Presence p = roster.getPresence (_this.getJID (ed)); + + EditorEditor.OnlineStatus status = _this.getOnlineStatus (p); + + ed.setOnlineStatus (status); + + EditorsEnvironment.fireEditorChangedEvent (new EditorChangedEvent (ed, + EditorChangedEvent.EDITOR_CHANGED)); + + } + + roster.addRosterListener (new RosterListener () + { + + public void entriesAdded (Collection addrs) + { + + } + + public void entriesDeleted (Collection addrs) + { + + } + + public void entriesUpdated (Collection addrs) + { + + } + + public void presenceChanged (Presence p) + { + + try + { + + // Get the editor associated with the presence. + Jid jid = p.getFrom (); + + String username = EditorsMessageHandler.getUsernameFromJID (jid); + + EditorEditor ed = EditorsEnvironment.getEditorByMessagingUsername (username); + + if (ed != null) + { + + ed.setOnlineStatus (_this.getOnlineStatus (p)); + + EditorsEnvironment.fireEditorChangedEvent (new EditorChangedEvent (ed, + EditorChangedEvent.EDITOR_CHANGED)); + + } + + } catch (Exception e) { + + Environment.logError ("Unable to update editor", + e); + + } + + } + + }); + + _this.loggedIn = true; + + if (onLogin != null) + { + + UIUtils.doLater (onLogin); + + } + + } catch (Exception e) { + + Environment.logError ("Unable to login", + e); + + if (onError != null) + { + + UIUtils.doLater (onError); + + } else { + + EditorsUIUtils.showLoginError (getUIString (editors,login,errors,other)); + //"Unable to login to the Editors service, please contact Quoll Writer support for assistance."); + + } + + } + + } + + }).start (); + + } +*/ + private static String getUsernameFromJID (String jid) + { + + return XmppStringUtils.unescapeLocalpart (XmppStringUtils.parseLocalpart (jid)); + + } + + private static String getUsernameFromJID (Jid jid) + { + + return jid.getLocalpartOrThrow ().asUnescapedString (); + + } + +/* +TODO OLD Remove? + private static String getJID (EditorEditor ed) + { + + return ed.getMessagingUsername () + "@" + ed.getServiceName (); + + } +*/ + + private static EntityBareJid getJID (EditorEditor ed) + throws XmppStringprepException + { + + return JidCreate.entityBareFrom (ed.getMessagingUsername () + "@" + ed.getServiceName ()); + + } + + private void sendUnsubscribed (EditorEditor ed) + { + + try + { + + BareJid jid = this.getJID (ed); + + Presence ret = new Presence (Presence.Type.unsubscribed); + ret.setTo (jid); + this.conn.sendStanza (ret); + + } catch (Exception e) { + + Environment.logError ("Unable to send unsubscribed presence to: " + + ed, + e); + + } + + } + + private void sendPresence (Presence.Type type, + Jid to) + { + + try + { + + Presence ret = new Presence (type); + ret.setTo (to); + this.conn.sendStanza (ret); + + } catch (Exception e) { + + Environment.logError ("Unable to send presence: " + + type + + " to: " + + to, + e); + + } + + } + + private void sendSubscribedToEditor (final EditorEditor ed) + { + + try + { + + BareJid jid = this.getJID (ed); + + this.sendPresence (Presence.Type.subscribed, + jid); + + } catch (Exception e) { + + Environment.logError ("Unable to send subscribed to editor: " + ed, + e); + + } + + } + + public void unsubscribeFromEditor (final EditorEditor ed) + { + + final EditorsMessageHandler _this = this; + + new Thread (() -> + { + + try + { + + BareJid jid = _this.getJID (ed); + + _this.sendPresence (Presence.Type.unsubscribe, + jid); + _this.sendPresence (Presence.Type.unsubscribed, + jid); + + } catch (Exception e) { + + Environment.logError ("Unable to unsubscribe from editor: " + ed, + e); + + } + + }).start (); + + } + + public void subscribeToEditor (final EditorEditor ed) + { + + final EditorsMessageHandler _this = this; + + new Thread (() -> + { + + try + { + + BareJid jid = _this.getJID (ed); + + Roster.getInstanceFor (_this.conn).createEntry (jid, + null, + null); + + _this.sendPresence (Presence.Type.subscribe, + jid); + + + //_this.sendMyPublicKeyToEditor (ed); + + } catch (Exception e) { + + ComponentUtils.showErrorMessage (new SimpleStringProperty ("Unable to subscribe to editor: " + ed.getEmail ())); + + Environment.logError ("Unable to subscribe to editor: " + ed, + e); + + } + + }).start (); + + } + + public void sendMessage (final StringProperty loginReason, + final EditorMessage mess, + final EditorEditor to, + final Runnable onSend, + final Runnable onLoginCancel) + { + + this.sendMessage (loginReason, + mess, + to, + onSend, + onLoginCancel, + null); + + } + + public void sendMessage (final StringProperty loginReason, + final EditorMessage mess, + final EditorEditor to, + final Runnable onSend, + final Runnable onLoginCancel, + final java.util.function.Consumer onError) + { + + final EditorsMessageHandler _this = this; + + this.logoutRequested = false; + + if (to.isPrevious ()) + { + + Environment.logError ("Trying to send message to previous editor: " + to + ", message is: " + mess); + + if (onError != null) + { + + Environment.scheduleImmediately (() -> + { + + onError.accept (new Exception ("Trying to send message to: " + to)); + + }); + + } + + return; + + } + + this.doLogin (loginReason, + () -> + { + + // TODO: Next release change this to be more in context. + //EditorsEnvironment.showMessageSendWarningIfEditorOfflineMessage (to); + + if (_this.messageSendInProgressCount.intValue () < 0) + { + + _this.messageSendInProgressCount.set (0); + + } + + _this.messageSendInProgressCount.incrementAndGet (); + + Environment.scheduleImmediately (() -> + { + + try + { + + _this.logMessage (">>> Sending", + mess); + + mess.setEditor (to); + mess.setSentByMe (true); + mess.setWhen (new Date ()); + mess.setDealtWith (true); + + Map data = mess.toMap (); + + String dmess = JSONEncoder.encode (data); + + if (dmess.length () > Constants.EDITORS_SERVICE_MAX_MESSAGE_SIZE) + { + + throw new GeneralException ("Message is too large, size is: " + + dmess.length () + + ", max is: " + Constants.EDITORS_SERVICE_MAX_MESSAGE_SIZE); + + } + + byte[] bmess = dmess.getBytes (); + + if (mess.isEncrypted ()) + { + + if (to.getTheirPublicKey () == null) + { + + throw new GeneralException ("Invalid state, no public key available for editor: " + + to + + ", unable to send message: " + + mess); + + } + + bmess = EditorsUtils.encrypt (dmess, + EditorsEnvironment.getUserAccount ().getPrivateKey (), + to.getTheirPublicKey ()); + + mess.setOriginalMessage (new String (bmess, "utf-8")); + + } else { + + mess.setOriginalMessage (dmess); + + } + + Chat c = ChatManager.getInstanceFor (_this.conn).createChat (_this.getJID (to), + _this); + + Message m = new Message (); + m.setBody (new String (bmess, "utf-8")); + m.setType (Message.Type.normal); + + c.sendMessage (m); + + // Save the message away. + EditorsEnvironment.addMessage (mess); + + if (onSend != null) + { + + Environment.scheduleImmediately (onSend); + + } + + } catch (Exception e) { + + if (onError != null) + { + + Environment.scheduleImmediately (() -> + { + + onError.accept (new Exception ("Unable to send message to " + to, + e)); + + }); + + } else { + + ComponentUtils.showErrorMessage (getUILanguageStringProperty (Arrays.asList (editors,messages,send,actionerror), + (to.getName () != null ? to.getName () : to.getEmail ()))); + //"Unable to send message to " + to.getName () + ". Please contact Quoll Writer support for assistance."); + + Environment.logError ("Unable to send message to: " + + to, + e); + + } + + } finally { + + _this.messageSendInProgressCount.decrementAndGet (); + + if ((_this.messageSendInProgressCount.intValue () <= 0) + && + (_this.logoutRequested) + ) + { + + _this.logout (null); + + } + + } + + }); + + }, + onLoginCancel); + + } + +} diff --git a/src/com/quollwriter/editors/EditorsObjectManager.java b/src/main/java/com/quollwriter/editors/EditorsObjectManager.java similarity index 82% rename from src/com/quollwriter/editors/EditorsObjectManager.java rename to src/main/java/com/quollwriter/editors/EditorsObjectManager.java index dfe2517a..a5d81524 100644 --- a/src/com/quollwriter/editors/EditorsObjectManager.java +++ b/src/main/java/com/quollwriter/editors/EditorsObjectManager.java @@ -4,7 +4,7 @@ import java.util.*; import java.sql.*; import javax.imageio.*; -import java.awt.image.*; +import javafx.embed.swing.*; import org.bouncycastle.bcpg.*; import org.bouncycastle.openpgp.*; @@ -25,7 +25,7 @@ public class EditorsObjectManager extends ObjectManager public EditorsObjectManager () { - + this.handlers.put (EditorProject.class, new EditorProjectDataHandler (this)); //this.handlers.put (EditorProject.OBJECT_TYPE, @@ -37,12 +37,12 @@ public EditorsObjectManager () this.handlers.put (EditorMessage.class, new EditorMessageDataHandler (this)); //this.handlers.put (EditorMessage.OBJECT_TYPE, - // this.handlers.get (EditorMessage.OBJECT_TYPE)); + // this.handlers.get (EditorMessage.OBJECT_TYPE)); this.handlers.put (ProjectEditor.class, new ProjectEditorDataHandler (this)); //this.handlers.put (ProjectEditor.OBJECT_TYPE, - // this.handlers.get (ProjectEditor.OBJECT_TYPE)); - + // this.handlers.get (ProjectEditor.OBJECT_TYPE)); + } public void init (File dir, @@ -61,43 +61,117 @@ public void init (File dir, } + public void deleteEditor (EditorEditor ed) + throws GeneralException + { + + Connection c = null; + + try + { + + c = this.getConnection (); + + this.deleteFromAllProjects (ed, + c); + + this.deleteAllMessagesForEditor (ed, + c); + + this.deleteObject (ed, + false, + c); + + } catch (Exception e) + { + + this.throwException (c, + "Unable to delete editor: " + ed, + e); + + } finally + { + + this.releaseConnection (c); + + } + + } + + public void deleteFromAllProjects (EditorEditor ed, + Connection c) + throws GeneralException + { + + ProjectEditorDataHandler h = (ProjectEditorDataHandler) this.handlers.get (ProjectEditor.class); + + h.deleteFromAllProjects (ed, + c); + + } + + public void deleteAllMessagesForEditor (EditorEditor ed, + Connection c) + throws GeneralException + { + + EditorMessageDataHandler h = (EditorMessageDataHandler) this.handlers.get (EditorMessage.class); + + h.deleteAllMessagesForEditor (ed, + c); + + } + + @Override + public boolean supportsLinks () + { + + return false; + + } + + @Override public void updateLinks (NamedObject d, - Set newLinks) + Connection c) { - + } - public void deleteLinks (NamedObject n, - Connection conn) + @Override + public void deleteLinks (NamedObject n, + Set remove, + Connection conn) { - + } - - public void getLinks (NamedObject d, - Project p, - Connection conn) + + @Override + public List getLinks (NamedObject d, + Connection conn) { - + + return new ArrayList<> (); + } - + public byte[] getOriginalMessage (EditorMessage em) throws Exception { - + EditorMessageDataHandler handler = (EditorMessageDataHandler) this.getHandler (EditorMessage.class); return handler.getOriginalMessage (em); - + } - + public int getUndealtWithMessageCount () throws Exception { - + EditorMessageDataHandler handler = (EditorMessageDataHandler) this.getHandler (EditorMessage.class); return handler.getUndealtWithMessageCount (); - + } // TODO: Maybe move to a builder pattern for more elegant searching/building up criteria? @@ -105,43 +179,43 @@ public Set getProjectMessages (String projId, String... messageTypes) throws Exception { - + EditorMessageDataHandler handler = (EditorMessageDataHandler) this.getHandler (EditorMessage.class); return handler.getProjectMessages (projId, messageTypes); - + } public boolean hasUserSentAProjectBefore () throws Exception { - + EditorMessageDataHandler handler = (EditorMessageDataHandler) this.getHandler (EditorMessage.class); return handler.getMessageCount (NewProjectMessage.MESSAGE_TYPE, true) > 0; } - + public Set getAllUndealtWithMessages () throws Exception { - + EditorMessageDataHandler handler = (EditorMessageDataHandler) this.getHandler (EditorMessage.class); return handler.getAllUndealtWithMessages (); - + } public Set getProjectsSentToEditor (EditorEditor ed) throws Exception { - + EditorMessageDataHandler handler = (EditorMessageDataHandler) this.getHandler (EditorMessage.class); return handler.getProjectsSentToEditor (ed); - + } public NewProjectMessage getNewProjectMessage (EditorEditor ed, @@ -149,45 +223,45 @@ public NewProjectMessage getNewProjectMessage (EditorEditor ed, boolean sentByMe) throws Exception { - + EditorMessageDataHandler handler = (EditorMessageDataHandler) this.getHandler (EditorMessage.class); return handler.getNewProjectMessage (ed, projectId, sentByMe); - + } - + public boolean hasMyPublicKeyBeenSentToEditor (EditorEditor ed) throws Exception { - + EditorMessageDataHandler handler = (EditorMessageDataHandler) this.getHandler (EditorMessage.class); - + return handler.hasMyPublicKeyBeenSentToEditor (ed); - + } - + public boolean hasSentMessageOfTypeToEditor (EditorEditor ed, String messageType) throws Exception { - + EditorMessageDataHandler handler = (EditorMessageDataHandler) this.getHandler (EditorMessage.class); - + return handler.hasSentMessageOfTypeToEditor (ed, messageType); } - + public boolean hasEditorSentInfo (EditorEditor ed) throws Exception { - + EditorMessageDataHandler handler = (EditorMessageDataHandler) this.getHandler (EditorMessage.class); - + return handler.hasEditorSentInfo (ed); - + } public void updateSchemaVersion (int newVersion, @@ -201,9 +275,9 @@ public void updateSchemaVersion (int newVersion, this.executeStatement ("UPDATE info SET schema_version = ?", params, conn); - + } - + /** * Get the current/latest version of the schema that is available. This is in contrast * to getSchemaVersion which should return the current version of the actual schema being @@ -213,15 +287,15 @@ public void updateSchemaVersion (int newVersion, */ public int getLatestSchemaVersion () { - + return EditorsEnvironment.schemaVersion; - } - + } + public int getSchemaVersion () - throws GeneralException + throws GeneralException { - + Connection c = null; try @@ -246,7 +320,7 @@ public int getSchemaVersion () this.throwException (c, "Unable to get schema version", e); - + } finally { @@ -255,14 +329,14 @@ public int getSchemaVersion () } return -1; - - + + } - + public EditorAccount getUserAccount () throws Exception { - + Connection c = null; try @@ -278,44 +352,44 @@ public EditorAccount getUserAccount () { int ind = 1; - + String em = rs.getString (ind++); - + if (em == null) { - + return null; - + } - + EditorAccount acc = new EditorAccount (); - + acc.setEmail (em); acc.setName (rs.getString (ind++)); - + InputStream av = rs.getBinaryStream (ind++); - + if (av != null) { - - acc.setAvatar (ImageIO.read (av)); - + + acc.setAvatar (SwingFXUtils.toFXImage (ImageIO.read (av), null)); + } - + acc.setLastLogin (rs.getTimestamp (ind++)); acc.setPublicKey (EditorsUtils.convertToPGPPublicKey (rs.getBytes (ind++))); - + ByteArrayInputStream bin = new ByteArrayInputStream (rs.getBytes (ind++)); - - RSASecretBCPGKey nprivKey = new RSASecretBCPGKey (new BCPGInputStream (bin)); - + + RSASecretBCPGKey nprivKey = new RSASecretBCPGKey (new BCPGInputStream (bin)); + acc.setPrivateKey (new PGPPrivateKey (1, acc.getPublicKey ().getPublicKeyPacket (), nprivKey)); - + acc.setMessagingUsername (rs.getString (ind++)); acc.setServiceName (rs.getString (ind++)); - + return acc; } @@ -326,22 +400,22 @@ public EditorAccount getUserAccount () this.throwException (c, "Unable to get user account", e); - + } finally { this.releaseConnection (c); } - + return null; - - } + + } /* public void setUserEmail (String em) throws GeneralException { - + Connection c = null; try @@ -351,11 +425,11 @@ public void setUserEmail (String em) List params = new ArrayList (); params.add (em); - + this.executeStatement ("UPDATE info SET email = ?", params, c); - + } finally { @@ -374,14 +448,14 @@ public void setUserEmail (String em) } } - - } + + } */ public String getNewMessageId (EditorEditor ed, String messageType) throws Exception { - + Connection c = null; try @@ -390,56 +464,56 @@ public String getNewMessageId (EditorEditor ed, c = this.getConnection (); EditorMessageDataHandler handler = (EditorMessageDataHandler) this.getHandler (EditorMessage.class); - + int count = 0; - + while (true) { - + if (count > 20) { - + Environment.logError ("Unable to find new message id for editor: " + ed + " and message type: " + messageType); - + return null; - + } - + String messId = ed.getId () + ":" + messageType + ":" + System.nanoTime (); - + EditorMessage mess = handler.getMessageByEditorAndId (ed, messId, c); - + if (mess == null) { - + return messId; - + } - + count++; - + } - + } catch (Exception e) { this.throwException (c, "Unable to get new message id", e); - + } finally { this.releaseConnection (c); } - + return null; - - } - + + } + public void setLastLogin (java.util.Date d) throws GeneralException { @@ -452,9 +526,9 @@ public void setLastLogin (java.util.Date d) c = this.getConnection (); List params = new ArrayList (); - + params.add (d); - + this.executeStatement ("UPDATE info SET lastlogin = ?", params, c); @@ -465,20 +539,20 @@ public void setLastLogin (java.util.Date d) this.throwException (c, "Unable to set last login", e); - + } finally { this.releaseConnection (c); } - + } - + public void setUserInformation (EditorAccount acc) throws GeneralException { - + Connection c = null; try @@ -489,78 +563,87 @@ public void setUserInformation (EditorAccount acc) List params = new ArrayList (); params.add (acc.getEmail ()); params.add (acc.getName ()); - - try + + if (acc.getAvatar () != null) { - - params.add (UIUtils.getImageBytes (acc.getAvatar ())); - - } catch (Exception e) { - - Environment.logError ("Unable to get avatar bytes", - e); - + + try + { + + params.add (UIUtils.getImageBytes (SwingFXUtils.fromFXImage (acc.getAvatar (), null))); + + } catch (Exception e) { + + Environment.logError ("Unable to get avatar bytes", + e); + + params.add (null); + + } + + } else { + params.add (null); - + } - + try { - + params.add (EditorsUtils.getPGPPublicKeyByteEncoded (acc.getPublicKey ())); - + } catch (Exception e) { - + throw new GeneralException ("Unable to encode public key", e); - + } - - params.add (((RSASecretBCPGKey) acc.getPrivateKey ().getPrivateKeyDataPacket ()).getEncoded ()); - + + params.add (((RSASecretBCPGKey) acc.getPrivateKey ().getPrivateKeyDataPacket ()).getEncoded ()); + params.add (acc.getMessagingUsername ()); params.add (acc.getServiceName ()); - + this.executeStatement ("UPDATE info SET email = ?, name = ?, avatarimage = ?, mypublickey = ?, myprivatekey = ?, messagingusername = ?, servicename = ?", params, c); - + } catch (Exception e) { this.throwException (c, "Unable to update user info", e); - + } finally { this.releaseConnection (c); } - + } - + public String getSchemaFile (String file) { - + return Constants.EDITOR_SCHEMA_DIR + file; - + } - + public String getCreateViewsFile () { - + return Constants.EDITOR_UPDATE_SCRIPTS_DIR + "/create-views.xml"; - + } - + public String getUpgradeScriptFile (int oldVersion, int newVersion) { - + return Constants.EDITOR_UPDATE_SCRIPTS_DIR + "/" + oldVersion + "-" + newVersion + ".xml"; - + } - -} \ No newline at end of file + +} diff --git a/src/com/quollwriter/editors/EditorsUtils.java b/src/main/java/com/quollwriter/editors/EditorsUtils.java similarity index 94% rename from src/com/quollwriter/editors/EditorsUtils.java rename to src/main/java/com/quollwriter/editors/EditorsUtils.java index 2c3f7f4f..547eb351 100644 --- a/src/com/quollwriter/editors/EditorsUtils.java +++ b/src/main/java/com/quollwriter/editors/EditorsUtils.java @@ -13,12 +13,8 @@ import java.util.*; import java.security.*; -import javax.swing.*; -import javax.swing.border.*; - -import com.jgoodies.forms.builder.*; -import com.jgoodies.forms.factories.*; -import com.jgoodies.forms.layout.*; +import javafx.scene.image.*; +import javafx.embed.swing.*; import org.bouncycastle.bcpg.*; import org.bouncycastle.openpgp.*; @@ -28,7 +24,7 @@ import org.bouncycastle.openpgp.operator.bc.*; import com.quollwriter.*; -import com.quollwriter.ui.*; +import com.quollwriter.ui.fx.*; import com.quollwriter.ui.events.*; import com.quollwriter.ui.components.QPopup; import com.quollwriter.ui.components.ActionAdapter; @@ -38,8 +34,8 @@ public class EditorsUtils { - public static BufferedImage getImageFromBase64EncodedString (String s) - throws Exception + public static Image getImageFromBase64EncodedString (String s) + throws Exception { if (s == null) @@ -56,6 +52,21 @@ public static BufferedImage getImageFromBase64EncodedString (String s) } + public static String getImageAsBase64EncodedString (Image im) + throws Exception + { + + if (im == null) + { + + return null; + + } + + return EditorsUtils.getImageAsBase64EncodedString (SwingFXUtils.fromFXImage (im, null)); + + } + public static String getImageAsBase64EncodedString (BufferedImage im) throws Exception { @@ -67,7 +78,7 @@ public static String getImageAsBase64EncodedString (BufferedImage im) } - byte[] bytes = UIUtils.getImageBytes (im); + byte[] bytes = UIUtils.getImageBytes (SwingFXUtils.toFXImage (im, null)); return com.quollwriter.Base64.encodeBytes (bytes); diff --git a/src/com/quollwriter/editors/EditorsWebServiceAction.java b/src/main/java/com/quollwriter/editors/EditorsWebServiceAction.java similarity index 84% rename from src/com/quollwriter/editors/EditorsWebServiceAction.java rename to src/main/java/com/quollwriter/editors/EditorsWebServiceAction.java index 0d11f229..bafb0ac6 100644 --- a/src/com/quollwriter/editors/EditorsWebServiceAction.java +++ b/src/main/java/com/quollwriter/editors/EditorsWebServiceAction.java @@ -1,8 +1,9 @@ package com.quollwriter.editors; +@FunctionalInterface public interface EditorsWebServiceAction { - + public void processResult (EditorsWebServiceResult res); - -} \ No newline at end of file + +} diff --git a/src/com/quollwriter/editors/EditorsWebServiceCall.java b/src/main/java/com/quollwriter/editors/EditorsWebServiceCall.java similarity index 100% rename from src/com/quollwriter/editors/EditorsWebServiceCall.java rename to src/main/java/com/quollwriter/editors/EditorsWebServiceCall.java diff --git a/src/com/quollwriter/editors/EditorsWebServiceHandler.java b/src/main/java/com/quollwriter/editors/EditorsWebServiceHandler.java similarity index 82% rename from src/com/quollwriter/editors/EditorsWebServiceHandler.java rename to src/main/java/com/quollwriter/editors/EditorsWebServiceHandler.java index f06ee7a2..7dcd8060 100644 --- a/src/com/quollwriter/editors/EditorsWebServiceHandler.java +++ b/src/main/java/com/quollwriter/editors/EditorsWebServiceHandler.java @@ -3,20 +3,15 @@ import java.io.*; import java.net.*; import java.util.*; +import java.util.function.*; import java.text.*; -import java.awt.event.*; import java.awt.image.*; import javax.imageio.*; -import javax.swing.*; -import javax.activation.*; -import org.jdom.*; +import javafx.beans.property.*; import org.bouncycastle.openpgp.*; -import com.gentlyweb.xml.*; -import com.gentlyweb.utils.*; - import com.quollwriter.*; import com.quollwriter.ui.*; import com.quollwriter.editors.ui.*; @@ -24,7 +19,8 @@ import com.quollwriter.data.editors.*; import static com.quollwriter.LanguageStrings.*; -import static com.quollwriter.Environment.getUIString; +import static com.quollwriter.uistrings.UILanguageStringsManager.getUILanguageStringProperty; + public class EditorsWebServiceHandler { @@ -62,13 +58,13 @@ public class FieldNames public enum Service { - accounts ("accounts", Environment.getProperty (Constants.ACCOUNTS_WEBSERVICE_URL_PROPERTY_NAME)), - authors ("authors", Environment.getProperty (Constants.AUTHORS_WEBSERVICE_URL_PROPERTY_NAME)), - projects ("projects", Environment.getProperty (Constants.PROJECTS_WEBSERVICE_URL_PROPERTY_NAME)), - login ("login", Environment.getProperty (Constants.LOGIN_WEBSERVICE_URL_PROPERTY_NAME)), - editors ("editors", Environment.getProperty (Constants.EDITORS_WEBSERVICE_URL_PROPERTY_NAME)), - sessions ("sessions", Environment.getProperty (Constants.SESSIONS_WEBSERVICE_URL_PROPERTY_NAME)), - invites ("invites", Environment.getProperty (Constants.INVITES_WEBSERVICE_URL_PROPERTY_NAME)); + accounts ("accounts", UserProperties.get (Constants.ACCOUNTS_WEBSERVICE_URL_PROPERTY_NAME)), + authors ("authors", UserProperties.get (Constants.AUTHORS_WEBSERVICE_URL_PROPERTY_NAME)), + projects ("projects", UserProperties.get (Constants.PROJECTS_WEBSERVICE_URL_PROPERTY_NAME)), + login ("login", UserProperties.get (Constants.LOGIN_WEBSERVICE_URL_PROPERTY_NAME)), + editors ("editors", UserProperties.get (Constants.EDITORS_WEBSERVICE_URL_PROPERTY_NAME)), + sessions ("sessions", UserProperties.get (Constants.SESSIONS_WEBSERVICE_URL_PROPERTY_NAME)), + invites ("invites", UserProperties.get (Constants.INVITES_WEBSERVICE_URL_PROPERTY_NAME)); private final String type; private final String url; @@ -163,7 +159,7 @@ private void displayPendingInvites (List invites) } - AbstractViewer viewer = Environment.getFocusedViewer (); + AbstractViewer viewer = null; // TODO Environment.getFocusedViewer (); for (int i = 0; i < invites.size (); i++) { @@ -313,6 +309,107 @@ public void logout () } + public void login (final Runnable onLogin, + final Consumer onError) + { + + final EditorAccount acc = EditorsEnvironment.getUserAccount (); + + if (acc.getWebServiceSessionId () != null) + { + + if (onLogin != null) + { + + Environment.schedule (onLogin, + -1, + -1); + + } + + return; + + } + + Map data = new HashMap (); + data.put ("email", + acc.getEmail ()); + data.put ("password", + acc.getPassword ()); + + final EditorsWebServiceHandler _this = this; + + this.callService (Service.sessions, + null, + data, + "POST", + null, + new EditorsWebServiceAction () + { + + public void processResult (EditorsWebServiceResult res) + { + + String sessionId = res.getReturnObjectAsString (); + + acc.setWebServiceSessionId (sessionId); + + if (sessionId == null) + { + + // Oops? + Environment.logError ("No session id returned from sessions service"); + + EditorsUIUtils.showLoginError (getUILanguageStringProperty (editors,login,errors,other)); + //"Sorry an unexpected error has occurred with
    the Editors service, please try again later."); + + return; + + } + + if (onLogin != null) + { + + Environment.schedule (onLogin, + -1, + -1); + + } + + } + + }, + new EditorsWebServiceAction () + { + + public void processResult (EditorsWebServiceResult res) + { + + Environment.logError ("Unable to login to editors service (qw website): " + res); + + if (onError != null) + { + + Environment.scheduleImmediately (() -> + { + + onError.accept (new Exception ("Unable to login.")); + + }); + + } else { + + EditorsUIUtils.showLoginError (res); + + } + + } + + }); + + } +/* +TODO Remove public void login (final ActionListener onLogin, final ActionListener onError) { @@ -403,7 +500,7 @@ public void processResult (EditorsWebServiceResult res) }); } - +*/ private void callService (final Service service, final String id, final Object data, @@ -559,7 +656,7 @@ private void createProject (final String name, final Set genres, final String expectations, final EditorProject.WordCountLength wordCountLength, - final ActionListener onComplete) + final Runnable onComplete) throws Exception { @@ -579,73 +676,68 @@ private void createProject (final String name, expectations, wordCountLength); - this.doLogin ("Before creating a {project} you must login to the Editors service.", - new ActionListener () + this.doLogin (new SimpleStringProperty ("Before creating a {project} you must login to the Editors service."), + () -> { - public void actionPerformed (ActionEvent ev) + if (EditorsEnvironment.getUserAccount ().getAuthor () == null) { - if (EditorsEnvironment.getUserAccount ().getAuthor () == null) - { + throw new IllegalStateException ("Unable to create project, no author available."); - throw new IllegalStateException ("Unable to create project, no author available."); + } - } + _this.callService (Service.projects, + null, + data, + "POST", + new EditorsWebServiceAction () + { - _this.callService (Service.projects, - null, - data, - "POST", - new EditorsWebServiceAction () - { - - public void processResult (EditorsWebServiceResult res) - { + public void processResult (EditorsWebServiceResult res) + { - ep.setId (res.getReturnObjectAsString ()); + ep.setId (res.getReturnObjectAsString ()); - _this.fillProject (ep, - name, - desc, - genres, - expectations, - wordCountLength); + _this.fillProject (ep, + name, + desc, + genres, + expectations, + wordCountLength); - try - { + try + { /* - _this.saveProjectToLocal (ep, - viewer); + _this.saveProjectToLocal (ep, + viewer); */ - } catch (Exception e) { - - Environment.logError ("Unable to save project to local", - e); + } catch (Exception e) { - } + Environment.logError ("Unable to save project to local", + e); - //viewer.getProject ().setEditorProject (ep); + } - if (onComplete != null) - { + //viewer.getProject ().setEditorProject (ep); - onComplete.actionPerformed (new ActionEvent ("done", 1, "done")); + if (onComplete != null) + { - } + Environment.scheduleImmediately (onComplete); } - }, - new EditorsWebServiceAction () - { + } - public void processResult (EditorsWebServiceResult res) - {} + }, + new EditorsWebServiceAction () + { - }); + public void processResult (EditorsWebServiceResult res) + {} - } + }); }, null); @@ -1644,36 +1736,30 @@ public void changePassword (final String newPassword, final EditorsWebServiceHandler _this = this; - this.doLogin (getUIString (editors,login,reasons,changepassword), + this.doLogin (getUILanguageStringProperty (editors,login,reasons,changepassword), //"To update your password you must first login to the Editors service.", - new ActionListener () + () -> { - @Override - public void actionPerformed (ActionEvent ev) - { + Map data = new HashMap (); + data.put (FieldNames.password, + newPassword); - Map data = new HashMap (); - data.put (FieldNames.password, - newPassword); - - _this.callService (Service.accounts, - null, - data, - "PUT", - onComplete, - onError); - - } + _this.callService (Service.accounts, + null, + data, + "PUT", + onComplete, + onError); }, null); } - private void doLogin (final String loginReason, - final ActionListener onLogin, - final ActionListener onCancel) + private void doLogin (final StringProperty loginReason, + final Runnable onLogin, + final Runnable onCancel) { final EditorsWebServiceHandler _this = this; @@ -1751,26 +1837,21 @@ public void getInvite (final String from, this.doLogin (null, // This method is ONLY called when the user is already logged in thus the message is never displayed. //"To get the invite for " + from + " you must first login to the Editors service.", - new ActionListener () + () -> { - public void actionPerformed (ActionEvent ev) - { + Map data = null; - Map data = null; - - data = new HashMap (); - data.put (FieldNames.received, - true); - - _this.callService (Service.invites, - from, - data, - "GET", - onComplete, - onError); + data = new HashMap (); + data.put (FieldNames.received, + true); - } + _this.callService (Service.invites, + from, + data, + "GET", + onComplete, + onError); }, null); @@ -1810,7 +1891,7 @@ public void actionPerformed (ActionEvent ev) } */ - public void getPendingInvites (final String loginReason, + public void getPendingInvites (final StringProperty loginReason, final EditorsWebServiceAction onComplete, final EditorsWebServiceAction onError) { @@ -1818,28 +1899,23 @@ public void getPendingInvites (final String loginReason, final EditorsWebServiceHandler _this = this; this.doLogin (loginReason, - new ActionListener () + () -> { - public void actionPerformed (ActionEvent ev) - { - - Map data = new HashMap (); - data.put (FieldNames.status, - "pending"); - data.put (FieldNames.beforeAccountCreation, - true); - data.put (FieldNames.received, - true); - - _this.callService (Service.invites, - null, - data, - "GET", - onComplete, - onError); + Map data = new HashMap (); + data.put (FieldNames.status, + "pending"); + data.put (FieldNames.beforeAccountCreation, + true); + data.put (FieldNames.received, + true); - } + _this.callService (Service.invites, + null, + data, + "GET", + onComplete, + onError); }, null); @@ -1854,22 +1930,17 @@ public void deleteInvite (final EditorEditor ed, // Can only do this when logged in. final EditorsWebServiceHandler _this = this; - this.doLogin (getUIString (editors,login,reasons,deleteinvite), + this.doLogin (getUILanguageStringProperty (editors,login,reasons,deleteinvite), //"To delete an invite you must first login to the Editors service.", - new ActionListener () + () -> { - public void actionPerformed (ActionEvent ev) - { - - _this.callService (Service.invites, - ed.getEmail (), - null, - "DELETE", - onComplete, - onError); - - } + _this.callService (Service.invites, + ed.getEmail (), + null, + "DELETE", + onComplete, + onError); }, null); @@ -1885,26 +1956,21 @@ public void updateInvite (final String toEmail, // Can only do this when logged in. final EditorsWebServiceHandler _this = this; - this.doLogin (getUIString (editors,login,reasons,updateinvite), + this.doLogin (getUILanguageStringProperty (editors,login,reasons,updateinvite), //"To update an invite you must first login to the Editors service.", - new ActionListener () + () -> { - public void actionPerformed (ActionEvent ev) - { - - Map data = new HashMap (); - data.put (FieldNames.status, - newStatus.getType ()); - - _this.callService (Service.invites, - toEmail, - data, - "PUT", - onComplete, - onError); + Map data = new HashMap (); + data.put (FieldNames.status, + newStatus.getType ()); - } + _this.callService (Service.invites, + toEmail, + data, + "PUT", + onComplete, + onError); }, null); @@ -1918,26 +1984,21 @@ public void sendInvite (final String toEmail, final EditorsWebServiceHandler _this = this; - this.doLogin (getUIString (editors,login,reasons,sendinvite), + this.doLogin (getUILanguageStringProperty (editors,login,reasons,sendinvite), //"To send an invite to " + toEmail + " you must first login to the Editors service.", - new ActionListener () + () -> { - public void actionPerformed (ActionEvent ev) - { - - Map data = new HashMap (); - data.put (FieldNames.email, - toEmail); + Map data = new HashMap (); + data.put (FieldNames.email, + toEmail); - _this.callService (Service.invites, - null, - data, - "POST", - onComplete, - onError); - - } + _this.callService (Service.invites, + null, + data, + "POST", + onComplete, + onError); }, null); @@ -1957,22 +2018,17 @@ public void deleteAccount (final EditorsWebServiceAction onComplete, final EditorsWebServiceHandler _this = this; - this.doLogin (getUIString (editors,login,reasons,deleteaccount), + this.doLogin (getUILanguageStringProperty (editors,login,reasons,deleteaccount), //"To delete your account you must first login to the Editors service.", - new ActionListener () + () -> { - public void actionPerformed (ActionEvent ev) - { - - _this.callService (Service.accounts, - null, - null, - "DELETE", - onComplete, - onError); - - } + _this.callService (Service.accounts, + null, + null, + "DELETE", + onComplete, + onError); }, null); diff --git a/src/com/quollwriter/editors/EditorsWebServiceResult.java b/src/main/java/com/quollwriter/editors/EditorsWebServiceResult.java similarity index 100% rename from src/com/quollwriter/editors/EditorsWebServiceResult.java rename to src/main/java/com/quollwriter/editors/EditorsWebServiceResult.java diff --git a/src/com/quollwriter/editors/ProjectEditorChangedEvent.java b/src/main/java/com/quollwriter/editors/ProjectEditorChangedEvent.java similarity index 100% rename from src/com/quollwriter/editors/ProjectEditorChangedEvent.java rename to src/main/java/com/quollwriter/editors/ProjectEditorChangedEvent.java diff --git a/src/com/quollwriter/editors/ProjectEditorChangedListener.java b/src/main/java/com/quollwriter/editors/ProjectEditorChangedListener.java similarity index 100% rename from src/com/quollwriter/editors/ProjectEditorChangedListener.java rename to src/main/java/com/quollwriter/editors/ProjectEditorChangedListener.java diff --git a/src/com/quollwriter/editors/UserOnlineStatusEvent.java b/src/main/java/com/quollwriter/editors/UserOnlineStatusEvent.java similarity index 100% rename from src/com/quollwriter/editors/UserOnlineStatusEvent.java rename to src/main/java/com/quollwriter/editors/UserOnlineStatusEvent.java diff --git a/src/com/quollwriter/editors/UserOnlineStatusListener.java b/src/main/java/com/quollwriter/editors/UserOnlineStatusListener.java similarity index 100% rename from src/com/quollwriter/editors/UserOnlineStatusListener.java rename to src/main/java/com/quollwriter/editors/UserOnlineStatusListener.java diff --git a/src/com/quollwriter/editors/messages/AbstractProjectMessage.java b/src/main/java/com/quollwriter/editors/messages/AbstractProjectMessage.java similarity index 86% rename from src/com/quollwriter/editors/messages/AbstractProjectMessage.java rename to src/main/java/com/quollwriter/editors/messages/AbstractProjectMessage.java index 26f3c821..204f4cef 100644 --- a/src/com/quollwriter/editors/messages/AbstractProjectMessage.java +++ b/src/main/java/com/quollwriter/editors/messages/AbstractProjectMessage.java @@ -18,12 +18,12 @@ public abstract class AbstractProjectMessage extends EditorMessage protected ProjectVersion projVer = null; //protected String versionName = null; //protected String versionId = null; - + public AbstractProjectMessage () { - + } - + public AbstractProjectMessage (Project project, Set chapters, ProjectVersion pv, @@ -31,31 +31,31 @@ public AbstractProjectMessage (Project project, //String notes, EditorEditor editor) { - + if ((chapters == null) || (chapters.size () == 0) ) { - + throw new IllegalArgumentException ("Expected at least 1 chapter."); - + } - + if (pv == null) { - + throw new IllegalArgumentException ("Expected project version."); - + } - + if (pv.getId () == null) { - + throw new IllegalArgumentException ("Project version must have an id."); - + } - + this.setEditor (editor); this.setForProjectName (project.getName ()); this.setForProjectId (project.getId ()); @@ -64,30 +64,30 @@ public AbstractProjectMessage (Project project, this.chapters = chapters; //this.notes = notes; //this.dueBy = dueBy; - + int wc = 0; - + for (Chapter c : chapters) { - + wc += TextUtilities.getWordCount (c.getChapterText ()); - + } - + this.wordCount = wc; - + } public abstract Project createProject () throws Exception; - + @Override public void fillToStringProperties (Map props) { - + super.fillToStringProperties (props); - + this.addToStringProperties (props, "chapters", this.chapters.size ()); @@ -106,9 +106,9 @@ public void fillToStringProperties (Map props) this.addToStringProperties (props, "notes", this.projVer.getDescription ()); - + } - + /** * Will fill up the data map with the information in this object that is encoded and sent in the message to the editor. * @@ -118,167 +118,167 @@ public void fillToStringProperties (Map props) protected void fillMap (Map data) throws Exception { - + if (this.getForProjectId () == null) { - + throw new GeneralException ("No project id set"); - + } - + if ((this.chapters == null) || (this.chapters.size () == 0) ) { - + throw new GeneralException ("No chapters set"); - + } - + data.put (MessageFieldNames.name, this.getForProjectName ()); - + if ((this.projVer.getDescriptionText () != null) && (this.projVer.getDescriptionText ().trim ().length () > 0) ) { - + data.put (MessageFieldNames.notes, this.projVer.getDescriptionText ().trim ()); - + } - + if (this.projVer.getDueDate () != null) { - + data.put (MessageFieldNames.dueby, this.projVer.getDueDate ().getTime ()); - + } - + if (this.projVer.getName () != null) { - + data.put (MessageFieldNames.versionname, this.projVer.getName ()); - + } - + data.put (MessageFieldNames.versionid, this.projVer.getId ()); - - List clist = new ArrayList (); - + + List clist = new ArrayList<> (); + data.put (MessageFieldNames.chapters, clist); - + // Add the chapters. for (Chapter c : this.chapters) { - + clist.add (TypeEncoder.encode (c)); - - } - + + } + } - + public String getMessage () throws GeneralException { - + // Return a summary, should be json. - Map m = new HashMap (); + Map m = new HashMap<> (); m.put (MessageFieldNames.name, this.getForProjectName ()); m.put (MessageFieldNames.projectid, this.getForProjectId ()); m.put (MessageFieldNames.chaptercount, this.chapters.size ()); - + if (this.projVer.getDescriptionText () != null) { - + m.put (MessageFieldNames.notes, this.projVer.getDescriptionText ()); } - + if (this.projVer.getDueDate () != null) { - + m.put (MessageFieldNames.dueby, this.projVer.getDueDate ().getTime ()); - + } - + m.put (MessageFieldNames.wordcount, this.wordCount); - + if (this.projVer.getName () != null) { - + m.put (MessageFieldNames.versionname, this.projVer.getName ()); - + } - + m.put (MessageFieldNames.versionid, this.projVer.getId ()); - + // Get a summary of each chapter. List chs = new ArrayList (); - + for (Chapter c : this.chapters) { - + Map cm = new HashMap (); chs.add (cm); - + cm.put (MessageFieldNames.name, c.getName ()); cm.put (MessageFieldNames.chapterid, c.getId ()); cm.put (MessageFieldNames.version, c.getVersion ()); - + } - + m.put (MessageFieldNames.chapters, chs); - + this.fillMessageMap (m); - + try { - + return JSONEncoder.encode (m); - + } catch (Exception e) { - + throw new GeneralException ("Unable to json encode message: " + m, e); - + } - - } - + + } + public void setMessage (String m) throws GeneralException { - + // This is a summary of what was sent/received. Map data = (Map) JSONDecoder.decode (m); - + this.fillFromMessageMap (data); - + this.setForProjectName (this.getString (MessageFieldNames.name, data)); this.setForProjectId (this.getString (MessageFieldNames.projectid, data)); - + ProjectVersion pv = new ProjectVersion (); pv.setDescription (new StringWithMarkup (this.getString (MessageFieldNames.notes, data, @@ -289,41 +289,41 @@ public void setMessage (String m) pv.setDueDate (this.getDate (MessageFieldNames.dueby, data, false)); - + pv.setId (this.getString (MessageFieldNames.versionid, data)); - + this.projVer = pv; - + this.wordCount = this.getInt (MessageFieldNames.wordcount, data); - + Set chaps = null; - + List chs = (List) data.get (MessageFieldNames.chapters); - + if (chs != null) { - + chaps = new LinkedHashSet (); - + for (int i = 0; i < chs.size (); i++) { - + Map cm = (Map) chs.get (i); Chapter c = TypeEncoder.decodeToChapter (cm); - + chaps.add (c); - + } - + } - + this.chapters = chaps; - + } - + /** * Used when converting the data in the message into a summary string. * Called from: {@link getMessage()}. @@ -332,7 +332,7 @@ public void setMessage (String m) */ protected abstract void fillMessageMap (Map m) throws GeneralException; - + /** * Used to extract data from the passed in map and init this object. The data has been taken * from a summary string generated by {@link getMessage()}. @@ -342,171 +342,171 @@ protected abstract void fillMessageMap (Map m) */ protected abstract void fillFromMessageMap (Map m) throws GeneralException; - + public ProjectVersion getProjectVersion () { - + return this.projVer; - + } - + public Set getChaptersWithText () throws Exception { - + Map data = EditorsEnvironment.getOriginalMessageAsMap (this); Object chaps = this.checkTypeAndNotNull (MessageFieldNames.chapters, data, List.class); - + List chapsL = (List) chaps; - + if (chapsL.size () == 0) { - + throw new GeneralException ("Expected to find at least 1 chapter."); - + } - + int wc = 0; - + Set chapsS = new LinkedHashSet (); - + for (int i = 0; i < chapsL.size (); i++) { - + Object co = chapsL.get (i); - + if (!(co instanceof Map)) { - + throw new GeneralException ("Expected chapter data for index: " + i + " to by a map, has type: " + co.getClass ().getName ()); - + } - + Map cm = (Map) co; Chapter c = TypeEncoder.decodeToChapter (cm); - + chapsS.add (c); - + } - + return chapsS; } - + public Set getChapters () { - + return this.chapters; - + } - + public int getWordCount () { - + return this.wordCount; - + } - + public boolean isEncrypted () { - + return true; - + } - + protected void doInit (Map data, EditorEditor from) throws Exception { - + this.setForProjectName (this.getString (MessageFieldNames.name, data)); - + String notes = this.getString (MessageFieldNames.notes, data, false); - - ProjectVersion pv = new ProjectVersion (); - + + ProjectVersion pv = new ProjectVersion (); + if (notes != null) { - + notes = notes.trim (); - + if (notes.length () > 5000) { - + throw new GeneralException ("Notes is too long, max length is: 5000, is: " + notes.length ()); - + } - + pv.setDescription (new StringWithMarkup (notes)); - + } - + pv.setId (this.getString (MessageFieldNames.versionid, data)); pv.setName (this.getString (MessageFieldNames.versionname, - data, + data, false)); pv.setDueDate (this.getDate (MessageFieldNames.dueby, data, false)); this.projVer = pv; - + Object chaps = this.checkTypeAndNotNull (MessageFieldNames.chapters, data, List.class); - + List chapsL = (List) chaps; - + if (chapsL.size () == 0) { - + throw new GeneralException ("Expected to find at least 1 chapter."); - + } - + int wc = 0; - + Set chapsS = new LinkedHashSet (); - + for (int i = 0; i < chapsL.size (); i++) { - + Object co = chapsL.get (i); - + if (!(co instanceof Map)) { - + throw new GeneralException ("Expected chapter data for index: " + i + " to by a map, has type: " + co.getClass ().getName ()); - + } - + Map cm = (Map) co; Chapter c = TypeEncoder.decodeToChapter (cm); wc += TextUtilities.getWordCount (c.getChapterText ()); - + chapsS.add (c); - + } - + this.wordCount = wc; this.chapters = chapsS; - + } - -} \ No newline at end of file + +} diff --git a/src/com/quollwriter/editors/messages/DefaultEditorMessageFilter.java b/src/main/java/com/quollwriter/editors/messages/DefaultEditorMessageFilter.java similarity index 100% rename from src/com/quollwriter/editors/messages/DefaultEditorMessageFilter.java rename to src/main/java/com/quollwriter/editors/messages/DefaultEditorMessageFilter.java diff --git a/src/com/quollwriter/editors/messages/EditorChatMessage.java b/src/main/java/com/quollwriter/editors/messages/EditorChatMessage.java similarity index 100% rename from src/com/quollwriter/editors/messages/EditorChatMessage.java rename to src/main/java/com/quollwriter/editors/messages/EditorChatMessage.java diff --git a/src/com/quollwriter/editors/messages/EditorInfoMessage.java b/src/main/java/com/quollwriter/editors/messages/EditorInfoMessage.java similarity index 82% rename from src/com/quollwriter/editors/messages/EditorInfoMessage.java rename to src/main/java/com/quollwriter/editors/messages/EditorInfoMessage.java index f20aba6b..6e7d1925 100644 --- a/src/com/quollwriter/editors/messages/EditorInfoMessage.java +++ b/src/main/java/com/quollwriter/editors/messages/EditorInfoMessage.java @@ -1,7 +1,8 @@ package com.quollwriter.editors.messages; import java.util.*; -import java.awt.image.*; + +import javafx.scene.image.*; import com.quollwriter.*; import com.quollwriter.editors.*; @@ -9,31 +10,31 @@ public class EditorInfoMessage extends EditorMessage { - + public static final String MESSAGE_TYPE = "editor-information"; - + private String name = null; - private BufferedImage avatar = null; - + private Image avatar = null; + public EditorInfoMessage () { - + } - + public EditorInfoMessage (EditorAccount acc) { - + this.name = acc.getName (); this.avatar = acc.getAvatar (); - + } - + @Override public void fillToStringProperties (Map props) { - + super.fillToStringProperties (props); - + this.addToStringProperties (props, "name", this.name); @@ -42,172 +43,172 @@ public void fillToStringProperties (Map props) (this.avatar != null)); } - + protected void fillMap (Map data) throws Exception { - + if (this.name != null) - { - + { + data.put (MessageFieldNames.name, this.name); - + } - + if (this.avatar != null) { data.put (MessageFieldNames.avatar, EditorsUtils.getImageAsBase64EncodedString (this.avatar)); - + } - + } - public BufferedImage getAvatar () + public Image getAvatar () { - + return this.avatar; - + } - + public String getName () { - + return this.name; - + } - + public String getMessage () throws GeneralException { - + Map m = new HashMap (); - + if (this.name != null) { - + m.put (MessageFieldNames.name, this.name); } - + if (this.avatar != null) { try { - + m.put (MessageFieldNames.avatar, EditorsUtils.getImageAsBase64EncodedString (this.avatar)); - + } catch (Exception e) { - + throw new GeneralException ("Unable to convert avatar image to a base64 string", e); - + } - + } try { - + return JSONEncoder.encode (m); - + } catch (Exception e) { - + throw new GeneralException ("Unable to json encode message: " + m, e); - + } - + } - + public void setMessage (String s) throws GeneralException { - + // This is a summary of what was sent/received. Map data = (Map) JSONDecoder.decode (s); - + String n = this.getString (MessageFieldNames.name, data, false); - + if (n != null) { - + this.name = n; - + } - + String avatar = this.getString (MessageFieldNames.avatar, data, false); - + if (avatar != null) { - + try { this.avatar = EditorsUtils.getImageFromBase64EncodedString (avatar); - + } catch (Exception e) { - + throw new GeneralException ("Unable to convert string to an avatar image", e); - + } - + } - + } - + protected void doInit (Map data, EditorEditor from) throws Exception { - + String n = this.getString (MessageFieldNames.name, data, false); - + if (n != null) { - + this.name = n; - + } - + String avatar = this.getString (MessageFieldNames.avatar, data, false); - + if (avatar != null) { - + this.avatar = EditorsUtils.getImageFromBase64EncodedString (avatar); - + } - + } - + public boolean isEncrypted () { - + return true; - + } - + public String getMessageType () { - + return MESSAGE_TYPE; - + } - -} \ No newline at end of file + +} diff --git a/src/com/quollwriter/editors/messages/EditorMessage.java b/src/main/java/com/quollwriter/editors/messages/EditorMessage.java similarity index 91% rename from src/com/quollwriter/editors/messages/EditorMessage.java rename to src/main/java/com/quollwriter/editors/messages/EditorMessage.java index f3551566..1e970765 100644 --- a/src/com/quollwriter/editors/messages/EditorMessage.java +++ b/src/main/java/com/quollwriter/editors/messages/EditorMessage.java @@ -2,13 +2,15 @@ import java.util.*; +import javafx.beans.property.*; + import com.quollwriter.*; import com.quollwriter.data.*; import com.quollwriter.data.editors.*; import com.quollwriter.editors.*; import static com.quollwriter.LanguageStrings.*; -import static com.quollwriter.Environment.getUIString; +import static com.quollwriter.uistrings.UILanguageStringsManager.getUILanguageStringProperty; /** * The base class for all messages sent between editors. @@ -46,20 +48,27 @@ public abstract class EditorMessage extends DataObject protected EditorEditor editor = null; private String forProjectId = null; - private String forProjectName = null; + private StringProperty forProjectNameProp = new SimpleStringProperty (); private String origMessage = null; private boolean sentByMe = false; private Date when = new Date (); private String messageId = null; private boolean wantsAck = false; private long ackKey = -1; - private boolean dealtWith = false; + private BooleanProperty dealtWithProp = new SimpleBooleanProperty (false); public EditorMessage () { super (OBJECT_TYPE); + this.dealtWithProp.addListener ((pr, oldv, newv) -> + { + + this.editor.messageUpdated (); + + }); + } public abstract String getMessageType (); @@ -82,7 +91,7 @@ public void fillToStringProperties (Map props) this.messageId); this.addToStringProperties (props, "dealtWith", - this.dealtWith); + this.dealtWithProp.getValue ()); this.addToStringProperties (props, "sentByMe", this.sentByMe); @@ -109,19 +118,26 @@ public String toString () } + public BooleanProperty dealtWithProperty () + { + + return this.dealtWithProp; + + } + public boolean isDealtWith () { - return this.dealtWith; + return this.dealtWithProp.getValue (); } public void setDealtWith (boolean v) { - boolean oldV = this.dealtWith; + boolean oldV = this.dealtWithProp.getValue (); - this.dealtWith = v; + this.dealtWithProp.setValue (v); this.firePropertyChangedEvent (EditorMessage.DEALT_WITH, oldV, @@ -201,22 +217,11 @@ public String getMessageId () public void setForProjectName (String n) { - this.forProjectName = n; + this.forProjectNameProp.setValue (n); } - /** - * Since so many messages relate to projects we place this call here for convenience. - * If there is a forProjectId value then it will be used to lookup the project name via: - * {@link Environment.getProjectById(String)} to ensure we are using the current name. - * If the project no longer exists then return the projectName specified by the message, - * if that value isn't available then return "Unknown {Project}". - * - * If the forProjectId is not specified then null is returned. - * - * @return The project name. - */ - public String getForProjectName () + public StringProperty forProjectNameProperty () { if (this.forProjectId == null) @@ -226,7 +231,7 @@ public String getForProjectName () } - String projName = this.forProjectName; + StringProperty projName = this.forProjectNameProp; try { @@ -237,7 +242,7 @@ public String getForProjectName () if (proj != null) { - projName = proj.getName (); + projName = proj.nameProperty (); } @@ -249,10 +254,10 @@ public String getForProjectName () } - if (projName == null) + if (projName.getValue () == null) { - projName = getUIString (editors,messages,unknownproject); + projName = getUILanguageStringProperty (editors,messages,unknownproject); //"Unknown {Project}"; } @@ -261,6 +266,24 @@ public String getForProjectName () } + /** + * Since so many messages relate to projects we place this call here for convenience. + * If there is a forProjectId value then it will be used to lookup the project name via: + * {@link Environment.getProjectById(String)} to ensure we are using the current name. + * If the project no longer exists then return the projectName specified by the message, + * if that value isn't available then return "Unknown {Project}". + * + * If the forProjectId is not specified then null is returned. + * + * @return The project name. + */ + public String getForProjectName () + { + + return this.forProjectNameProperty ().getValue (); + + } + public String getForProjectId () { diff --git a/src/com/quollwriter/editors/messages/EditorMessageFilter.java b/src/main/java/com/quollwriter/editors/messages/EditorMessageFilter.java similarity index 83% rename from src/com/quollwriter/editors/messages/EditorMessageFilter.java rename to src/main/java/com/quollwriter/editors/messages/EditorMessageFilter.java index a595b34c..0d1f4896 100644 --- a/src/com/quollwriter/editors/messages/EditorMessageFilter.java +++ b/src/main/java/com/quollwriter/editors/messages/EditorMessageFilter.java @@ -1,8 +1,9 @@ package com.quollwriter.editors.messages; +@FunctionalInterface public interface EditorMessageFilter { - + public boolean accept (EditorMessage m); - -} \ No newline at end of file + +} diff --git a/src/com/quollwriter/editors/messages/EditorRemovedMessage.java b/src/main/java/com/quollwriter/editors/messages/EditorRemovedMessage.java similarity index 100% rename from src/com/quollwriter/editors/messages/EditorRemovedMessage.java rename to src/main/java/com/quollwriter/editors/messages/EditorRemovedMessage.java diff --git a/src/com/quollwriter/editors/messages/ErrorMessage.java b/src/main/java/com/quollwriter/editors/messages/ErrorMessage.java similarity index 100% rename from src/com/quollwriter/editors/messages/ErrorMessage.java rename to src/main/java/com/quollwriter/editors/messages/ErrorMessage.java diff --git a/src/com/quollwriter/editors/messages/InteractionMessage.java b/src/main/java/com/quollwriter/editors/messages/InteractionMessage.java similarity index 100% rename from src/com/quollwriter/editors/messages/InteractionMessage.java rename to src/main/java/com/quollwriter/editors/messages/InteractionMessage.java diff --git a/src/com/quollwriter/editors/messages/InviteMessage.java b/src/main/java/com/quollwriter/editors/messages/InviteMessage.java similarity index 80% rename from src/com/quollwriter/editors/messages/InviteMessage.java rename to src/main/java/com/quollwriter/editors/messages/InviteMessage.java index 36a4fd6a..feec6bd6 100644 --- a/src/com/quollwriter/editors/messages/InviteMessage.java +++ b/src/main/java/com/quollwriter/editors/messages/InviteMessage.java @@ -1,7 +1,8 @@ package com.quollwriter.editors.messages; import java.util.*; -import java.awt.image.*; + +import javafx.scene.image.*; import com.quollwriter.*; import com.quollwriter.editors.*; @@ -10,31 +11,31 @@ //@Message(type=InviteMessage.MESSAGE_TYPE) public class InviteMessage extends EditorMessage { - + public static final String MESSAGE_TYPE = "invite"; - + private String editorName = null; - private BufferedImage editorAvatar = null; - + private Image editorAvatar = null; + public InviteMessage () { - + } - + public InviteMessage (EditorAccount acc) { - + this.editorName = acc.getName (); this.editorAvatar = acc.getAvatar (); - + } - + @Override public void fillToStringProperties (Map props) { - + super.fillToStringProperties (props); - + this.addToStringProperties (props, "editorName", this.editorName); @@ -43,110 +44,110 @@ public void fillToStringProperties (Map props) (this.editorAvatar != null)); } - + protected void fillMap (Map data) throws Exception { - + Map edInf = new HashMap (); - + data.put (MessageFieldNames.editorinformation, edInf); - + if (this.editorName != null) { - + edInf.put (MessageFieldNames.name, this.editorName); } - + if (this.editorAvatar != null) { - + edInf.put (MessageFieldNames.avatar, EditorsUtils.getImageAsBase64EncodedString (this.editorAvatar)); - + } - + } - public BufferedImage getEditorAvatar () + public Image getEditorAvatar () { - + return this.editorAvatar; - + } - + public String getEditorName () { - + return this.editorName; - + } - + public String getMessage () { - + return null; - + } - + public void setMessage (String s) { - + // Nothing to do. No need to construct. - + } - + protected void doInit (Map data, EditorEditor from) throws Exception { - + Map edInf = (Map) data.get (MessageFieldNames.editorinformation); - + if (edInf != null) { - + String n = this.getString (MessageFieldNames.name, edInf, false); - + if (n != null) { - + this.editorName = n; - + } - + String avatar = this.getString (MessageFieldNames.avatar, edInf, false); - + if (avatar != null) { - + this.editorAvatar = EditorsUtils.getImageFromBase64EncodedString (avatar); - + } - + } - + } - + public boolean isEncrypted () { - + return true; - + } - + public String getMessageType () { - + return MESSAGE_TYPE; - + } - -} \ No newline at end of file + +} diff --git a/src/com/quollwriter/editors/messages/InviteResponseMessage.java b/src/main/java/com/quollwriter/editors/messages/InviteResponseMessage.java similarity index 81% rename from src/com/quollwriter/editors/messages/InviteResponseMessage.java rename to src/main/java/com/quollwriter/editors/messages/InviteResponseMessage.java index 6ae40705..d753b381 100644 --- a/src/com/quollwriter/editors/messages/InviteResponseMessage.java +++ b/src/main/java/com/quollwriter/editors/messages/InviteResponseMessage.java @@ -1,7 +1,8 @@ package com.quollwriter.editors.messages; import java.util.*; -import java.awt.image.*; + +import javafx.scene.image.*; import com.quollwriter.*; import com.quollwriter.editors.*; @@ -10,232 +11,232 @@ //@Message(type=InviteResponseMessage.MESSAGE_TYPE) public class InviteResponseMessage extends EditorMessage { - + public static final String MESSAGE_TYPE = "invite-response"; - + private boolean accepted = false; private String editorName = null; - private BufferedImage editorAvatar = null; - + private Image editorAvatar = null; + public InviteResponseMessage () { - + } - + public InviteResponseMessage (boolean accepted, EditorAccount acc) { - + this.accepted = accepted; - + if (acc == null) { - + throw new NullPointerException ("Expected account to be provided."); - + } - + if (this.accepted) { - + this.editorName = acc.getName (); this.editorAvatar = acc.getAvatar (); } - + } - + @Override public void fillToStringProperties (Map props) { - + super.fillToStringProperties (props); - + this.addToStringProperties (props, "accepted", this.accepted); } - + protected void fillMap (Map data) throws Exception { - + data.put (MessageFieldNames.accepted, this.accepted); Map edInf = new HashMap (); - + data.put (MessageFieldNames.editorinformation, edInf); - + if (this.editorName != null) { - + edInf.put (MessageFieldNames.name, this.editorName); } - + if (this.editorAvatar != null) { - + edInf.put (MessageFieldNames.avatar, EditorsUtils.getImageAsBase64EncodedString (this.editorAvatar)); - + } - + } public boolean isAccepted () { - + return this.accepted; - + } - - public BufferedImage getEditorAvatar () + + public Image getEditorAvatar () { - + return this.editorAvatar; - + } - + public String getEditorName () { - + return this.editorName; - + } - + public String getMessage () - throws GeneralException + throws GeneralException { - + Map data = new HashMap (); - + data.put (MessageFieldNames.accepted, this.accepted); Map edInf = new HashMap (); - + data.put (MessageFieldNames.editorinformation, edInf); - + if (this.editorName != null) { - + edInf.put (MessageFieldNames.name, this.editorName); } - + if (this.editorAvatar != null) { - + try { - + edInf.put (MessageFieldNames.avatar, EditorsUtils.getImageAsBase64EncodedString (this.editorAvatar)); } catch (Exception e) { - + throw new GeneralException ("Unable to base64 encode editor avatar.", e); - + } - + } - + try { - + return JSONEncoder.encode (data); - + } catch (Exception e) { - + throw new GeneralException ("Unable to json encode data: " + data, e); - + } - + } - + public void setMessage (String s) throws GeneralException { - + // This is a summary of what was sent/received. Map data = (Map) JSONDecoder.decode (s); - + this.doInit (data, this.getEditor ()); - + } - + protected void doInit (Map data, EditorEditor from) throws GeneralException { - + this.accepted = this.getBoolean (MessageFieldNames.accepted, data); Map edInf = (Map) data.get (MessageFieldNames.editorinformation); - + if (edInf != null) { - + String n = this.getString (MessageFieldNames.name, edInf, false); - + if (n != null) { - + this.editorName = n; - + } - + String avatar = this.getString (MessageFieldNames.avatar, edInf, false); - + if (avatar != null) { - + try { - + this.editorAvatar = EditorsUtils.getImageFromBase64EncodedString (avatar); - + } catch (Exception e) { - + throw new GeneralException ("Unable to get avatar image from base64 encoded string.", e); - + } - + } - + } - + } - + public boolean isEncrypted () { - + return true; - + } - + public String getMessageType () { - + return MESSAGE_TYPE; - + } - -} \ No newline at end of file + +} diff --git a/src/com/quollwriter/editors/messages/MessageFactory.java b/src/main/java/com/quollwriter/editors/messages/MessageFactory.java similarity index 98% rename from src/com/quollwriter/editors/messages/MessageFactory.java rename to src/main/java/com/quollwriter/editors/messages/MessageFactory.java index e6781c7c..fab697f1 100644 --- a/src/com/quollwriter/editors/messages/MessageFactory.java +++ b/src/main/java/com/quollwriter/editors/messages/MessageFactory.java @@ -76,7 +76,7 @@ public static EditorMessage getInstance (String messageType) try { - mess = (EditorMessage) cl.newInstance (); + mess = (EditorMessage) cl.getDeclaredConstructor ().newInstance (); } catch (Exception e) { diff --git a/src/com/quollwriter/editors/messages/MessageFieldNames.java b/src/main/java/com/quollwriter/editors/messages/MessageFieldNames.java similarity index 100% rename from src/com/quollwriter/editors/messages/MessageFieldNames.java rename to src/main/java/com/quollwriter/editors/messages/MessageFieldNames.java diff --git a/src/com/quollwriter/editors/messages/MessageType.java b/src/main/java/com/quollwriter/editors/messages/MessageType.java similarity index 100% rename from src/com/quollwriter/editors/messages/MessageType.java rename to src/main/java/com/quollwriter/editors/messages/MessageType.java diff --git a/src/com/quollwriter/editors/messages/NewProjectMessage.java b/src/main/java/com/quollwriter/editors/messages/NewProjectMessage.java similarity index 84% rename from src/com/quollwriter/editors/messages/NewProjectMessage.java rename to src/main/java/com/quollwriter/editors/messages/NewProjectMessage.java index 0f664cb9..a2b5a76d 100644 --- a/src/com/quollwriter/editors/messages/NewProjectMessage.java +++ b/src/main/java/com/quollwriter/editors/messages/NewProjectMessage.java @@ -1,7 +1,8 @@ package com.quollwriter.editors.messages; import java.util.*; -import java.awt.image.*; +//import java.awt.image.*; +import javafx.scene.image.*; import com.quollwriter.*; import com.quollwriter.text.*; @@ -17,9 +18,9 @@ */ public class NewProjectMessage extends AbstractProjectMessage { - + public static final String MESSAGE_TYPE = "project-new"; - + //private String projectName = null; //private Set chapters = null; //private String notes = null; @@ -29,21 +30,21 @@ public class NewProjectMessage extends AbstractProjectMessage private String responseMessage = null; private Date responseDate = null; private String editorName = null; - private BufferedImage editorAvatar = null; + private Image editorAvatar = null; //private String versionName = null; - + public NewProjectMessage () { - + } - + public NewProjectMessage (Project project, Set chapters, ProjectVersion pv, EditorEditor editor, EditorAccount acc) { - + super (project, chapters, pv, @@ -54,103 +55,103 @@ public NewProjectMessage (Project project, (chapters.size () == 0) ) { - + throw new IllegalArgumentException ("Expected at least 1 chapter."); - + } - + this.setEditor (editor); this.setForProjectName (project.getName ()); this.setForProjectId (project.getId ()); this.versionName = versionName; - + this.chapters = chapters; this.notes = notes; this.dueBy = dueBy; - + int wc = 0; - + for (Chapter c : chapters) { - + wc += TextUtilities.getWordCount (c.getText ()); - + } - + this.wordCount = wc; */ if (acc != null) { - + this.editorName = acc.getName (); this.editorAvatar = acc.getAvatar (); - + } - + } - + @Override public void fillToStringProperties (Map props) { - + super.fillToStringProperties (props); - + this.addToStringProperties (props, "editorName", this.editorName); this.addToStringProperties (props, "hasEditorAvatar", (this.editorAvatar != null)); - + } - -/* + +/* public Set getChaptersWithText () throws Exception { - + Map data = EditorsEnvironment.getOriginalMessageAsMap (this); Object chaps = this.checkTypeAndNotNull (MessageFieldNames.chapters, data, List.class); - + List chapsL = (List) chaps; - + if (chapsL.size () == 0) { - + throw new GeneralException ("Expected to find at least 1 chapter."); - + } - + int wc = 0; - + Set chapsS = new LinkedHashSet (); - + for (int i = 0; i < chapsL.size (); i++) { - + Object co = chapsL.get (i); - + if (!(co instanceof Map)) { - + throw new GeneralException ("Expected chapter data for index: " + i + " to by a map, has type: " + co.getClass ().getName ()); - + } - + Map cm = (Map) co; Chapter c = TypeEncoder.decodeToChapter (cm); - + chapsS.add (c); - + } - + return chapsS; } @@ -158,200 +159,200 @@ public Set getChaptersWithText () /* public Set getChapters () { - + return this.chapters; - + } - */ + */ public boolean isAccepted () { - - return this.accepted; - + + return this.accepted; + } - + public void setAccepted (boolean v) { - + this.accepted = v; this.responseDate = new Date (); - + } - - public BufferedImage getEditorAvatar () + + public Image getEditorAvatar () { - + return this.editorAvatar; - + } - + public String getEditorName () { - + return this.editorName; - + } - + public Date getResponseDate () { - + return this.responseDate; - + } - + public void setResponseMessage (String m) { - + this.responseMessage = m; - + } - + public String getResponseMessage () { - + return this.responseMessage; - + } /* public Date getDueBy () { - + return this.dueBy; - + } - + public int getWordCount () { - + return this.wordCount; - + } - + public String getVersionName () { - + return this.versionName; - + } - + public String getNotes () { - + return this.notes; - + } */ - + @Override protected void fillMap (Map data) throws Exception { - + super.fillMap (data); - -/* + +/* if (this.getForProjectId () == null) { - + throw new GeneralException ("No project id set"); - + } - + if ((this.chapters == null) || (this.chapters.size () == 0) ) { - + throw new GeneralException ("No chapters set"); - + } - + data.put (MessageFieldNames.name, this.getForProjectName ()); - + if ((this.notes != null) && (this.notes.trim ().length () > 0) ) { - + data.put (MessageFieldNames.notes, this.notes.trim ()); - + } - + if (this.versionName != null) { - + data.put (MessageFieldNames.versionname, this.versionName); - + } - + if (this.dueBy != null) { - + data.put (MessageFieldNames.dueby, this.dueBy.getTime ()); - + } - + List clist = new ArrayList (); - + data.put (MessageFieldNames.chapters, clist); - + // Add the chapters. for (Chapter c : this.chapters) { - + clist.add (TypeEncoder.encode (c)); - - } + + } */ Map edInf = new HashMap (); - + data.put (MessageFieldNames.editorinformation, edInf); - + if (this.editorName != null) { - + edInf.put (MessageFieldNames.name, this.editorName); - + } - + if (this.editorAvatar != null) { - + edInf.put (MessageFieldNames.avatar, EditorsUtils.getImageAsBase64EncodedString (this.editorAvatar)); - + } - + } private boolean hasChapterText () { - + for (Chapter c : this.chapters) { - + if (c.getText () != null) { - + return true; - + } - + } - + return false; - + } - + /** * Creates a new Project object from the data held within the message. */ @@ -359,18 +360,18 @@ private boolean hasChapterText () public Project createProject () throws Exception { - + Set chaps = this.chapters; - + /* if (!this.hasChapterText ()) { - + chaps = this.getChaptersWithText (); - + } */ - + chaps = this.getChaptersWithText (); Project proj = new Project (); @@ -378,143 +379,143 @@ public Project createProject () proj.setId (this.getForProjectId ()); proj.setName (this.getForProjectName ()); proj.setForEditor (this.getEditor ().getEmail ()); - + proj.setProjectVersion (this.getProjectVersion ()); - + if (this.responseMessage != null) { - + proj.setEditResponseMessage (this.responseMessage); - + } - + Book b = new Book (proj, proj.getName ()); - + proj.addBook (b); - + for (Chapter c : chaps) { - + b.addChapter (c); - + } - - return proj; - + + return proj; + } - + @Override protected void doInit (Map data, EditorEditor from) throws Exception { - + super.doInit (data, from); - + Map edInf = (Map) data.get (MessageFieldNames.editorinformation); - + if (edInf != null) { - + String n = this.getString (MessageFieldNames.name, edInf, false); - + if (n != null) { - + this.editorName = n; - + } - + String avatar = this.getString (MessageFieldNames.avatar, edInf, false); - + if (avatar != null) { - + this.editorAvatar = EditorsUtils.getImageFromBase64EncodedString (avatar); - + } - - } - /* + + } + /* this.setForProjectName (this.getString (MessageFieldNames.name, data)); - + String notes = this.getString (MessageFieldNames.notes, data, false); - + if (notes != null) { - + notes = notes.trim (); - + if (notes.length () > 5000) { - + throw new GeneralException ("Notes is too long, max length is: 5000, is: " + notes.length ()); - + } - + this.notes = notes; - + } - + this.versionName = this.getString (MessageFieldNames.versionname, - data, + data, false); this.dueBy = this.getDate (MessageFieldNames.dueby, data, false); - + Object chaps = this.checkTypeAndNotNull (MessageFieldNames.chapters, data, List.class); - + List chapsL = (List) chaps; - + if (chapsL.size () == 0) { - + throw new GeneralException ("Expected to find at least 1 chapter."); - + } - + int wc = 0; - + Set chapsS = new LinkedHashSet (); - + for (int i = 0; i < chapsL.size (); i++) { - + Object co = chapsL.get (i); - + if (!(co instanceof Map)) { - + throw new GeneralException ("Expected chapter data for index: " + i + " to by a map, has type: " + co.getClass ().getName ()); - + } - + Map cm = (Map) co; Chapter c = TypeEncoder.decodeToChapter (cm); wc += TextUtilities.getWordCount (c.getText ()); - + chapsS.add (c); - + } - + this.wordCount = wc; this.chapters = chapsS; */ @@ -523,7 +524,7 @@ protected void doInit (Map data, public String getMessage () throws GeneralException { - + // Return a summary, should be json. Map m = new HashMap (); m.put (MessageFieldNames.name, @@ -539,131 +540,131 @@ public String getMessage () if (this.versionName != null) { - + m.put (MessageFieldNames.versionname, this.versionName); - + } - + if (this.responseDate != null) { - + m.put (MessageFieldNames.accepted, this.accepted); m.put (MessageFieldNames.responsedate, this.responseDate.getTime ()); - + if (this.responseMessage != null) { - + m.put (MessageFieldNames.responsemessage, this.responseMessage); - + } } - + // Get a summary of each chapter. List chs = new ArrayList (); - + for (Chapter c : this.chapters) { - + Map cm = new HashMap (); chs.add (cm); - + cm.put (MessageFieldNames.name, c.getName ()); cm.put (MessageFieldNames.chapterid, c.getId ()); cm.put (MessageFieldNames.version, c.getVersion ()); - + } - + m.put (MessageFieldNames.chapters, chs); - + if (this.dueBy != null) { - + m.put (MessageFieldNames.dueby, this.dueBy.getTime ()); - + } - + try { - + return JSONEncoder.encode (m); - + } catch (Exception e) { - + throw new GeneralException ("Unable to json encode message: " + m, e); - + } - + } */ - + @Override protected void fillMessageMap (Map m) - throws GeneralException + throws GeneralException { - + if (this.responseDate != null) { - + m.put (MessageFieldNames.accepted, this.accepted); m.put (MessageFieldNames.responsedate, this.responseDate.getTime ()); - + if (this.responseMessage != null) { - + m.put (MessageFieldNames.responsemessage, this.responseMessage); - + } - } - - } - + } + + } + @Override protected void fillFromMessageMap (Map data) throws GeneralException - + { - + this.responseDate = this.getDate (MessageFieldNames.responsedate, data, false); if (this.responseDate != null) { - + this.accepted = this.getBoolean (MessageFieldNames.accepted, data); - + this.responseMessage = this.getString (MessageFieldNames.responsemessage, data, false); } - + } /* public void setMessage (String m) throws GeneralException { - + // This is a summary of what was sent/received. Map data = (Map) JSONDecoder.decode (m); - + this.setForProjectName (this.getString (MessageFieldNames.name, data)); this.setForProjectId (this.getString (MessageFieldNames.projectid, @@ -683,60 +684,60 @@ public void setMessage (String m) if (this.responseDate != null) { - + this.accepted = this.getBoolean (MessageFieldNames.accepted, data); - + this.responseMessage = this.getString (MessageFieldNames.responsemessage, data, false); } - + Set chaps = null; - + List chs = (List) data.get (MessageFieldNames.chapters); - + if (chs != null) { - + chaps = new LinkedHashSet (); - + for (int i = 0; i < chs.size (); i++) { - + Map cm = (Map) chs.get (i); Chapter c = TypeEncoder.decodeToChapter (cm); - + chaps.add (c); - + } - + } - + this.chapters = chaps; - + this.dueBy = this.getDate (MessageFieldNames.dueby, data, false); - + } */ /* public boolean isEncrypted () { - + return true; - + } - */ + */ public String getMessageType () { - + return MESSAGE_TYPE; - + } - - -} \ No newline at end of file + + +} diff --git a/src/com/quollwriter/editors/messages/NewProjectResponseMessage.java b/src/main/java/com/quollwriter/editors/messages/NewProjectResponseMessage.java similarity index 83% rename from src/com/quollwriter/editors/messages/NewProjectResponseMessage.java rename to src/main/java/com/quollwriter/editors/messages/NewProjectResponseMessage.java index 1ba66a5f..0f698f0d 100644 --- a/src/com/quollwriter/editors/messages/NewProjectResponseMessage.java +++ b/src/main/java/com/quollwriter/editors/messages/NewProjectResponseMessage.java @@ -1,7 +1,8 @@ package com.quollwriter.editors.messages; import java.util.*; -import java.awt.image.*; + +import javafx.scene.image.*; import com.quollwriter.*; import com.quollwriter.editors.*; @@ -11,33 +12,33 @@ public class NewProjectResponseMessage extends EditorMessage { - + public static final String MESSAGE_TYPE = "project-new-response"; - + private String responseMessage = null; private boolean accepted = false; private String editorName = null; - private BufferedImage editorAvatar = null; - + private Image editorAvatar = null; + public NewProjectResponseMessage () { - + } - + public NewProjectResponseMessage (String projectId, boolean accepted, String message, EditorEditor ed, EditorAccount acc) { - + if (projectId == null) { - + throw new IllegalArgumentException ("Project id must be specified."); - + } - + this.setEditor (ed); this.setForProjectId (projectId); this.responseMessage = message; @@ -45,222 +46,222 @@ public NewProjectResponseMessage (String projectId, if (this.accepted) { - + this.editorName = acc.getName (); this.editorAvatar = acc.getAvatar (); } - + } - + @Override public void fillToStringProperties (Map props) { - + super.fillToStringProperties (props); - + this.addToStringProperties (props, "accepted", this.accepted); this.addToStringProperties (props, "message", this.responseMessage); - + } - + public boolean isAccepted () { - + return this.accepted; - + } - - public BufferedImage getEditorAvatar () + + public Image getEditorAvatar () { - + return this.editorAvatar; - + } - + public String getEditorName () { - + return this.editorName; - + } - + public String getResponseMessage () { - + return this.responseMessage; - + } - + protected void fillMap (Map data) throws GeneralException { - + if (this.getForProjectId () == null) { - + throw new GeneralException ("No project id set"); - + } - + if (this.responseMessage != null) { - + data.put (MessageFieldNames.message, this.responseMessage); - + } - + data.put (MessageFieldNames.accepted, this.accepted); - + Map edInf = new HashMap (); - + data.put (MessageFieldNames.editorinformation, edInf); - + if (this.editorName != null) { - + edInf.put (MessageFieldNames.name, this.editorName); } - + if (this.editorAvatar != null) { - + try { - + edInf.put (MessageFieldNames.avatar, EditorsUtils.getImageAsBase64EncodedString (this.editorAvatar)); } catch (Exception e) { - + throw new GeneralException ("Unable to get encoded avatar for editor."); - + } - + } - + } - + protected void doInit (Map data, EditorEditor from) throws GeneralException { - + this.responseMessage = this.getString (MessageFieldNames.message, data, false); - + this.accepted = this.getBoolean (MessageFieldNames.accepted, data); Map edInf = (Map) data.get (MessageFieldNames.editorinformation); - + if (edInf != null) { - + String n = this.getString (MessageFieldNames.name, edInf, false); - + if (n != null) { - + this.editorName = n; - + } - + String avatar = this.getString (MessageFieldNames.avatar, edInf, false); - + if (avatar != null) { - + try { - + this.editorAvatar = EditorsUtils.getImageFromBase64EncodedString (avatar); - + } catch (Exception e) { - + throw new GeneralException ("Unable to get image from encoded avatar."); - + } - + } - + } - + } - + public String getMessage () throws GeneralException { - + // Return a summary, should be json. Map m = new HashMap (); m.put (MessageFieldNames.projectid, this.getForProjectId ()); m.put (MessageFieldNames.accepted, this.accepted); - + if (this.responseMessage != null) { - + m.put (MessageFieldNames.message, this.responseMessage); } - + try { - + return JSONEncoder.encode (m); - + } catch (Exception e) { - + throw new GeneralException ("Unable to json encode message: " + m, e); - + } - + } - + public void setMessage (String m) throws GeneralException { - + // This is a summary of what was sent/received. Map data = (Map) JSONDecoder.decode (m); - + this.doInit (data, this.getEditor ()); - + } - + public boolean isEncrypted () { - + return true; - + } - + public String getMessageType () { - + return MESSAGE_TYPE; - + } - - -} \ No newline at end of file + + +} diff --git a/src/com/quollwriter/editors/messages/ProjectCommentsMessage.java b/src/main/java/com/quollwriter/editors/messages/ProjectCommentsMessage.java similarity index 81% rename from src/com/quollwriter/editors/messages/ProjectCommentsMessage.java rename to src/main/java/com/quollwriter/editors/messages/ProjectCommentsMessage.java index 18022b80..339a828e 100644 --- a/src/com/quollwriter/editors/messages/ProjectCommentsMessage.java +++ b/src/main/java/com/quollwriter/editors/messages/ProjectCommentsMessage.java @@ -13,391 +13,392 @@ */ public class ProjectCommentsMessage extends EditorMessage implements PropertyChangedListener { - + public static final String MESSAGE_TYPE = "project-comments"; - + private Set comments = null; private String generalComment = null; private ProjectVersion projVer = null; - private Map commentsDealtWith = new HashMap (); - + private Map commentsDealtWith = new HashMap<> (); + public ProjectCommentsMessage () { - + } - + public ProjectCommentsMessage (Project project, String genComment, Set comments, ProjectVersion pv, EditorEditor editor) { - + if ((comments == null) || (comments.size () == 0) ) { - + throw new IllegalArgumentException ("Expected at least 1 note."); - + } - + if (pv == null) { - + throw new IllegalArgumentException ("Expected a project version."); - + } - + if (pv.getId () == null) { - + throw new IllegalArgumentException ("Project version must have an id."); - + } this.projVer = pv; - + this.setEditor (editor); + this.setForProjectName (project.getName ()); this.setForProjectId (project.getId ()); this.comments = comments; this.generalComment = genComment; - + } - + @Override public void setPropertiesAsString (String p) throws Exception { - + super.setPropertiesAsString (p); String d = this.getProperty ("dealtwithcomments"); - + if (d != null) { - + // Decode the json. Map m = (Map) JSONDecoder.decode (d); - + this.commentsDealtWith.putAll (m); - + } - + } - + public void setCommentDealtWith (String id, Date date) throws Exception { - + Map dealtWith = this.getCommentsDealtWith (); - + if (date == null) { - + dealtWith.remove (id); - + } else { - + dealtWith.put (id, date); } - + this.setProperty ("dealtwithcomments", JSONEncoder.encode (dealtWith)); - + } - + public Map getCommentsDealtWith () { - + return this.commentsDealtWith; - + } - + @Override public void fillToStringProperties (Map props) { - + super.fillToStringProperties (props); - + this.addToStringProperties (props, "versionName", this.projVer.getName ()); this.addToStringProperties (props, "versionId", this.projVer.getId ()); - + this.addToStringProperties (props, "generalComment", this.generalComment); this.addToStringProperties (props, "comments", this.comments.size ()); - + } - + public ProjectVersion getProjectVersion () { - + return this.projVer; - + } - + public String getGeneralComment () { - - return this.generalComment; - + + return this.generalComment; + } - + public Set getChapters () { - - Set chaps = new LinkedHashSet (); - + + Set chaps = new LinkedHashSet<> (); + for (Note n : this.comments) { - + Chapter c = n.getChapter (); - + if (chaps.contains (c)) { - + continue; - + } - + chaps.add (c); - + } - + return chaps; - + } public Set getComments () { - + return this.comments; - + } - + @Override public void propertyChanged (PropertyChangedEvent ev) { - + if (ev.getChangeType ().equals (Note.DEALT_WITH)) { - + Note n = (Note) ev.getSource (); - + try { - + this.setCommentDealtWith (n.getId (), (Date) ev.getNewValue ()); - + } catch (Exception e) { - + Environment.logError ("Unable to set comment as dealt with: " + n, e); - + } } - + } - + protected void fillMap (Map data) throws GeneralException { - + if (this.getForProjectId () == null) { - + throw new GeneralException ("No project id set"); - + } - + if (this.generalComment != null) { - + data.put (MessageFieldNames.generalcomment, this.generalComment); - + } - + if ((this.comments == null) || (this.comments.size () == 0) ) { - + throw new GeneralException ("No notes set"); - + } - + data.put (MessageFieldNames.versionid, this.projVer.getId ()); - + if (this.projVer.getName () != null) { - + data.put (MessageFieldNames.versionname, this.projVer.getName ()); - + } - - List clist = new ArrayList (); - + + List clist = new ArrayList<> (); + data.put (MessageFieldNames.comments, clist); - + for (Note n : this.comments) { - + clist.add (TypeEncoder.encode (n)); - - } - + + } + } - + protected void doInit (Map data, EditorEditor from) throws GeneralException { - + this.generalComment = this.getString (MessageFieldNames.generalcomment, data, false); - + String projVerId = this.getString (MessageFieldNames.versionid, data); String projVerName = this.getString (MessageFieldNames.versionname, data, false); - + // Get the project version. ProjectVersion pv = new ProjectVersion (); pv.setId (projVerId); pv.setName (projVerName); - + this.projVer = pv; - + Object cms = this.checkTypeAndNotNull (MessageFieldNames.comments, data, List.class); - + List commsL= (List) cms; - + if (commsL.size () == 0) { - + throw new GeneralException ("Expected to find at least 1 comment."); - + } - - Set comments = new LinkedHashSet (); - + + Set comments = new LinkedHashSet<> (); + for (int i = 0; i < commsL.size (); i++) { - + Object co = commsL.get (i); - + if (!(co instanceof Map)) { - + throw new GeneralException ("Expected comment data for index: " + i + " to by a map, has type: " + co.getClass ().getName ()); - + } - + Map cm = (Map) co; Note n = TypeEncoder.decodeToNote (cm); - + n.addPropertyChangedListener (this); - + comments.add (n); - + } - + this.comments = comments; - + } - + public String getMessage () throws GeneralException { - + // Return a summary, should be json. Map m = new HashMap (); m.put (MessageFieldNames.projectid, this.getForProjectId ()); - + if (this.generalComment != null) { - + m.put (MessageFieldNames.generalcomment, this.generalComment); - + } - + m.put (MessageFieldNames.versionid, this.projVer.getId ()); - + if (this.projVer.getName () != null) { - + m.put (MessageFieldNames.versionname, this.projVer.getName ()); - + } List cms = new ArrayList (); - + m.put (MessageFieldNames.comments, cms); - + for (Note n : this.comments) { - + cms.add (TypeEncoder.encode (n)); - + } - + try { - + return JSONEncoder.encode (m); - + } catch (Exception e) { - + throw new GeneralException ("Unable to json encode message: " + m, e); - + } - + } public void setMessage (String m) throws GeneralException { - + // This is a summary of what was sent/received. Map data = (Map) JSONDecoder.decode (m); - + this.setForProjectId (this.getString (MessageFieldNames.projectid, data)); - + ProjectVersion pv = new ProjectVersion (); pv.setId (this.getString (MessageFieldNames.versionid, data)); @@ -406,50 +407,50 @@ public void setMessage (String m) false)); this.projVer = pv; - + this.generalComment = this.getString (MessageFieldNames.generalcomment, data, false); - + Set comms = null; - + List cms = (List) data.get (MessageFieldNames.comments); - + if (cms != null) { - - comms = new LinkedHashSet (); - + + comms = new LinkedHashSet<> (); + for (int i = 0; i < cms.size (); i++) { - + Map cm = (Map) cms.get (i); Note n = TypeEncoder.decodeToNote (cm); - + comms.add (n); - + } - + } - + this.comments = comms; - + } - + public boolean isEncrypted () { - + return true; - + } - + public String getMessageType () { - + return MESSAGE_TYPE; - + } - - -} \ No newline at end of file + + +} diff --git a/src/com/quollwriter/editors/messages/ProjectEditStopMessage.java b/src/main/java/com/quollwriter/editors/messages/ProjectEditStopMessage.java similarity index 100% rename from src/com/quollwriter/editors/messages/ProjectEditStopMessage.java rename to src/main/java/com/quollwriter/editors/messages/ProjectEditStopMessage.java diff --git a/src/com/quollwriter/editors/messages/PublicKeyMessage.java b/src/main/java/com/quollwriter/editors/messages/PublicKeyMessage.java similarity index 100% rename from src/com/quollwriter/editors/messages/PublicKeyMessage.java rename to src/main/java/com/quollwriter/editors/messages/PublicKeyMessage.java diff --git a/src/com/quollwriter/editors/messages/TypeEncoder.java b/src/main/java/com/quollwriter/editors/messages/TypeEncoder.java similarity index 100% rename from src/com/quollwriter/editors/messages/TypeEncoder.java rename to src/main/java/com/quollwriter/editors/messages/TypeEncoder.java diff --git a/src/com/quollwriter/editors/messages/UpdateProjectMessage.java b/src/main/java/com/quollwriter/editors/messages/UpdateProjectMessage.java similarity index 100% rename from src/com/quollwriter/editors/messages/UpdateProjectMessage.java rename to src/main/java/com/quollwriter/editors/messages/UpdateProjectMessage.java diff --git a/src/main/java/com/quollwriter/editors/ui/AddEditCommentPopup.java b/src/main/java/com/quollwriter/editors/ui/AddEditCommentPopup.java new file mode 100644 index 00000000..b4cac9e8 --- /dev/null +++ b/src/main/java/com/quollwriter/editors/ui/AddEditCommentPopup.java @@ -0,0 +1,391 @@ +package com.quollwriter.editors.ui; + +import java.util.*; + +import javafx.scene.Node; +import javafx.scene.control.*; +import javafx.scene.layout.*; +import javafx.event.*; +import javafx.collections.*; + +import javafx.beans.property.*; + +import com.quollwriter.*; +import com.quollwriter.data.*; +import com.quollwriter.editors.*; +import com.quollwriter.editors.ui.panels.*; +import com.quollwriter.ui.fx.*; +import com.quollwriter.ui.fx.components.*; +import com.quollwriter.ui.fx.viewers.*; +import com.quollwriter.ui.fx.panels.*; +import com.quollwriter.ui.fx.popups.*; +import com.quollwriter.text.*; + +import static com.quollwriter.uistrings.UILanguageStringsManager.getUILanguageStringProperty; +import static com.quollwriter.LanguageStrings.*; + +public class AddEditCommentPopup extends PopupContent +{ + + private static final String POPUP_ID = "comment"; + private Note item = null; + private Chapter chapter = null; + private Form form = null; + private QuollTextArea desc = null; + private boolean addMode = false; + private HyperlinkLinkedToPanel linkedToPanel = null; + private TextEditor.Highlight highlight = null; + + public AddEditCommentPopup (EditorProjectViewer viewer, + Chapter ch, + Note item) + { + + super (viewer); + + this.item = item; + this.chapter = ch; + + if (this.item.getKey () == null) + { + + throw new IllegalArgumentException ("Expected item to have a key."); + + } + + this.addMode = this.item.getKey () < 0; + + EditorChapterPanel editor = viewer.getEditorForChapter (this.chapter); + + this.form = this.addItems (Form.builder (), + editor.getSelectedText ()) + .confirmButton (getUILanguageStringProperty (buttons,save)) + .cancelButton (getUILanguageStringProperty (buttons,cancel)) + .build (); + + this.form.addEventHandler (Form.FormEvent.CANCEL_EVENT, + ev -> + { + + this.close (); + + }); + + this.form.addEventHandler (Form.FormEvent.CONFIRM_EVENT, + ev -> + { + + this.form.hideError (); + + Set err = this.getFormErrors (); + + if (err.size () > 0) + { + + this.form.showErrors (err); + return; + + } + + if (this.handleSave ()) + { + + this.close (); + + } + + }); + + if (!this.addMode) + { + + this.highlight = this.viewer.getEditorForChapter (this.chapter).getEditor ().addHighlight (new IndexRange (this.item.getStartPosition (), + this.item.getEndPosition ()), + UserProperties.getEditorCommentChapterHighlightColor ()); + + } + + this.getChildren ().add (this.form); + + } + + public void setOnClose (Runnable r) + { + + this.getPopup ().setOnClose (r); + + } + + public void setOnCancel (EventHandler h) + { + + this.form.setOnCancel (h); + + } + + private Set getFormErrors () + { + + List prefix = Arrays.asList (comments,addedit,errors); + + Set errs = new LinkedHashSet<> (); + + String text = this.desc.getText (); + + if ((text == null) + || + (text.trim ().length () == 0) + ) + { + + errs.add (getUILanguageStringProperty (Utils.newList (prefix,novalue))); + //"Please enter a description."); + + } + + return errs; + + } + + private Form.Builder addItems (Form.Builder builder, + String selectedText) + { + + List prefix = Arrays.asList (comments,addedit,labels); + + this.desc = QuollTextArea.builder () + .placeholder (getUILanguageStringProperty (comments,addedit,labels,comment,tooltip)) + .styleClassName (StyleClassNames.DESCRIPTION) + .withViewer (this.viewer) + .formattingEnabled (true) + .build (); + + builder.item (this.desc); + + this.linkedToPanel = new HyperlinkLinkedToPanel (this.item, + this.getBinder (), + this.viewer); + + builder.item (this.linkedToPanel); + + this.desc.setText (this.item.getDescription ()); + + return builder; + + } + + private boolean handleSave () + { + + String c = this.desc.getText (); + + this.item.setDescription (this.desc.getTextWithMarkup ()); + + // Use the first line of the description as the summary. + Paragraph p = new Paragraph (c, + 0); + + this.item.setSummary (p.getFirstSentence ().getText ()); + + EditorChapterPanel editor = viewer.getEditorForChapter (this.chapter); + + String type = Note.EDIT_NEEDED_NOTE_TYPE; + + int s = editor.getSelection ().getStart (); + int e = editor.getSelection ().getEnd (); + + if ((!this.addMode) + && + (s != e) + && + (e > s) + ) + { + + this.item.setPosition (s); + this.item.setEndPosition (e); + + } + + if (this.addMode) + { + + this.item.setPosition (s); + this.item.setEndPosition (e); + + } + + try + { + + if (this.addMode) + { + + // Add the item to the chapter. + this.item.setKey (null); + this.item.setChapter (this.chapter); + + // Need to save the object first so the key is setup correctly. + this.viewer.saveObject (this.item, + true); + + this.chapter.addNote (this.item); + + } + + this.item.setLinks (this.linkedToPanel.getLinkedToPanel ().getSelected ()); + + this.viewer.saveObject (this.item, + true); + + this.viewer.fireProjectEvent (ProjectEvent.Type.note, + (this.addMode ? ProjectEvent.Action._new : ProjectEvent.Action.edit), + this.item); + + + } catch (Exception ex) + { + + Environment.logError ("Unable to save/add note: " + + this.item, + ex); + + this.chapter.removeNote (this.item); + + ComponentUtils.showErrorMessage (this.viewer, + getUILanguageStringProperty(comments, (this.addMode ? _new : edit), actionerror)); + + return false; + + } + +/* +TODO Needed? + try + { + + Position pos = this.editor.getDocument ().createPosition (this.item.getPosition ()); + + this.item.setTextPosition (pos); + + if (this.item.getEndPosition () > -1) + { + + this.item.setEndTextPosition (this.editor.getDocument ().createPosition (this.item.getEndPosition ())); + + } + + } catch (Exception ex) { + + Environment.logError ("Unable to set text position", + ex); + + } +*/ +/* + if (this.item.isEditNeeded ()) + { + + try + { + + this.item.setTextPosition2 (editor.createTextPosition (this.item.getPosition ())); + + if (this.item.getEndPosition () > -1) + { + + this.item.setEndTextPosition2 (editor.createTextPosition (this.item.getEndPosition ())); + + } + + } catch (Exception e) { + + Environment.logError ("Unable to set text position", + e); + + } + + } +*/ + if (this.item.getChapter () != null) + { + + editor.requestFocus (); + + } + + // Need to reindex the chapter to ensure that things are in the right order. + // TODO Needed? this.chapter.reindex (); + + return true; + + } + + @Override + public QuollPopup createPopup () + { + + StringProperty title = null; + + if (!this.addMode) + { + + title = getUILanguageStringProperty (comments,edit,LanguageStrings.title); + + } else { + + title = getUILanguageStringProperty (comments,_new,LanguageStrings.title); + + } + + QuollPopup p = QuollPopup.builder () + .title (title) + .styleClassName (this.addMode ? StyleClassNames.ADD : StyleClassNames.EDIT) + .headerIconClassName (StyleClassNames.COMMENT) + .hideOnEscape (true) + .withClose (true) + .content (this) + .popupId (AddEditCommentPopup.getPopupIdForComment (this.item)) + .removeOnClose (true) + .withViewer (this.viewer) + .build (); + + p.getStyleClass ().add (StyleClassNames.COMMENT); + + p.toFront (); + + p.addEventHandler (QuollPopup.PopupEvent.SHOWN_EVENT, + ev -> + { + + this.desc.requestFocus (); + + }); + + p.addEventHandler (QuollPopup.PopupEvent.CLOSED_EVENT, + ev -> + { + + EditorChapterPanel ed = this.viewer.getEditorForChapter (this.chapter); + + if (ed != null) + { + + ed.getEditor ().removeHighlight (this.highlight); + + } + + }); + + return p; + + } + + public static String getPopupIdForComment (Note ci) + { + + return POPUP_ID + ci.getObjectReference ().asString (); + + } + +} diff --git a/src/main/java/com/quollwriter/editors/ui/ChatMessageAccordionItem.java b/src/main/java/com/quollwriter/editors/ui/ChatMessageAccordionItem.java new file mode 100644 index 00000000..25de2825 --- /dev/null +++ b/src/main/java/com/quollwriter/editors/ui/ChatMessageAccordionItem.java @@ -0,0 +1,39 @@ +package com.quollwriter.editors.ui; + +import java.util.*; +import javafx.scene.*; + +import com.quollwriter.data.*; +import com.quollwriter.data.editors.*; +import com.quollwriter.*; +import com.quollwriter.editors.*; +import com.quollwriter.events.*; +import com.quollwriter.editors.messages.*; +import com.quollwriter.ui.fx.viewers.*; + +public class ChatMessageAccordionItem extends MessageAccordionItem +{ + + public ChatMessageAccordionItem (AbstractViewer pv, + Date d, + Set messages) + { + + super (pv, + d, + messages); + + } + + @Override + public Node getMessageBox (EditorChatMessage m) + { + + ChatMessageBox cmb = new ChatMessageBox (m, + this.viewer); + + return cmb; + + } + +} diff --git a/src/main/java/com/quollwriter/editors/ui/ChatMessageBox.java b/src/main/java/com/quollwriter/editors/ui/ChatMessageBox.java new file mode 100644 index 00000000..38632c88 --- /dev/null +++ b/src/main/java/com/quollwriter/editors/ui/ChatMessageBox.java @@ -0,0 +1,158 @@ +package com.quollwriter.editors.ui; + +import java.awt.image.*; +import java.util.*; + +import javafx.beans.property.*; +import javafx.scene.layout.*; +import javafx.scene.control.*; +import javafx.scene.*; +import javafx.embed.swing.*; +import javafx.scene.image.*; + +import com.quollwriter.*; +import com.quollwriter.data.*; +import com.quollwriter.data.editors.*; +import com.quollwriter.editors.messages.*; +import com.quollwriter.editors.*; +import com.quollwriter.ui.fx.components.*; +import com.quollwriter.ui.fx.viewers.*; +import com.quollwriter.ui.fx.*; +import com.quollwriter.uistrings.UILanguageStringsManager; + +import static com.quollwriter.LanguageStrings.*; +import static com.quollwriter.uistrings.UILanguageStringsManager.getUILanguageStringProperty; + +public class ChatMessageBox extends MessageBox +{ + + public ChatMessageBox (EditorChatMessage mess, + AbstractViewer viewer) + { + + super (mess, + viewer); + + this.managedProperty ().bind (this.visibleProperty ()); + this.getStyleClass ().add (StyleClassNames.CHATMESSAGE); + + HBox b = new HBox (); + + this.getChildren ().add (b); + + QuollTextView messText = QuollTextView.builder () + .text (this.message.getMessage ()) + .inViewer (this.viewer) + .build (); + HBox.setHgrow (messText, + Priority.ALWAYS); + + if (this.message.isSentByMe ()) + { + + ObjectProperty av = EditorsEnvironment.getUserAccount ().avatarProperty (); +/* +TODO Remove? Don't think its needed. + if (av != null) + { + + b.getChildren ().add (new ImageView (SwingFXUtils.toFXImage (EditorsEnvironment.getUserAccount ().getAvatar (), + null))); + + } +*/ + b.getChildren ().add (messText); + messText.maxWidthProperty ().bind (b.widthProperty ()); + messText.prefWidthProperty ().bind (b.widthProperty ()); + + Node nav = this.createAvatar (av, + (av == null ? getUILanguageStringProperty (editors,editor,view,chatmessages,sentbyme) : null), + this.message.getWhen ()); + nav.getStyleClass ().add (StyleClassNames.USER); + + b.getChildren ().add (nav); + + } else { + + ObjectProperty av = this.message.getEditor ().mainAvatarProperty (); +/* + if (av == null) + { + + av = Environment.getNoEditorAvatarImage (); + + } +*/ + Node nav = this.createAvatar (av, + null, + this.message.getWhen ()); + nav.getStyleClass ().add (StyleClassNames.OTHER); + + b.getChildren ().add (nav); + b.getChildren ().add (messText); + + } + + } + + public boolean isAutoDealtWith () + { + + return true; + + } + + private Node createAvatar (ObjectProperty im, + StringProperty message, + Date when) + { + + VBox b = new VBox (); + + IconBox ib = IconBox.builder () + .image (im) + .styleClassName ("avatar-box") + .onImagePresent (bb -> + { + + bb.pseudoClassStateChanged (StyleClassNames.NOAVATAR_PSEUDO_CLASS, false); + + }) + .onNoImage (bb -> + { + + bb.pseudoClassStateChanged (StyleClassNames.NOAVATAR_PSEUDO_CLASS, true); + + }) + .build (); + + b.getChildren ().add (ib); + + if (message != null) + { + + b.getChildren ().add (QuollLabel.builder () + .label (message) + .build ()); + + } + + if (when != null) + { + + b.getChildren ().add (QuollLabel.builder () + .label (UILanguageStringsManager.createStringPropertyWithBinding (() -> + { + + return Environment.formatTime (when); + + })) + .build ()); + + } + + return b; + + } + +} diff --git a/src/main/java/com/quollwriter/editors/ui/CommentItemFormatter.java b/src/main/java/com/quollwriter/editors/ui/CommentItemFormatter.java new file mode 100644 index 00000000..4661611c --- /dev/null +++ b/src/main/java/com/quollwriter/editors/ui/CommentItemFormatter.java @@ -0,0 +1,166 @@ +package com.quollwriter.editors.ui; + +import java.util.*; +import java.util.function.*; + +import javafx.beans.property.*; +import javafx.scene.Node; +import javafx.scene.control.*; +import javafx.scene.layout.*; + +import com.quollwriter.*; +import com.quollwriter.data.*; +import com.quollwriter.ui.fx.components.*; +import com.quollwriter.ui.fx.viewers.*; +import com.quollwriter.ui.fx.*; +import com.quollwriter.ui.fx.panels.*; + +public class CommentItemFormatter extends AbstractChapterItemFormatter +{ + + public CommentItemFormatter (AbstractProjectViewer viewer, + IPropertyBinder binder, + Note item, + Runnable onNewPopupShown, + boolean itemEditable, + Supplier> extraControls) + { + + super (viewer, + binder, + item, + onNewPopupShown, + itemEditable && !item.isDealtWith (), + extraControls); + + } + + @Override + public void saveItem (Note item) + throws GeneralException + { + + viewer.saveObject (item, + false); + + } + + @Override + public void deleteItem (Note item) + { + + // TODO Fix! + if (this.viewer instanceof EditorProjectViewer) + { + + ((EditorProjectViewer) viewer).showDeleteComment (item); + + } + + } + + @Override + public void editItem (Note item) + { + + this.viewer.runCommand (ProjectViewer.CommandId.editobject, + item); + + } + + @Override + public Node getContent () + { + + VBox v = new VBox (); + + if (this.item.isDealtWith ()) + { + + QuollLabel l = QuollLabel.builder () + .styleClassName (StyleClassNames.DEALTWITH) + .label (new SimpleStringProperty (Environment.formatDateTime (this.item.getDealtWith ()))) + .build (); + + v.getChildren ().add (l); + + this.binder.addChangeListener (this.item.dealtWithProperty (), + (pr, oldv, newv) -> + { + + l.setVisible (this.item.isDealtWith ()); + + }); + + } + + String summ = this.item.getSummary (); + + String desc = null; + + if ((!this.item.getType ().equals ("")) + && + (!this.item.isEditNeeded ()) + ) + { + + summ = "" + this.item.getType () + ": " + summ; + + if (this.item.getDescription () != null) + { + + summ += "
    " + this.item.getDescription ().getMarkedUpText (); + + } + + desc = summ; + + } else { + + desc = item.getDescription ().getMarkedUpText (); + + } + + QuollTextView t = QuollTextView.builder () + .text (desc) + .styleClassName (StyleClassNames.DESCRIPTION) + .build (); + /* + BasicHtmlTextFlow t = BasicHtmlTextFlow.builder () + .text (desc) + .styleClassName (StyleClassNames.DESCRIPTION) + .build (); +*/ + v.getChildren ().add (t); + + return v; + + } + + @Override + public String getStyleClassName () + { + + return StyleClassNames.COMMENT; + + } + + @Override + public StringProperty getPopupTitle () + { + + return null; + /* + if (mode == CommentActionHandler.EDIT) + { + + return getUILanguageStringProperty (comments,edit,title); + //"Edit Comment"; + + } + + return getUILanguageStringProperty (comments,_new,title); +*/ + } + +} diff --git a/src/main/java/com/quollwriter/editors/ui/EditorChaptersSidebarItem.java b/src/main/java/com/quollwriter/editors/ui/EditorChaptersSidebarItem.java new file mode 100644 index 00000000..4c9a85e2 --- /dev/null +++ b/src/main/java/com/quollwriter/editors/ui/EditorChaptersSidebarItem.java @@ -0,0 +1,927 @@ +package com.quollwriter.editors.ui; + +import java.util.*; +import java.util.function.*; +import java.util.stream.*; + +import javafx.collections.*; +import javafx.beans.value.*; +import javafx.beans.binding.*; +import javafx.beans.property.*; +import javafx.css.*; +import javafx.scene.*; +import javafx.scene.layout.*; +import javafx.scene.control.*; +import javafx.scene.image.*; +import javafx.scene.input.*; +import javafx.geometry.*; + +import org.reactfx.*; +import org.fxmisc.flowless.*; +import org.fxmisc.wellbehaved.event.*; + +import com.quollwriter.*; +import com.quollwriter.data.*; +import com.quollwriter.data.comparators.*; +import com.quollwriter.data.editors.*; +import com.quollwriter.ui.fx.*; +import com.quollwriter.ui.fx.viewers.*; +import com.quollwriter.ui.fx.components.*; +import com.quollwriter.ui.fx.sidebars.*; +import com.quollwriter.ui.fx.panels.*; +import com.quollwriter.editors.ui.panels.*; +import com.quollwriter.uistrings.UILanguageStringsManager; + +import static com.quollwriter.uistrings.UILanguageStringsManager.getUILanguageStringProperty; +import static com.quollwriter.LanguageStrings.*; + +public class EditorChaptersSidebarItem extends ProjectObjectsSidebarItem +{ + + private QuollTreeView tree = null; + private IntegerProperty countProp = null; + private Map> eventSourceSubscriptions = new HashMap<> (); + private Map noteTreeLabels = new HashMap<> (); + private boolean ignoreChaptersEvents = false; + + public EditorChaptersSidebarItem (EditorProjectViewer pv, + IPropertyBinder binder) + { + + super (pv, + binder); + + pv.getProject ().getBooks ().get (0).getChapters ().stream () + .forEach (c -> this.addListenersForChapter (c)); + + this.countProp = new SimpleIntegerProperty (0); + + this.addChangeListener (this.viewer.currentPanelProperty (), + (pr, oldv, newv) -> + { + + this.selectItem (); + + }); + + this.tree = NamedObjectTree.builder () + .project (this.viewer.getProject ()) + .root (this.createTree ()) + .onDragDropped (n -> {}) + .canExport (n -> false) + .canImport ((nOver, nImport) -> false) + .labelProvider (treeItem -> + { + + NamedObject n = treeItem.getValue (); + + if (n instanceof Project) + { + + return new Label (); + + } + + QuollLabel l = QuollLabel.builder () + .styleClassName (n.getObjectType ()) + .build (); + + if (n instanceof Note) + { + + Note _n = (Note) n; + + l.setIconClassName (StyleClassNames.COMMENT); + l.getStyleClass ().add (StyleClassNames.COMMENT); + l.textProperty ().bind (n.nameProperty ()); + + } + + l.setOnMouseClicked (ev -> + { + + if (ev.getButton () != MouseButton.PRIMARY) + { + + return; + + } + + l.requestFocus (); + + this.viewer.viewObject (n); + + }); + + List prefix = Arrays.asList (project,sidebar,chapters,treepopupmenu,items); + + if (n instanceof Chapter) + { + + Chapter c = (Chapter) n; + + this.addSetChangeListener (c.getNotes (), + ev -> + { + + this.updateChapterLabel (c, + l); + + }); + + this.addChangeListener (c.nameProperty (), + (pr, oldv, newv) -> + { + + this.updateChapterLabel (c, + l); + + }); + + this.updateChapterLabel (c, + l); + + //l.setFocusTraversable (true); + + Runnable setIcon = () -> + { + + l.setIconClassName (StyleClassNames.CHAPTER); + + if (c.getEditPosition () > 0) + { + + l.setIconClassName (StyleClassNames.EDITPOSITION); + + } + + if (c.isEditComplete ()) + { + + l.setIconClassName (StyleClassNames.EDITCOMPLETE); + + } + + }; + + if (!c.isEditComplete () && c.getEditPosition () > 0) + { + + l.pseudoClassStateChanged (StyleClassNames.EDITPOSITION_PSEUDO_CLASS, true); + + } + + if (c.isEditComplete ()) + { + + l.pseudoClassStateChanged (StyleClassNames.EDITCOMPLETE_PSEUDO_CLASS, true); + + } + + UIUtils.runLater (setIcon); + + this.addChangeListener (UserProperties.showEditPositionIconInChapterListProperty (), + (pr, oldv, newv) -> + { + + l.pseudoClassStateChanged (StyleClassNames.EDITPOSITION_PSEUDO_CLASS, false); + + if ((newv) + && + (c.getEditPosition () > -1) + ) + { + + l.pseudoClassStateChanged (StyleClassNames.EDITPOSITION_PSEUDO_CLASS, true); + + } + + UIUtils.runLater (setIcon); + + }); + + this.addChangeListener (c.editPositionProperty (), + (pr, oldv, newv) -> + { + + if (UserProperties.getAsBoolean (Constants.SHOW_EDIT_POSITION_ICON_IN_CHAPTER_LIST_PROPERTY_NAME)) + { + + if (!c.isEditComplete ()) + { + + l.pseudoClassStateChanged (StyleClassNames.EDITPOSITION_PSEUDO_CLASS, newv.intValue () > 0); + + + } + + } else { + + l.pseudoClassStateChanged (StyleClassNames.EDITPOSITION_PSEUDO_CLASS, false); + + } + + UIUtils.runLater (setIcon); + + }); + + this.addChangeListener (UserProperties.showEditCompleteIconInChapterListProperty (), + (pr, oldv, newv) -> + { + + l.pseudoClassStateChanged (StyleClassNames.EDITCOMPLETE_PSEUDO_CLASS, false); + + if ((newv) + && + (c.isEditComplete ()) + ) + { + + l.pseudoClassStateChanged (StyleClassNames.EDITCOMPLETE_PSEUDO_CLASS, true); + + } + + if (newv) + { + + UIUtils.runLater (setIcon); + + } else { + + l.setIconClassName (StyleClassNames.CHAPTER); + + } + + }); + + this.addChangeListener (c.editCompleteProperty (), + (pr, oldv, newv) -> + { + + if (UserProperties.getAsBoolean (Constants.SHOW_EDIT_COMPLETE_ICON_IN_CHAPTER_LIST_PROPERTY_NAME)) + { + + l.pseudoClassStateChanged (StyleClassNames.EDITCOMPLETE_PSEUDO_CLASS, newv); + + } else { + + l.pseudoClassStateChanged (StyleClassNames.EDITCOMPLETE_PSEUDO_CLASS, false); + + } + + UIUtils.runLater (setIcon); + + }); + + } + + return l; + + }) + .onClick ((n, ev) -> + { + + if (n instanceof NoteTreeLabel) + { + + TreeItem ti = this.tree.getTreeItemForObject (n); + + ti.setExpanded (!ti.isExpanded ()); + + } else { + + this.viewer.viewObject (n); + + } + + }) + .contextMenuItemSupplier (n -> + { + + Set its = new LinkedHashSet<> (); + + if (n instanceof Note) + { + + List prefix = Arrays.asList (editors,project,sidebar,comments,treepopupmenu,comments,items); + + final Note note = (Note) n; + + its.add (QuollMenuItem.builder () + .label (getUILanguageStringProperty (Utils.newList (prefix,view))) + .iconName (StyleClassNames.VIEW) + .onAction (ev -> + { + + this.viewer.viewObject (n); + + }) + .build ()); + + if (!note.isDealtWith ()) + { + + its.add (QuollMenuItem.builder () + .label (getUILanguageStringProperty (Utils.newList (prefix,edit))) + .iconName (StyleClassNames.EDIT) + .onAction (ev -> + { + + this.viewer.editComment (note); + + }) + .build ()); + + its.add (QuollMenuItem.builder () + .label (getUILanguageStringProperty (Utils.newList (prefix,delete))) + .iconName (StyleClassNames.DELETE) + .onAction (ev -> + { + + this.viewer.showDeleteComment (note); + + }) + .build ()); + + } + + } + + if (n instanceof Chapter) + { + + List prefix = Arrays.asList (editors,project,sidebar,comments,treepopupmenu,chapters,items); + + final Chapter c = (Chapter) n; + + final String chapterObjTypeName = Environment.getObjectTypeName (c).getValue (); + + its.add (QuollMenuItem.builder () + .label (getUILanguageStringProperty (Utils.newList (prefix,edit))) + .iconName (StyleClassNames.EDIT) + .onAction (ev -> + { + + this.viewer.runCommand (ProjectViewer.CommandId.viewobject, + c); + + }) + .build ()); + + if (!c.isEditComplete ()) + { + + its.add (QuollMenuItem.builder () + .label (getUILanguageStringProperty (Utils.newList (prefix,seteditcomplete))) + .iconName (StyleClassNames.EDITCOMPLETE) + .onAction (ev -> + { + + this.viewer.setChapterEditComplete (c, + true); + + }) + .build ()); + + } else { + + its.add (QuollMenuItem.builder () + .label (getUILanguageStringProperty (Utils.newList (prefix,seteditneeded))) + .iconName (StyleClassNames.EDITNEEDED) + .onAction (ev -> + { + + this.viewer.setChapterEditComplete (c, + false); + + }) + .build ()); + + } + + if ((c.getEditPosition () > 0) + && + (!c.isEditComplete ()) + ) + { + + its.add (QuollMenuItem.builder () + .label (getUILanguageStringProperty (Utils.newList (prefix,gotoeditposition))) + .iconName (StyleClassNames.GOTOEDITPOSITION) + .onAction (ev -> + { + + this.viewer.editChapter (c, + () -> + { + + EditorChapterPanel p = this.viewer.getEditorForChapter (c); + + p.getEditor ().moveTo (c.getEditPosition ()); + p.getEditor ().requestFollowCaret (); + + }); + + }) + .build ()); + + its.add (QuollMenuItem.builder () + .label (getUILanguageStringProperty (Utils.newList (prefix,removeeditposition))) + .iconName (StyleClassNames.REMOVEEDITPOSITION) + .onAction (ev -> + { + + this.viewer.removeChapterEditPosition (c); + + }) + .build ()); + + } + + if (this.viewer.isEditing (c)) + { + + its.add (QuollMenuItem.builder () + .label (getUILanguageStringProperty (Utils.newList (prefix,close))) + .iconName (StyleClassNames.CLOSE) + .onAction (ev -> + { + + this.viewer.runCommand (ProjectViewer.CommandId.closepanel, + c); + + }) + .build ()); + + } + + } + + return its; + + }) + .build (); + + this.selectItem (); + + } + + private void selectItem () + { + + this.tree.select (null); + this.tree.requestLayout (); + + Panel p = this.viewer.getCurrentPanel (); + + if (p == null) + { + + return; + + } + + if (p != null) + { + + if (p.getContent () instanceof NamedObjectPanelContent) + { + + NamedObjectPanelContent nc = (NamedObjectPanelContent) p.getContent (); + + if (nc.getObject () instanceof Chapter) + { + + this.tree.select ((Chapter) nc.getObject ()); + this.tree.requestLayout (); + + return; + + } + + } + + } + + } + + private void removeListenersForChapter (Chapter c) + { + + if (this.eventSourceSubscriptions.get (c) != null) + { + + this.eventSourceSubscriptions.get (c).stream () + .forEach (s -> s.unsubscribe ()); + + this.eventSourceSubscriptions.remove (c); + + } + + } + + private void updateChapterLabel (Chapter c, + Label l) + { + + l.textProperty ().unbind (); + + String v = "%1$s (%2$s)"; + + l.setText (String.format (v, + c.getName (), + Environment.formatNumber (c.getNotes ().size ()))); + + //l.setAccessibleText ("TEXTING");//l.getText ()); + + + } + + private void addListenersForChapter (Chapter c) + { + + List subs = new ArrayList<> (); + + subs.add (c.chapterItemsEvents ().subscribe (ev -> + { + + if (ev.getType () == CollectionEvent.Type.remove) + { + + // Remove the item. + this.tree.removeObject (ev.getSource ()); + + } + + if (ev.getType () == CollectionEvent.Type.add) + { + + ChapterItem ci = ev.getSource (); + + TreeItem pti = this.tree.getTreeItemForObject (ci.getChapter ()); + + int ind = new ArrayList (c.getNotes ()).indexOf (ci); + + TreeItem ti = new TreeItem<> (ci); + + if (ind < 0) + { + + ind = 0; + + } + + pti.getChildren ().add (ind, + ti); + + } + + })); + + this.eventSourceSubscriptions.put (c, + subs); + } + + private ChapterItem getChapterItemBefore (ChapterItem ci) + { + + Set items = new TreeSet (Collections.reverseOrder (new ChapterItemSorter ())); + + int start = 0; + int end = ci.getEndPosition (); + Chapter ch = ci.getChapter (); + + if (ci instanceof Note) + { + + for (Note n : ch.getNotes ()) + { + + if ((n.getPosition () >= start) + && + (n.getPosition () <= end) + ) + { + + items.add (n); + + } + + } + + } + + if (items.size () > 0) + { + + return items.iterator ().next (); + + } + + return null; + + } + + private void selectChapter (Chapter c) + { + + this.tree.select (c); + + } + + @Override + public boolean canImport (NamedObject o) + { + + return false; + + } + + @Override + public void importObject (NamedObject o) + { + + new IllegalStateException ("Shouldnt be possible."); + + } + + @Override + public Node getContent () + { + + return this.tree; + + } + + @Override + public List getStyleClassNames () + { + + return Arrays.asList (StyleClassNames.CHAPTER); + + } + + @Override + public StringProperty getTitle () + { + + return Environment.getObjectTypeNamePlural (Chapter.OBJECT_TYPE); + + } + + @Override + public String getId () + { + + return Chapter.OBJECT_TYPE; + + } + + @Override + public void init (State ss) + { + + super.init (ss); + + if (ss != null) + { + + String exp = ss.getAsString ("expanded"); + + if (exp != null) + { + + Arrays.stream (exp.split (",")) + .forEach (v -> + { + + NamedObject o = this.getObjectForReference (v); + + if (o != null) + { + + TreeItem ti = this.tree.getTreeItemForObject (o); + + if (ti != null) + { + + ti.setExpanded (true); + + } + + } + + }); + + } + + } + + } + + @Override + public BooleanProperty showItemCountOnHeader () + { + + // TODO Make a style? + return new SimpleBooleanProperty (true); + + } + + @Override + public State getState () + { + + State ss = super.getState (); + + if (ss == null) + { + + ss = new State (); + + } + + ss.set ("expanded", + this.tree.getExpandedTreeItems ().stream () + .map (ti -> ti.getValue ().getObjectReference ().asString ()) + .collect (Collectors.joining (","))); + + return ss; + + } + + @Override + public Supplier> getHeaderContextMenuItemSupplier () + { + + List prefix = Arrays.asList (project,sidebar,chapters,headerpopupmenu,items); + + return () -> + { + + Set items = new LinkedHashSet<> (); + + return items; + + }; + + } + + private TreeItem createTreeItem (Chapter c) + { + + TreeItem ci = new TreeItem<> (c); + + ci.getChildren ().addAll (c.getNotes ().stream () + .map (n -> new TreeItem (n)) + .collect (Collectors.toList ())); + + return ci; + + } + + private TreeItem createTree () + { + + List objs = new ArrayList<> (this.viewer.getProject ().getBooks ().get (0).getChapters ()); + + TreeItem root = new TreeItem<> (this.viewer.getProject ()); + + for (Chapter c : objs) + { + + root.getChildren ().add (this.createTreeItem (c)); + + } + + this.countProp.setValue (objs.size ()); + + return root; + + } + + @Override + public IntegerProperty getItemCount () + { + + return this.countProp; + + } + + public NamedObject getObjectForReference (String s) + { + + if (s == null) + { + + return null; + + } + + if (s.startsWith (NoteTreeLabel.OBJECT_TYPE)) + { + + int ind = s.indexOf ("-"); + + if (ind > -1) + { + + s = s.substring (0, + ind); + + } + + StringTokenizer t = new StringTokenizer (s, + "/"); + + t.nextToken (); + + String k = t.nextToken (); + + try + { + + Chapter c = this.viewer.getProject ().getChapterByKey (Long.parseLong (k)); + + if (c != null) + { + + return this.noteTreeLabels.get (c); + + } + + } catch (Exception e) { + + } + + return null; + + } + + ObjectReference ref = ObjectReference.parseObjectReference (s); + + return (NamedObject) this.viewer.getProject ().getObjectForReference (ref); + + } + + private static class NoteTreeLabel extends BlankNamedObject + { + + public static final String OBJECT_TYPE = "notetreelabel"; + + public Chapter chapter = null; + public IPropertyBinder.ListenerHandle listenerHandle = null; + + public NoteTreeLabel (Chapter c) + { + + super (OBJECT_TYPE, + "note-tree-label"); + + this.chapter = c; + + } + + @Override + public boolean equals (Object o) + { + + if (o instanceof NoteTreeLabel) + { + + NoteTreeLabel no = (NoteTreeLabel) o; + + if (no.chapter.equals (this.chapter)) + { + + return true; + + } + + } + + return false; + + } + + @Override + public int hashCode () + { + + return Objects.hash (this.getName (), this.chapter); + + } + + @Override + public ObjectReference getObjectReference () + { + + return new ObjectReference (this.getObjectType () + "/" + this.chapter.getKey (), + 1L, + this.chapter.getObjectReference ()); + + } + + } + +} diff --git a/src/main/java/com/quollwriter/editors/ui/EditorChatBox.java b/src/main/java/com/quollwriter/editors/ui/EditorChatBox.java new file mode 100644 index 00000000..98a2cee7 --- /dev/null +++ b/src/main/java/com/quollwriter/editors/ui/EditorChatBox.java @@ -0,0 +1,269 @@ +package com.quollwriter.editors.ui; + +import java.util.*; +import java.util.concurrent.*; + +import javafx.scene.layout.*; +import javafx.scene.control.*; + +import com.quollwriter.data.editors.*; +import com.quollwriter.events.*; +import com.quollwriter.editors.*; +import com.quollwriter.*; +import com.quollwriter.editors.messages.*; +import com.quollwriter.ui.fx.viewers.*; +import com.quollwriter.ui.fx.components.*; +import com.quollwriter.ui.fx.*; + +import static com.quollwriter.LanguageStrings.*; +import static com.quollwriter.uistrings.UILanguageStringsManager.getUILanguageStringProperty; + +public class EditorChatBox extends VBox implements EditorInteractionListener +{ + + private EditorEditor editor = null; + private AbstractViewer viewer = null; + private boolean typingStartedSent = false; + private Label notification = null; + private QuollTextArea message = null; + private ScheduledFuture typingStop = null; + private ScheduledFuture typingStart = null; + + public EditorChatBox (EditorEditor ed, + AbstractViewer viewer) + { + + EditorChatBox _this = this; + + this.editor = ed; + this.viewer = viewer; + this.getStyleClass ().add (StyleClassNames.CHATBOX); + + EditorsEnvironment.addEditorInteractionListener (this); + + this.message = QuollTextArea.builder () + .placeholder (getUILanguageStringProperty (editors,LanguageStrings.editor,sendchat,box,tooltip)) + .build (); + + this.message.setOnTextKeyReleased (ev -> + { + + if (this.typingStop != null) + { + + this.typingStop.cancel (true); + + } + + if (this.typingStart != null) + { + + this.typingStart.cancel (true); + + } + + this.typingStart = Environment.schedule (() -> + { + + if (!_this.typingStartedSent) + { + + _this.typingStartedSent = true; + + // Send the message. + _this.sendStartedTyping (); + + } + + }, + 50, + -1); + + this.typingStop = Environment.schedule (() -> + { + + _this.typingStartedSent = false; + + // Send stopped message. + _this.sendStoppedTyping (); + + }, + 750, + -1); + + }); + + this.notification = QuollLabel.builder () + .styleClassName (StyleClassNames.LOADING) + .label (editors,LanguageStrings.editor,sendchat,sending) + .build (); + HBox.setHgrow (this.notification, + Priority.ALWAYS); + + Runnable sendMessage = () -> + { + + String text = _this.message.getText ().trim (); + + if (text.length () == 0) + { + + return; + + } + + this.notification.textProperty ().unbind (); + this.notification.textProperty ().bind (getUILanguageStringProperty (editors,LanguageStrings.editor,sendchat,sending)); + this.notification.setVisible (true); + HBox.setHgrow (this.notification, + Priority.ALWAYS); + + // Add the message to the today list. + final Date when = new Date (); + + final Date w = Utils.zeroTimeFields (when); + + final EditorChatMessage m = new EditorChatMessage (text, + true, + _this.editor, + when); + + m.setDealtWith (true); + + this.sendStoppedTyping (); + + EditorsEnvironment.sendMessageToEditor (m, + () -> + { + + UIUtils.runLater (() -> + { + + _this.notification.setVisible (false); + + _this.message.setText (""); + _this.message.requestFocus (); + + }); + + }, + () -> + { + + _this.notification.setVisible (false); + + }, + null); + + }; + + UIUtils.addDoOnReturnPressed (this.message, + sendMessage); + + Button save = QuollButton.builder () + .iconName (StyleClassNames.SEND) + .tooltip (editors,LanguageStrings.editor,sendchat,box,buttons,send,tooltip) + .onAction (ev -> + { + + UIUtils.runLater (sendMessage); + + }) + .build (); + + Button cancel = QuollButton.builder () + .iconName (StyleClassNames.CANCEL) + .tooltip (editors,LanguageStrings.editor,sendchat,box,buttons,LanguageStrings.cancel,tooltip) + .onAction (ev -> + { + + this.message.setText (""); + + }) + .build (); + + HBox buts = new HBox (); + buts.getStyleClass ().addAll (StyleClassNames.BUTTONS, "controls", "tool-bar"); + buts.getChildren ().addAll (this.notification, save, cancel); + + this.getChildren ().addAll (this.message, buts); + + } + + @Override + public void handleInteraction (EditorInteractionEvent ev) + { + + if (this.editor != ev.getEditor ()) + { + + return; + + } + + if (ev.getAction () == InteractionMessage.Action.typing) + { + + this.showTyping (); + + } + + if (ev.getAction () == InteractionMessage.Action.normal) + { + + this.notification.setVisible (false); + + } + + } + + public void requestFocus () + { + + this.message.requestFocus (); + + } + + private void showTyping () + { + + this.notification.textProperty ().unbind (); + this.notification.textProperty ().bind (getUILanguageStringProperty (Arrays.asList (editors,LanguageStrings.editor,sendchat,contactistyping), + this.editor.mainNameProperty ())); + //this.editor.getShortName () + " is typing..."); + this.notification.getStyleClass ().clear (); + this.notification.getStyleClass ().addAll (StyleClassNames.NOTIFICATION, StyleClassNames.TYPING); + this.notification.setVisible (true); + + } + + private void showSending () + { + + this.notification.textProperty ().unbind (); + this.notification.textProperty ().bind (getUILanguageStringProperty (Arrays.asList (editors,LanguageStrings.editor,sendchat,sending))); + this.notification.getStyleClass ().clear (); + this.notification.getStyleClass ().addAll (StyleClassNames.NOTIFICATION, StyleClassNames.SENDING); + this.notification.setVisible (true); + + } + + private void sendStartedTyping () + { + + EditorsEnvironment.sendInteractionMessageToEditor (InteractionMessage.Action.typing, + this.editor, + null); + + } + + private void sendStoppedTyping () + { + + EditorsEnvironment.sendInteractionMessageToEditor (InteractionMessage.Action.normal, + this.editor, + null); + + } + +} diff --git a/src/main/java/com/quollwriter/editors/ui/EditorInfoBox.java b/src/main/java/com/quollwriter/editors/ui/EditorInfoBox.java new file mode 100644 index 00000000..b42dbe53 --- /dev/null +++ b/src/main/java/com/quollwriter/editors/ui/EditorInfoBox.java @@ -0,0 +1,2284 @@ +package com.quollwriter.editors.ui; + +import java.awt.image.*; + +import java.util.*; +import java.io.*; + +import javafx.beans.property.*; +import javafx.scene.control.*; +import javafx.scene.layout.*; +import javafx.scene.image.*; +import javafx.embed.swing.*; + +import com.quollwriter.*; +import com.quollwriter.data.*; +import com.quollwriter.data.editors.*; +import com.quollwriter.events.*; +import com.quollwriter.editors.ui.*; +import com.quollwriter.editors.*; +//import com.quollwriter.editors.ui.sidebars.*; +import com.quollwriter.editors.messages.*; +import com.quollwriter.ui.fx.*; +import com.quollwriter.ui.fx.components.*; +import com.quollwriter.ui.fx.viewers.*; + +import static com.quollwriter.LanguageStrings.*; +import static com.quollwriter.uistrings.UILanguageStringsManager.getUILanguageStringProperty; + +public class EditorInfoBox extends VBox +{ + + private EditorEditor editor = null; + private AbstractViewer viewer = null; + private Pane avatar = null; + private HBox avatarBox = null; + private QuollLabel mainName = null; + private IconBox onlineStatus = null; + private QuollLabel other = null; + private VBox details = null; + private HBox editorInfo = null; + private QuollButton projectMessages = null; + private QuollButton importantMessages = null; + private QuollButton comments = null; + private QuollButton chat = null; + private boolean showProjectInfo = false; + private ProjectEditor projEditor = null; + private Project proj = null; + private boolean editorProject = false; + + public EditorInfoBox (EditorEditor ed, + AbstractViewer viewer, + boolean showProjectInfo, + IPropertyBinder binder) + //throws GeneralException + { + + final EditorInfoBox _this = this; + + this.editor = ed; + + UIUtils.addStyleSheet (this, + Constants.COMPONENT_STYLESHEET_TYPE, + StyleClassNames.CONTACT); + + this.setFillWidth (true); + this.getStyleClass ().add (StyleClassNames.CONTACT); + this.showProjectInfo = showProjectInfo; + + if ((this.showProjectInfo) + && + (!(viewer instanceof AbstractProjectViewer)) + ) + { + + throw new IllegalArgumentException ("To show project information a project viewer must be provided."); + + } + + if (viewer instanceof AbstractProjectViewer) + { + + this.proj = ((AbstractProjectViewer) viewer).getProject (); + + this.editorProject = this.proj.isEditorProject (); + + } + + this.loadMessagesForEditor (); + + // We add ourselves as a listener for editor change events however we don't ever + // remove ourselves since, as a standard component, we don't have a fixed lifecycle. + //EditorsEnvironment.addEditorChangedListener (this); + + //EditorsEnvironment.addEditorMessageListener (this); + + binder.addSetChangeListener (this.editor.getMessages (), + ev -> + { + + this.updateButtons (); + + }); + + binder.addChangeListener (this.editor.messagesUpdatedProperty (), + (pr, oldv, newv) -> + { + + this.updateButtons (); + + }); + + this.viewer = viewer; + + if (this.viewer instanceof AbstractProjectViewer) + { + + this.projEditor = ((AbstractProjectViewer) this.viewer).getProject ().getProjectEditor (this.editor); + + } + + binder.addChangeListener (ed.editorStatusProperty (), + (pr, oldv, newv) -> + { + + this.updateForEditorStatus (); + + }); + + this.editorInfo = new HBox (); + /* + HBox.setHgrow (this.editorInfo, + Priority.ALWAYS); +*/ + this.setOnMouseReleased (ev -> + { + + if (this.getProperties ().get ("context-menu") != null) + { + + ((ContextMenu) this.getProperties ().get ("context-menu")).hide (); + + } + + if ((ev.isPopupTrigger ()) + || + (this.editor.isPending ()) + ) + { + + return; + + } + + // Show the editor. + try + { + + this.viewer.sendMessageToEditor (this.editor); + + } catch (Exception e) { + + Environment.logError ("Unable to show editor: " + + this.editor, + e); + + ComponentUtils.showErrorMessage (this.viewer, + getUILanguageStringProperty (editors,LanguageStrings.editor,view,actionerror)); + //"Unable to show {editor}."); + + } + + }); + + this.avatarBox = IconBox.builder () + .styleClassName ("avatar-box") + .image (this.editor.mainAvatarProperty ()) + .onNoImage (b -> + { + + if (this.avatarBox != null) + { + + this.avatarBox.pseudoClassStateChanged (StyleClassNames.NOAVATAR_PSEUDO_CLASS, true); + + } + + }) + .onImagePresent (b -> + { + + if (this.avatarBox != null) + { + + this.avatarBox.pseudoClassStateChanged (StyleClassNames.NOAVATAR_PSEUDO_CLASS, false); + + } + + }) + .build (); + + this.avatarBox.pseudoClassStateChanged (StyleClassNames.NOAVATAR_PSEUDO_CLASS, this.editor.getMainAvatar () == null); + +/* + this.avatar = new ImageView (); + this.avatar.setPreserveRatio (true); + this.avatar.setSmooth (true); + this.avatar.getStyleClass ().add (StyleClassNames.AVATAR); +*/ + //this.updateAvatar (); +/* + VBox p = new VBox (); + p.getStyleClass ().add ("avatar-box"); + p.getChildren ().add (this.avatar); + + p.widthProperty ().addListener ((pr, oldv, newv) -> + { + + this.avatar.setFitWidth (Math.round (newv.doubleValue ()) - p.getInsets ().getLeft () - p.getInsets ().getRight ()); + + UIUtils.runLater (() -> + { + + this.requestLayout (); + + }); + + }); +*/ +/* + binder.addChangeListener (ed.mainAvatarProperty (), + (pr, oldv, newv) -> + { + + this.updateAvatar (); + + }); +*/ + final boolean pending = ed.isPending (); + + this.details = new VBox (); + + StringProperty nameProp = new SimpleStringProperty (); + + this.mainName = QuollLabel.builder () + .label (nameProp) + .styleClassName (StyleClassNames.NAME) + .build (); + + nameProp.setValue (ed.getMainName ()); + + binder.addChangeListener (ed.mainNameProperty (), + (pr, oldv, newv) -> + { + + nameProp.setValue (ed.getMainName ()); + + }); + + this.other = QuollLabel.builder () + .styleClassName (StyleClassNames.OTHER) + .build (); + + this.onlineStatus = IconBox.builder () + .styleClassName (StyleClassNames.ONLINESTATUS) + .build (); + + binder.addChangeListener (ed.onlineStatusProperty (), + (pr, oldv, newv) -> + { + + this.updateForOnlineStatus (); + + }); + + this.editorInfo.getChildren ().addAll (this.avatarBox, this.details); + this.updateForEditorStatus (); + this.updateForOnlineStatus (); + + // Create the buttons. + this.projectMessages = QuollButton.builder () + .iconName (Project.OBJECT_TYPE) + .onAction (ev -> + { + + try + { + + EditorsUIUtils.showProjectMessagesForEditor (this.editor, + (AbstractProjectViewer) this.viewer, + this.projectMessages); + + } catch (Exception e) { + + Environment.logError ("Unable to show project messages for editor: " + + this.editor, + e); + + ComponentUtils.showErrorMessage (viewer, + getUILanguageStringProperty (editors,messages,show,project,actionerror)); + //"Unable to show {project} messages for {editor}."); + + } + + }) + .build (); + + this.importantMessages = QuollButton.builder () + .iconName (StyleClassNames.IMPORTANT) + .onAction (ev -> + { + + try + { + + EditorsUIUtils.showImportantMessagesForEditor (this.editor, + this.viewer, + this.importantMessages); + + } catch (Exception e) { + + Environment.logError ("Unable to show important messages for editor: " + + this.editor, + e); + + ComponentUtils.showErrorMessage (this.viewer, + getUILanguageStringProperty (editors,messages,show,important,actionerror)); + //"Unable to show important messages for {editor}."); + + } + + }) + .build (); + + this.comments = QuollButton.builder () + .iconName (StyleClassNames.COMMENT) + .onAction (ev -> + { + + try + { + + EditorsUIUtils.showAllCommentsForEditor (this.editor, + (AbstractProjectViewer) this.viewer, + this.comments); + + } catch (Exception e) { + + Environment.logError ("Unable to show comments for editor: " + + this.editor, + e); + + ComponentUtils.showErrorMessage (this.viewer, + getUILanguageStringProperty (editors,LanguageStrings.editor,view,actionerror)); + //"Unable to show {comments} for {editor}."); + + } + + }) + .build (); + + this.chat = QuollButton.builder () + .iconName (StyleClassNames.MESSAGE) + .onAction (ev -> + { + + try + { + + this.viewer.sendMessageToEditor (this.editor); + + } catch (Exception e) { + + Environment.logError ("Unable to show editor: " + + this.editor, + e); + + ComponentUtils.showErrorMessage (this.viewer, + getUILanguageStringProperty (editors,LanguageStrings.editor,view,actionerror)); + //"Unable to show {editor}."); + + } + + }) + .build (); + + QuollToolBar tb = QuollToolBar.builder () + .styleClassName (StyleClassNames.STATUSBAR) + .controls (Arrays.asList (this.onlineStatus, + this.importantMessages, + this.comments, + this.projectMessages, + this.chat)) + .build (); + + this.details.getChildren ().addAll (this.mainName, this.other, tb); + + this.getChildren ().add (this.editorInfo); + + this.updateButtons (); + + this.addFullPopupListener (); + + } +/* + private void updateAvatar () + { + + if (this.editor.getMainAvatar () != null) + { + + this.avatar.setBackground (new Background (new BackgroundImage (this.editor.getMainAvatar (), //SwingFXUtils.toFXImage (this.editor.getMainAvatar (), null), + BackgroundRepeat.NO_REPEAT, + BackgroundRepeat.NO_REPEAT, + BackgroundPosition.CENTER, + new BackgroundSize (100, 100, true, true, true, false)))); + + this.avatarBox.pseudoClassStateChanged (StyleClassNames.NOAVATAR_PSEUDO_CLASS, false); + + } else { + + this.avatar.setBackground (null); + this.avatarBox.pseudoClassStateChanged (StyleClassNames.NOAVATAR_PSEUDO_CLASS, true); + + } + + } +*/ + + private void updateButtons () + { + + UIUtils.runLater (() -> + { + + this.updateButtons_int (); + + }); + + } + + private void updateButtons_int () + { + + Set mess = this.getImportantMessages (); + + this.importantMessages.setVisible (false); + int ms = mess.size (); + + if (ms > 0) + { + + this.projectMessages.pseudoClassStateChanged (StyleClassNames.UNDEALTWITH_PSEUDO_CLASS, true); + + UIUtils.setTooltip (this.importantMessages, + getUILanguageStringProperty (Arrays.asList (editors,LanguageStrings.editor,view,importantmessages,tooltip), + //"%s new/important message%s requiring your attention, click to view them", + Environment.formatNumber (ms))); + //(ms == 1 ? "" : "s"), + //(ms == 1 ? "s" : ""))); + + this.importantMessages.setText (String.format ("%s", + Environment.formatNumber (ms))); + + this.importantMessages.setVisible (true); + + } + + this.projectMessages.setVisible (false); + if ((this.showProjectInfo) + && + ((this.projEditor != null) + || + (this.editorProject) + ) + ) + { + + int undealtWithCount = 0; + + // Get undealt with messages that are not chat. + // If there is just one then show it, otherwise show a link that will display a popup of them. + Set projMess = this.getProjectMessages (); + + for (EditorMessage em : projMess) + { + + if (!em.isDealtWith ()) + { + + undealtWithCount++; + + } + + } + + int ps = projMess.size (); + + this.projectMessages.pseudoClassStateChanged (StyleClassNames.UNDEALTWITH_PSEUDO_CLASS, (undealtWithCount > 0)); + + if (undealtWithCount > 0) + { + + UIUtils.setTooltip (this.projectMessages, + getUILanguageStringProperty (Arrays.asList (editors,LanguageStrings.editor,view,projecteditor,undealtwithmessagecount,tooltip), + //"%s {project} message%s requiring your attention, click to view them", + Environment.formatNumber (undealtWithCount))); + //(undealtWithCount == 1 ? "" : "s"), + //(undealtWithCount == 1 ? "s" : ""))); + + } else { + + UIUtils.setTooltip (this.projectMessages, + getUILanguageStringProperty (Arrays.asList (editors,LanguageStrings.editor,view,projecteditor,undealtwithmessagecount,tooltip), + //"%s {project} message%s, click to view them", + Environment.formatNumber (ps))); + //(projMess.size () == 1 ? "" : "s"), + //(projMess.size () == 1 ? "s" : ""))); + + } + + this.projectMessages.setText (String.format ("%s", + Environment.formatNumber (ps))); + + this.projectMessages.setVisible (true); + + } + + this.comments.setVisible (false); + + if (this.showProjectInfo) + { + + AbstractProjectViewer pv = (AbstractProjectViewer) this.viewer; + + int commCount = 0; + + if (!this.editor.isPending ()) + { + + this.comments.setVisible (true); + + // Get undealt with messages that are not chat. + // If there is just one then show it, otherwise show a link that will display a popup of them. + Set comments = this.editor.getMessages (new DefaultEditorMessageFilter (pv.getProject (), + ProjectCommentsMessage.MESSAGE_TYPE)); + + if (comments.size () > 0) + { + + int sets = comments.size (); + int undealtWithCount = 0; + + for (EditorMessage m : comments) + { + + if (!m.isDealtWith ()) + { + + undealtWithCount++; + + + } + + ProjectCommentsMessage pcm = (ProjectCommentsMessage) m; + + commCount += pcm.getComments ().size (); + + } + + this.projectMessages.pseudoClassStateChanged (StyleClassNames.UNDEALTWITH_PSEUDO_CLASS, (undealtWithCount > 0)); + + UIUtils.setTooltip (this.comments, + getUILanguageStringProperty (Arrays.asList (editors,LanguageStrings.editor,view,projectcomments,(this.projEditor != null ? received : sent),tooltip), + //"%s {comment%s} %s %s", + Environment.formatNumber (commCount), + //(commCount == 1 ? "" : "s"), + //(this.projEditor != null ? "from" : "sent to"), + this.editor.mainNameProperty ())); + + } else { + + if (this.projEditor != null) + { + + UIUtils.setTooltip (this.comments, + getUILanguageStringProperty (Arrays.asList (editors,LanguageStrings.editor,view,noprojectcomments,received,tooltip), + //"%s has not sent you any {comments} yet.", + this.editor.mainNameProperty ())); + + } else { + + UIUtils.setTooltip (this.comments, + getUILanguageStringProperty (Arrays.asList (editors,LanguageStrings.editor,view,noprojectcomments,sent,tooltip), + //"You have not sent any {comments} to %s yet.", + this.editor.mainNameProperty ())); + + } + + } + + this.comments.setText (Environment.formatNumber (commCount)); + + this.comments.setDisable (commCount == 0); + + } + + } + + this.chat.setVisible (false); + + Set chatMessages = this.getChatMessages (); + + int chatMessagesSize = chatMessages.size (); + + if (chatMessagesSize > 0) + { + + this.chat.pseudoClassStateChanged (StyleClassNames.UNDEALTWITH_PSEUDO_CLASS, true); + + UIUtils.setTooltip (this.chat, + getUILanguageStringProperty (Arrays.asList (editors,LanguageStrings.editor,view,unreadchatmessages,tooltip), + //"%s unread chat message%s", + Environment.formatNumber (chatMessagesSize))); + + this.chat.setText (Environment.formatNumber (chatMessagesSize)); + + this.chat.setVisible (true); + + } + + } + + private void updateForOnlineStatus () + { + + if (this.editor.isPending ()) + { + + this.onlineStatus.setVisible (false); + return; + + } + + this.onlineStatus.setVisible (true); + + if (this.editor.getOnlineStatus () != null) + { + + //this.onlineStatus.getStyleClass ().addAll (this.editor.getOnlineStatus ().getType () + "-icon"); + UIUtils.setTooltip (this.onlineStatus, + this.editor.getOnlineStatus ().nameProperty ()); + this.onlineStatus.setIconName (this.editor.getOnlineStatus ().getType ()); + + } else { + + //this.onlineStatus.getStyleClass ().add (EditorEditor.OnlineStatus.offline.getType () + "-icon"); + UIUtils.setTooltip (this.onlineStatus, + EditorEditor.OnlineStatus.offline.nameProperty ()); + this.onlineStatus.setIconName (EditorEditor.OnlineStatus.offline.getType ()); + + } + + } + + private void updateForEditorStatus () + { + + this.other.setVisible (false); + UIUtils.setTooltip (this.editorInfo, + null); + + if ((this.showProjectInfo) + && + (this.projEditor != null) + ) + { + + this.other.setVisible (true); + this.other.textProperty ().unbind (); + this.other.textProperty ().bind (this.projEditor.statusMessageProperty ()); + + } + + if (!this.editor.isPending ()) + { + + if (!this.editor.isPrevious ()) + { + + UIUtils.setTooltip (this.editorInfo, + getUILanguageStringProperty (Arrays.asList (editors,LanguageStrings.editor,view,info,tooltip,currenteditor), + //"Click to send a message to %s, right click to see the menu", + this.editor.getMainName ())); + + } else { + + UIUtils.setTooltip (this.editorInfo, + getUILanguageStringProperty (editors,LanguageStrings.editor,view,info,tooltip,previouseditor)); + + } + + } else { + + if (!this.editor.isInvitedByMe ()) + { + + this.other.textProperty ().unbind (); + this.other.textProperty ().bind (getUILanguageStringProperty (Arrays.asList (editors,LanguageStrings.editor,view,LanguageStrings.other,pendingeditor,invitereceived), + //"Received: %s", + Environment.formatDate (this.editor.getDateCreated ()))); + + } else { + + this.other.textProperty ().unbind (); + this.other.textProperty ().bind (getUILanguageStringProperty (Arrays.asList (editors,LanguageStrings.editor,view,LanguageStrings.other,pendingeditor,invitesent), + //"Invited: %s", + Environment.formatDate (this.editor.getDateCreated ()))); + + } + + this.other.setVisible (true); + + } + + } + + public boolean isShowProjectInfo () + { + + return this.showProjectInfo; + + } + + private boolean isShowAttentionBorder () + { + + final EditorInfoBox _this = this; + + // TODO: Investigate why this is needed, this is being called on closedown of QW. + // Probably from close of link to message server. + if (this.viewer instanceof AbstractProjectViewer) + { + + if (((AbstractProjectViewer) this.viewer).getProject () == null) + { + + return false; + + } + + } + + if (this.editor.isPrevious ()) + { + + return false; + + } + + return this.editor.getMessages (EditorsUIUtils.getImportantMessageFilter ()).size () > 0; + + } + + private Set getProjectComments () + { + + return this.editor.getMessages (new DefaultEditorMessageFilter (this.proj, + ProjectCommentsMessage.MESSAGE_TYPE)); + + } + + private Set getChatMessages () + { + + return this.editor.getMessages (new EditorMessageFilter () + { + + @Override + public boolean accept (EditorMessage m) + { + + if ((m.getMessageType ().equals (EditorChatMessage.MESSAGE_TYPE)) + && + (!m.isDealtWith ()) + ) + { + + return true; + + } + + return false; + + } + + }); + + } + + private Set getProjectMessages () + { + + final EditorInfoBox _this = this; + + final String projId = this.proj.getId (); + + return this.editor.getMessages (new EditorMessageFilter () + { + + @Override + public boolean accept (EditorMessage m) + { + + if (!projId.equals (m.getForProjectId ())) + { + + return false; + + } + + if ((m.getMessageType ().equals (NewProjectMessage.MESSAGE_TYPE)) + || + (m.getMessageType ().equals (NewProjectResponseMessage.MESSAGE_TYPE)) + || + (m.getMessageType ().equals (UpdateProjectMessage.MESSAGE_TYPE)) + || + (m.getMessageType ().equals (ProjectEditStopMessage.MESSAGE_TYPE)) + ) + { + + return true; + + } + + return false; + + } + + }); + + } + + private Set getImportantMessages () + { + + if (this.editor.isPrevious ()) + { + + return new HashSet (); + + } + + final EditorInfoBox _this = this; + + String _projId = ""; + + if (this.proj != null) + { + + _projId = this.proj.getId (); + + } + + final String projId = _projId; + + Set mess = this.editor.getMessages (m -> + { + + if (!EditorsUIUtils.getImportantMessageFilter ().accept (m)) + { + + return false; + + } + + if (m.getMessageType ().equals (EditorChatMessage.MESSAGE_TYPE)) + { + + return false; + + } + + if (_this.showProjectInfo) + { + + if (projId.equals (m.getForProjectId ())) + { + + return false; + + } + + } + + return true; + + }); + + return mess; + + } + public ProjectEditor getProjectEditor () + { + + return this.projEditor; + + + } + public EditorEditor getEditor () + { + + return this.editor; + + } + +/* + private void update () + { + + if (this.proj != null) + { + + // TODO: Fix this. + if (((AbstractProjectViewer) this.viewer).getProject () == null) + { + + // We are closing down. + return; + + } + + } + + this.onlineStatus.setVisible (false); + this.other.setVisible (false); + this.projectMessages.setVisible (false); + this.importantMessages.setVisible (false); + + this.mainName.setText (this.editor.getMainName ()); + + BufferedImage bi = null; + + if (this.editor.getMainAvatar () != null) + { + + bi = UIUtils.getScaledImage (this.editor.getMainAvatar (), + 50); + + } else { + + bi = Environment.getNoEditorAvatarImage (); + + } + + this.avatar.setIcon (new ImageIcon (bi)); + + if (this.editor.getOnlineStatus () != null) + { + + String type = Constants.ONLINE_STATUS_ICON_NAME_PREFIX + this.editor.getOnlineStatus ().getType (); + + this.onlineStatus.setIcon (Environment.getIcon (type, + Constants.ICON_MENU_INNER)); + this.onlineStatus.setToolTipText (this.editor.getOnlineStatus ().getName ()); + //this.onlineStatus.setText (this.editor.getOnlineStatus ().getName ()); + this.onlineStatus.setText (""); + this.onlineStatus.setVisible (true); + this.onlineStatus.setMaximumSize (this.onlineStatus.getPreferredSize ()); + + } + + if (!this.editor.isPending ()) + { + + UIUtils.setAsButton (this.editorInfo); + + if (!this.editor.isPrevious ()) + { + + this.editorInfo.setToolTipText (String.format (getUIString (editors,LanguageStrings.editor,view,info,tooltip,currenteditor), + //"Click to send a message to %s, right click to see the menu", + this.editor.getMainName ())); + + } else { + + this.editorInfo.setToolTipText (getUIString (editors,LanguageStrings.editor,view,info,tooltip,previouseditor)); + //"Right click to see the menu"); + + } + + } else { + + if (!this.editor.isInvitedByMe ()) + { + + this.other.setText (String.format (getUIString (editors,LanguageStrings.editor,view,LanguageStrings.other,pendingeditor,invitereceived), + //"Received: %s", + Environment.formatDate (this.editor.getDateCreated ()))); + + } else { + + this.other.setText (String.format (getUIString (editors,LanguageStrings.editor,view,LanguageStrings.other,pendingeditor,invitesent), + //"Invited: %s", + Environment.formatDate (this.editor.getDateCreated ()))); + + } + + this.other.setVisible (true); + + } + + //final String projId = this.projectViewer.getProject ().getId (); + + Set mess = this.getImportantMessages (); + + int ms = mess.size (); + + this.importantMessages.setForeground (java.awt.Color.black); + + if (ms > 0) + { + + this.importantMessages.setForeground (java.awt.Color.red); + + this.importantMessages.setToolTipText (String.format (getUIString (editors,LanguageStrings.editor,view,importantmessages,tooltip), + //"%s new/important message%s requiring your attention, click to view them", + Environment.formatNumber (ms))); + //(ms == 1 ? "" : "s"), + //(ms == 1 ? "s" : ""))); + + this.importantMessages.setText (String.format ("%s", + Environment.formatNumber (ms))); + + this.importantMessages.setVisible (true); + + } + + //if (this.editor.isPending ()) + //{ + + // this.importantMessages.setVisible (false); + + //} + + + if (this.editor.isPrevious ()) + { + + this.onlineStatus.setIcon (Environment.getIcon (Constants.ERROR_RED_ICON_NAME, + Constants.ICON_MENU_INNER)); + this.onlineStatus.setToolTipText (getUIString (editors,LanguageStrings.editor,view,previouseditor,onlinestatus,tooltip)); + //"This is a previous {contact}.")); + this.onlineStatus.setText (""); + this.onlineStatus.setMaximumSize (this.onlineStatus.getPreferredSize ()); + + this.onlineStatus.setVisible (true); + + } + + if ((this.showProjectInfo) + && + ((this.projEditor != null) + || + (this.editorProject) + ) + ) + { + + if (this.projEditor != null) + { + + this.other.setVisible (true); + xxx do this + this.other.setText (Environment.replaceObjectNames (this.projEditor.getStatusMessage ())); + + } + + int undealtWithCount = 0; + + // Get undealt with messages that are not chat. + // If there is just one then show it, otherwise show a link that will display a popup of them. + Set projMess = this.getProjectMessages (); + + for (EditorMessage em : projMess) + { + + if (!em.isDealtWith ()) + { + + undealtWithCount++; + + } + + } + + int ps = projMess.size (); + + this.projectMessages.setForeground (java.awt.Color.black); + + if (undealtWithCount > 0) + { + + this.projectMessages.setForeground (java.awt.Color.red); + + this.projectMessages.setToolTipText (String.format (getUIString (editors,LanguageStrings.editor,view,projecteditor,undealtwithmessagecount,tooltip), + //"%s {project} message%s requiring your attention, click to view them", + Environment.formatNumber (undealtWithCount))); + //(undealtWithCount == 1 ? "" : "s"), + //(undealtWithCount == 1 ? "s" : ""))); + + } else { + + this.projectMessages.setToolTipText (String.format (getUIString (editors,LanguageStrings.editor,view,projecteditor,undealtwithmessagecount,tooltip), + //"%s {project} message%s, click to view them", + Environment.formatNumber (ps))); + //(projMess.size () == 1 ? "" : "s"), + //(projMess.size () == 1 ? "s" : ""))); + + } + + this.projectMessages.setText (String.format ("%s", + Environment.formatNumber (ps))); + + this.projectMessages.setVisible (true); + + } + + this.comments.setVisible (false); + + if (this.showProjectInfo) + { + + AbstractProjectViewer pv = (AbstractProjectViewer) this.viewer; + + int commCount = 0; + + if (!this.editor.isPending ()) + { + + this.comments.setVisible (true); + this.comments.setForeground (java.awt.Color.black); + + // Get undealt with messages that are not chat. + // If there is just one then show it, otherwise show a link that will display a popup of them. + Set comments = this.editor.getMessages (new DefaultEditorMessageFilter (pv.getProject (), + ProjectCommentsMessage.MESSAGE_TYPE)); + + if (comments.size () > 0) + { + + int sets = comments.size (); + int undealtWithCount = 0; + + for (EditorMessage m : comments) + { + + if (!m.isDealtWith ()) + { + + undealtWithCount++; + + + } + + ProjectCommentsMessage pcm = (ProjectCommentsMessage) m; + + commCount += pcm.getComments ().size (); + + } + + if (undealtWithCount > 0) + { + + this.comments.setForeground (java.awt.Color.red); + + } + + this.comments.setToolTipText (Environment.replaceObjectNames (String.format (getUIString (editors,LanguageStrings.editor,view,projectcomments,(this.projEditor != null ? received : sent),tooltip), + //"%s {comment%s} %s %s", + Environment.formatNumber (commCount), + //(commCount == 1 ? "" : "s"), + //(this.projEditor != null ? "from" : "sent to"), + this.editor.getShortName ()))); + + } else { + + if (this.projEditor != null) + { + + this.comments.setToolTipText (Environment.replaceObjectNames (String.format (getUIString (editors,LanguageStrings.editor,view,noprojectcomments,received,tooltip), + //"%s has not sent you any {comments} yet.", + this.editor.getShortName ()))); + + } else { + + this.comments.setToolTipText (Environment.replaceObjectNames (String.format (getUIString (editors,LanguageStrings.editor,view,noprojectcomments,sent,tooltip), + //"You have not sent any {comments} to %s yet.", + this.editor.getShortName ()))); + + } + + } + + this.comments.setText (Environment.formatNumber (commCount)); + + this.comments.setEnabled (commCount > 0); + + } + + } + + this.chat.setVisible (false); + + Set chatMessages = this.getChatMessages (); + + int chatMessagesSize = chatMessages.size (); + + if (chatMessagesSize > 0) + { + + this.chat.setForeground (java.awt.Color.red); + + this.chat.setToolTipText (Environment.replaceObjectNames (String.format (getUIString (editors,LanguageStrings.editor,view,unreadchatmessages,tooltip), + //"%s unread chat message%s", + Environment.formatNumber (chatMessagesSize)))); + + this.chat.setText (Environment.formatNumber (chatMessagesSize)); + + this.chat.setVisible (true); + + } + + if (this.isShowAttentionBorder ()) + { + + this.editorInfo.setBorder (new CompoundBorder (new MatteBorder (0, 2, 0, 0, UIUtils.getColor ("#ff0000")), + UIUtils.createPadding (0, 5, 0, 0))); + + } else { + + this.editorInfo.setBorder (null); + + } + + this.validate (); + this.repaint (); + + } +*/ + + public void addDeleteAllMessagesMenuItem (ContextMenu menu) + { + + final EditorInfoBox _this = this; + + if (Environment.isDebugModeEnabled ()) + { + + if ((this.proj != null) + && + (this.proj.getProjectEditor (_this.editor) != null) + ) + { + + menu.getItems ().add (QuollMenuItem.builder () + .label (new SimpleStringProperty ("Remove {project} editor [Debug option]")) + .iconName (StyleClassNames.DELETE) + .onAction (ev -> + { + + QuollPopup.yesConfirmTextEntryBuilder () + .inViewer (this.viewer) + .title (new SimpleStringProperty ("Remove {project} editor?")) + .description (new SimpleStringProperty (String.format ("To remove %s as a {project} editor please enter Yes in the box below. Note: this will also remove all {project} related message types for this {project} (project-new, project-new-response, project-update, project-edit-stop, project-comments)", + this.editor.getMainName ()))) + .confirmButtonLabel (new SimpleStringProperty ("Yes, delete them")) + .cancelButtonLabel (new SimpleStringProperty ("No, keep them")) + .onConfirm (eev -> + { + + this.loadMessagesForEditor (); + + final Set messages = _this.editor.getMessages (new DefaultEditorMessageFilter (_this.proj, + NewProjectMessage.MESSAGE_TYPE, + NewProjectResponseMessage.MESSAGE_TYPE, + UpdateProjectMessage.MESSAGE_TYPE, + ProjectEditStopMessage.MESSAGE_TYPE, + ProjectCommentsMessage.MESSAGE_TYPE)); + + try + { + + EditorsEnvironment.deleteMessages (messages); + + EditorsEnvironment.removeProjectEditor (_this.proj.getProjectEditor (_this.editor)); + + } catch (Exception e) { + + Environment.logError ("Unable to delete messages for editor: " + + _this.editor, + e); + + ComponentUtils.showErrorMessage (_this.viewer, + new SimpleStringProperty ("Unable to delete messages for editor.")); + + return; + + } + + QuollPopup.messageBuilder () + .inViewer (_this.viewer) + .title (new SimpleStringProperty ("{Project} editor removed")) + .message (new SimpleStringProperty ("All associated {project} messages have been deleted.")) + .closeButton () + .build (); + + }) + .build (); + + }) + .build ()); + + } + + menu.getItems ().add (QuollMenuItem.builder () + .label (new SimpleStringProperty ("Delete Contact completely [debug option]")) + .iconName (StyleClassNames.DELETE) + .onAction (ev -> + { + + QuollPopup.yesConfirmTextEntryBuilder () + .description (new SimpleStringProperty ("Enter Yes to completely delete the Contact.")) + .onConfirm (eev -> + { + + try + { + + EditorsEnvironment.deleteEditor (this.editor); + + } catch (Exception e) { + + Environment.logError ("Unable to delete editor: " + this.editor, + e); + + ComponentUtils.showErrorMessage (new SimpleStringProperty ("Unable to delete editor.")); + + } + + }) + .build (); + + }) + .build ()); + + menu.getItems ().add (QuollMenuItem.builder () + .label (new SimpleStringProperty ("Delete all messages for types [Debug option]")) + .iconName (StyleClassNames.DELETE) + .onAction (ev -> + { + + VBox b = new VBox (); + + Set types = new LinkedHashSet<> (); + + types.add (NewProjectMessage.MESSAGE_TYPE); + types.add (UpdateProjectMessage.MESSAGE_TYPE); + types.add (NewProjectResponseMessage.MESSAGE_TYPE); + types.add (ProjectEditStopMessage.MESSAGE_TYPE); + types.add (ProjectCommentsMessage.MESSAGE_TYPE); + types.add (InviteMessage.MESSAGE_TYPE); + types.add (InviteResponseMessage.MESSAGE_TYPE); + types.add (EditorChatMessage.MESSAGE_TYPE); + types.add (EditorInfoMessage.MESSAGE_TYPE); + types.add (EditorRemovedMessage.MESSAGE_TYPE); + + final Map cbs = new HashMap<> (); + + for (String t : types) + { + + CheckBox cb = QuollCheckBox.builder () + .label (new SimpleStringProperty (t)) + .build (); + + cbs.put (t, + cb); + + b.getChildren ().add (cb); + + } + + QuollPopup.questionBuilder () + .inViewer (_this.viewer) + .title (new SimpleStringProperty ("Delete types of message")) + .message (b) + .confirmButtonLabel (new SimpleStringProperty ("Yes, delete them")) + .onConfirm (eev -> + { + + _this.loadMessagesForEditor (); + + Set selTypes = new LinkedHashSet (); + + for (String t : cbs.keySet ()) + { + + if (cbs.get (t).isSelected ()) + { + + selTypes.add (t); + + } + + } + + Set toDel = _this.editor.getMessages (null, + selTypes.toArray (new String[selTypes.size ()])); + + try + { + + EditorsEnvironment.deleteMessages (toDel); + + } catch (Exception e) { + + Environment.logError ("Unable to delete messages for editor: " + + _this.editor, + e); + + ComponentUtils.showErrorMessage (_this.viewer, + new SimpleStringProperty ("Unable to delete messages for editor.")); + + return; + + } + + for (EditorMessage m : toDel) + { + + _this.editor.removeMessage (m); + + } + + QuollPopup.messageBuilder () + .inViewer (_this.viewer) + .title (new SimpleStringProperty ("Selected message types deleted")) + .closeButton () + .message (new SimpleStringProperty ("All message for selected types have been deleted.")) + .build (); + + }) + .build (); + + }) + .build ()); + + } + + } + + private void loadMessagesForEditor () + { + + if (this.editor.messagesLoaded ()) + { + + return; + + } + + try + { + + EditorsEnvironment.loadMessagesForEditor (this.editor); + + } catch (Exception e) { + + Environment.logError ("Unable to load messages for editor: " + + this.editor, + e); + + ComponentUtils.showErrorMessage (this.viewer, + getUILanguageStringProperty (editors,LanguageStrings.editor,view,actionerror)); + //"Unable to load messages for editor."); + + return; + + } + + } + + public void addSendMessageMenuItem (ContextMenu menu) + { + + final EditorInfoBox _this = this; + + if (this.editor.isPrevious ()) + { + + return; + + } + + final boolean pending = this.editor.isPending (); + + if (!pending) + { + + menu.getItems ().add (QuollMenuItem.builder () + .label (editors,LanguageStrings.editor,view,popupmenu,items,sendmessage) + .iconName (StyleClassNames.MESSAGE) + .onAction (ev -> + { + + try + { + + this.viewer.sendMessageToEditor (this.editor); + + } catch (Exception e) { + + Environment.logError ("Unable to show editor: " + + this.editor, + e); + + ComponentUtils.showErrorMessage (this.viewer, + getUILanguageStringProperty (editors,LanguageStrings.editor,view,actionerror)); + //"Unable to show {editor}."); + + } + + }) + .build ()); + + } + + } + + public void addShowImportantMessagesMenuItem (ContextMenu menu) + { + + if (this.editor.isPrevious ()) + { + + return; + + } + + final EditorInfoBox _this = this; + + final boolean pending = this.editor.isPending (); + + if (!pending) + { + + final Set messages = this.editor.getMessages (m -> + { + + if (!EditorsUIUtils.getDefaultViewableMessageFilter ().accept (m)) + { + + return false; + + } + + if (m.isDealtWith ()) + { + + return false; + + } + + if (m.getMessageType ().equals (EditorChatMessage.MESSAGE_TYPE)) + { + + return false; + + } + + return true; + + }); + + if (messages.size () > 0) + { + + menu.getItems ().add (QuollMenuItem.builder () + .label (getUILanguageStringProperty (Arrays.asList (editors,LanguageStrings.editor,view,popupmenu,items,importantmessages), + Environment.formatNumber (messages.size ()))) + .iconName (StyleClassNames.IMPORTANT) + .onAction (ev -> + { + + try + { + + EditorsUIUtils.showImportantMessagesForEditor (this.editor, + this.viewer, + null); + + } catch (Exception e) { + + Environment.logError ("Unable to show project messages for editor: " + + this.editor, + e); + + ComponentUtils.showErrorMessage (this.viewer, + getUILanguageStringProperty (editors,LanguageStrings.messages,show,important,actionerror)); + //"Unable to {project} messages for editor."); + + return; + + } + + }) + .build ()); + + } + + } + + } + + public void addProjectSentAndUpdatesMenuItem (ContextMenu menu) + { + + final EditorInfoBox _this = this; + + final boolean pending = this.editor.isPending (); + + //boolean isEditorProject = this.projectViewer.getProject ().isEditorProject (); + + if ((!pending) + && + (this.showProjectInfo) + && + (this.proj != null) + ) + { + + final Set messages = this.editor.getMessages (new DefaultEditorMessageFilter (this.proj, + NewProjectMessage.MESSAGE_TYPE, + NewProjectResponseMessage.MESSAGE_TYPE, + UpdateProjectMessage.MESSAGE_TYPE, + ProjectEditStopMessage.MESSAGE_TYPE)); + + if (messages.size () > 0) + { + + menu.getItems ().add (QuollMenuItem.builder () + .label (getUILanguageStringProperty (Arrays.asList (editors,LanguageStrings.editor,view,popupmenu,items,projectupdates), + Environment.formatNumber (messages.size ()))) + .iconName (Project.OBJECT_TYPE) + .onAction (ev -> + { + + try + { + + EditorsUIUtils.showProjectMessagesForEditor (this.editor, + (AbstractProjectViewer) this.viewer, + null); + + } catch (Exception e) { + + Environment.logError ("Unable to show project messages for editor: " + + this.editor, + e); + + ComponentUtils.showErrorMessage (this.viewer, + getUILanguageStringProperty (editors,LanguageStrings.messages,show,project,actionerror)); + //"Unable to {project} messages for editor.") + + return; + + } + + }) + .build ()); + + } + + } + + } + + public void addProjectsInvolvedWithMenuItem (ContextMenu menu) + { + + final boolean pending = this.editor.isPending (); + + if (!pending) + { + + // Get all the projects. + int projCount = 0; + + try + { + + projCount = Environment.getAllProjectInfos (Project.EDITOR_PROJECT_TYPE).size (); + + } catch (Exception e) { + + Environment.logError ("Unable to get all projects", + e); + + } + + if (projCount > 0) + { + + menu.getItems ().add (QuollMenuItem.builder () + .label (getUILanguageStringProperty (Arrays.asList (editors,LanguageStrings.editor,view,popupmenu,items,projectsuserediting), + this.editor.mainNameProperty (), + Environment.formatNumber (projCount))) + .iconName (Project.OBJECT_TYPE) + .onAction (ev -> + { + + try + { + + EditorsUIUtils.showProjectsUserIsEditingForEditor (this.editor, + this.viewer); + + } catch (Exception e) { + + Environment.logError ("Unable to show projects user is editing for editor: " + + this.editor, + e); + + ComponentUtils.showErrorMessage (this.viewer, + getUILanguageStringProperty (editors,LanguageStrings.editor,showprojectscontactisediting,actionerror)); + //String.format ("Unable to show {projects} you are editing for %s.", + // _this.editor.getShortName ())); + + return; + + } + + }) + .build ()); + + } + + final Set messages = this.editor.getMessages (m -> + { + + if (m.isSentByMe ()) + { + + return false; + + } + + if (!m.getMessageType ().equals (NewProjectResponseMessage.MESSAGE_TYPE)) + { + + return false; + + } + + NewProjectResponseMessage nprm = (NewProjectResponseMessage) m; + + if (!nprm.isAccepted ()) + { + + return false; + + } + + return true; + + }); + + if (messages.size () > 0) + { + + menu.getItems ().add (QuollMenuItem.builder () + .label (getUILanguageStringProperty (Arrays.asList (editors,LanguageStrings.editor,view,popupmenu,items,projectscontactediting), + this.editor.mainNameProperty (), + Environment.formatNumber (messages.size ()))) + .iconName (Project.OBJECT_TYPE) + .onAction (ev -> + { + + try + { + + EditorsUIUtils.showProjectsEditorIsEditingForUser (this.editor, + this.viewer); + + } catch (Exception e) { + + Environment.logError ("Unable to show projects for editor: " + + this.editor, + e); + + ComponentUtils.showErrorMessage (this.viewer, + getUILanguageStringProperty (editors,LanguageStrings.editor,showprojectscontactisediting,actionerror)); + //String.format ("Unable to show {projects} %s is editing for you.", + // _this.editor.getShortName ())); + + return; + + } + + }) + .build ()); + + } + + } + + } + + public void addShowCommentsMenuItem (ContextMenu menu) + { + + final EditorInfoBox _this = this; + + if (this.editor.isPending ()) + { + + return; + + } + + if (this.proj == null) + { + + return; + + } + + boolean isEditorProject = this.proj.isEditorProject (); + + final Set messages = this.editor.getMessages (m -> + { + + return ((m.getMessageType ().equals (ProjectCommentsMessage.MESSAGE_TYPE)) + && + (_this.proj.getId ().equals (m.getForProjectId ()))); + + }); + + String suffix = (this.projEditor != null ? "received" : "sent"); + + if ((isEditorProject) + && + (messages.size () > 0) + ) + { + + menu.getItems ().add (QuollMenuItem.builder () + .label (editors,LanguageStrings.editor,view,popupmenu,items,commentssent) + .iconName (StyleClassNames.COMMENT) + .onAction (ev -> + { + + try + { + + EditorsUIUtils.showAllCommentsForEditor (this.editor, + (AbstractProjectViewer) this.viewer, + null); + + } catch (Exception e) { + + Environment.logError ("Unable to show comments from editor: " + + this.editor, + e); + + ComponentUtils.showErrorMessage (this.viewer, + getUILanguageStringProperty (editors,viewcommentserror)); + //"Unable to show {comments} from editor."); + + return; + + } + + }) + .build ()); + + } else { + + Iterator iter = messages.iterator (); + + if (messages.size () > 0) + { + + final ProjectCommentsMessage message = (ProjectCommentsMessage) messages.iterator ().next (); + + menu.getItems ().add (QuollMenuItem.builder () + .label (getUILanguageStringProperty (editors,LanguageStrings.editor,view,popupmenu,items,(this.projEditor != null ? lastcommentsreceived : lastcommentssent), + Environment.formatNumber (message.getComments ().size ()))) + .iconName (StyleClassNames.FIND) + .onAction (ev -> + { + + EditorsUIUtils.showProjectComments (message, + (AbstractProjectViewer) this.viewer, + null); + + }) + .build ()); + + } + + if (messages.size () > 1) + { + + menu.getItems ().add (QuollMenuItem.builder () + .label (editors,LanguageStrings.editor,view,popupmenu,items,(this.projEditor != null ? commentsreceived : commentssent)) + .iconName (StyleClassNames.COMMENT) + .onAction (ev -> + { + + try + { + + EditorsUIUtils.showAllCommentsForEditor (this.editor, + (AbstractProjectViewer) this.viewer, + null); + + } catch (Exception e) { + + Environment.logError ("Unable to show comments from editor: " + + this.editor, + e); + + ComponentUtils.showErrorMessage (this.viewer, + getUILanguageStringProperty (editors,viewcommentserror)); + //"Unable to show {comments} from editor."); + + return; + + } + + }) + .build ()); + + } + + } + + } + + public void addSendOrUpdateProjectMenuItem (ContextMenu menu) + { + + if ((this.editor.isPrevious ()) + || + (this.editor.isPending ()) + ) + { + + return; + + } + + if (this.proj == null) + { + + return; + + } + + final boolean pending = this.editor.isPending (); + + boolean isEditorProject = this.proj.isEditorProject (); + + if ((!pending) + && + (!isEditorProject) + ) + { + + this.loadMessagesForEditor (); + + // Find out what was the last project message sent. + Set messages = this.editor.getMessages (new DefaultEditorMessageFilter (this.proj, + NewProjectMessage.MESSAGE_TYPE, + NewProjectResponseMessage.MESSAGE_TYPE, + ProjectEditStopMessage.MESSAGE_TYPE, + UpdateProjectMessage.MESSAGE_TYPE)); + + EditorMessage last = null; + + for (EditorMessage m : messages) + { + + last = m; + + } + + boolean addSend = false; + boolean addUpdate = false; + + if ((last == null) + || + (last instanceof ProjectEditStopMessage) + ) + { + + addSend = true; + + } + + if (last instanceof NewProjectMessage) + { + + // Sent the project. Do nothing since we have no response. + addSend = true; + //return; + + } + + if (last instanceof NewProjectResponseMessage) + { + + NewProjectResponseMessage npr = (NewProjectResponseMessage) last; + + if (!npr.isAccepted ()) + { + + addSend = true; + + } else { + + addUpdate = true; + + } + + } + + if (last instanceof UpdateProjectMessage) + { + + addUpdate = true; + + } + + if (addSend) + { + + menu.getItems ().add (QuollMenuItem.builder () + .iconName (StyleClassNames.SEND) + .label (editors,LanguageStrings.editor,view,popupmenu,items,sendproject) + .onAction (ev -> + { + + EditorsUIUtils.showSendProject ((AbstractProjectViewer) this.viewer, + this.editor, + null); + + }) + .build ()); + + return; + + } + + if (addUpdate) + { + + menu.getItems ().add (QuollMenuItem.builder () + .label (editors,LanguageStrings.editor,view,popupmenu,items,sendupdateproject) + .iconName (StyleClassNames.SEND) + .onAction (ev -> + { + + EditorsUIUtils.showUpdateProject ((AbstractProjectViewer) this.viewer, + this.editor, + null); + + }) + .build ()); + + } else { + + menu.getItems ().add (QuollMenuItem.builder () + .label (editors,LanguageStrings.editor,view,popupmenu,items,sendproject) + .iconName (StyleClassNames.SEND) + .onAction (ev -> + { + + EditorsUIUtils.showSendProject ((AbstractProjectViewer) this.viewer, + this.editor, + null); + + }) + .build ()); + + } + + } + + } + + public void addUpdateEditorInfoMenuItem (ContextMenu menu) + { + + final boolean pending = this.editor.isPending (); + + if (!pending) + { + + menu.getItems ().add (QuollMenuItem.builder () + .label (editors,LanguageStrings.editor,view,popupmenu,items,updatecontactinfo) + .iconName (StyleClassNames.EDIT) + .onAction (ev -> + { + + EditorsUIUtils.updateEditorInfo (this.viewer, + this.editor); + + }) + .build ()); + + } + + } + + public void addRemoveEditorMenuItem (ContextMenu menu) + { + + final EditorInfoBox _this = this; + + if (this.editor.isPrevious ()) + { + + return; + + } + + menu.getItems ().add (QuollMenuItem.builder () + .label (editors,LanguageStrings.editor,view,popupmenu,items,removecontact) + .iconName (StyleClassNames.DELETE) + .onAction (ev -> + { + + EditorsUIUtils.showRemoveEditor (this.viewer, + this.editor, + null); + + }) + .build ()); + } + + public void addShowAllMessagesMenuItem (final ContextMenu menu) + { + + menu.getItems ().add (QuollMenuItem.builder () + .label (editors,LanguageStrings.editor,view,popupmenu,items,allmessages) + .iconName (StyleClassNames.FIND) + .onAction (ev -> + { + + EditorsUIUtils.showAllMessagesForEditor (this.editor, + this.viewer, + null); + + }) + .build ()); + + } + +/* + public void addSearchMessagesMenuItem (final JPopupMenu menu, + final EditorPanel panel) + { + + final EditorInfoBox _this = this; + + final boolean pending = this.editor.isPending (); + + if (!pending) + { + + menu.add (UIUtils.createMenuItem ("Search messages", + Constants.FIND_ICON_NAME, + new ActionListener () + { + + public void actionPerformed (ActionEvent ev) + { + + panel.showSearch (); + + } + + })); + + } + + } +*/ + public void addFullPopupListener () + { + + final EditorInfoBox _this = this; + + this.setOnContextMenuRequested (ev -> + { + + ContextMenu cm = new ContextMenu (); + + this.addSendMessageMenuItem (cm); + this.addSendOrUpdateProjectMenuItem (cm); + this.addShowImportantMessagesMenuItem (cm); + + if (this.editor.isPending ()) + { + + cm.getItems ().add (QuollMenuItem.builder () + .label (editors,LanguageStrings.editor,view,popupmenu,items,resendinvite) + .iconName (StyleClassNames.NOTIFY) + .onAction (eev -> + { + + EditorsEnvironment.sendInvite (this.editor.getEmail (), + this.viewer); + + }) + .build ()); + + } + + this.addShowAllMessagesMenuItem (cm); + + this.addUpdateEditorInfoMenuItem (cm); + + this.addRemoveEditorMenuItem (cm); + + this.addDeleteAllMessagesMenuItem (cm); + + ev.consume (); + + this.getProperties ().put ("context-menu", cm); + + cm.setAutoFix (true); + cm.setAutoHide (true); + cm.setHideOnEscape (true); + cm.show (this, + ev.getScreenX (), + ev.getScreenY ()); + + }); + + } + + public void addBasicPopupListener () + { + + this.setOnContextMenuRequested (ev -> + { + + ContextMenu cm = new ContextMenu (); + + this.addDeleteAllMessagesMenuItem (cm); + + this.addSendMessageMenuItem (cm); + + this.addUpdateEditorInfoMenuItem (cm); + + ev.consume (); + + this.editorInfo.getProperties ().put ("context-menu", cm); + + cm.setAutoFix (true); + cm.setAutoHide (true); + cm.setHideOnEscape (true); + cm.show (this.editorInfo, + ev.getScreenX (), + ev.getScreenY ()); + + }); + + } + +} diff --git a/src/main/java/com/quollwriter/editors/ui/EditorInfoMessageBox.java b/src/main/java/com/quollwriter/editors/ui/EditorInfoMessageBox.java new file mode 100644 index 00000000..6ae5bcbd --- /dev/null +++ b/src/main/java/com/quollwriter/editors/ui/EditorInfoMessageBox.java @@ -0,0 +1,202 @@ +package com.quollwriter.editors.ui; + +import java.awt.image.*; +import java.util.*; + +import javafx.beans.property.*; +import javafx.scene.layout.*; +import javafx.scene.image.*; +import javafx.embed.swing.*; + +import com.quollwriter.*; +import com.quollwriter.editors.*; +import com.quollwriter.data.editors.*; +import com.quollwriter.ui.fx.viewers.*; +import com.quollwriter.ui.fx.*; +import com.quollwriter.ui.fx.components.*; +import com.quollwriter.editors.messages.*; + +import static com.quollwriter.LanguageStrings.*; +import static com.quollwriter.uistrings.UILanguageStringsManager.getUILanguageStringProperty; + +public class EditorInfoMessageBox extends MessageBox +{ + + private VBox responseBox = null; + + public EditorInfoMessageBox (EditorInfoMessage mess, + AbstractViewer viewer) + { + + super (mess, + viewer); + + mess.dealtWithProperty ().addListener ((pr, oldv, newv) -> + { + + this.responseBox.setVisible (!newv); + + }); + + this.getStyleClass ().add (StyleClassNames.EDITORINFO); + + List prefix = Arrays.asList (editors,messages,contactinfo); + + StringProperty title = getUILanguageStringProperty (Utils.newList (prefix,sent,LanguageStrings.title)); + //"Sent name/avatar"; + + if (!this.message.isSentByMe ()) + { + + title = getUILanguageStringProperty (Utils.newList (prefix,received,LanguageStrings.title)); + //"Received name/avatar update"; + + } + + this.getChildren ().add (Header.builder () + .title (title) + .iconClassName (StyleClassNames.INFORMATION) + .styleClassName (StyleClassNames.SUBTITLE) + .build ()); + + HBox edInfo = new HBox (); + edInfo.getStyleClass ().add (StyleClassNames.INFO); + + this.getChildren ().add (edInfo); + + if (this.message.getAvatar () != null) + { + + edInfo.getChildren ().add (IconBox.builder () + .styleClassName ("avatar-box") + .image (new SimpleObjectProperty<> (this.message.getAvatar ())) + .build ()); + + } + + String n = this.message.getName (); + + if (n == null) + { + + n = this.message.getEditor ().getMainName (); + + } + + QuollLabel name = QuollLabel.builder () + .label (new SimpleStringProperty (n)) + .styleClassName (StyleClassNames.NAME) + .build (); + + edInfo.getChildren ().add (name); + + if ((!this.message.isDealtWith ()) + && + (!this.message.isSentByMe ()) + ) + { + + this.responseBox = new VBox (); + + this.getChildren ().add (this.responseBox); + + QuollButton update = QuollButton.builder () + .label (getUILanguageStringProperty (Utils.newList (prefix,received,buttons,LanguageStrings.update))) + .onAction (ev -> + { + + EditorEditor ed = this.message.getEditor (); + + try + { + + // Just update the info. + String newName = this.message.getName (); + + if (newName != null) + { + + ed.setName (newName.trim ()); + + } + + Image newImage = this.message.getAvatar (); + + if (newImage != null) + { + + ed.setAvatar (newImage); + + } + + EditorsEnvironment.updateEditor (ed); + + this.message.setDealtWith (true); + + EditorsEnvironment.updateMessage (this.message); + + } catch (Exception e) { + + Environment.logError ("Unable to update editor: " + + ed, + e); + + ComponentUtils.showErrorMessage (this.viewer, + getUILanguageStringProperty (editors,editor,edit,actionerror)); + //"Unable to update {editor}, please contact Quoll Writer support for assistance."); + + return; + + } + + }) + .build (); + + QuollButton ignore = QuollButton.builder () + .label (getUILanguageStringProperty (Utils.newList (prefix,received,buttons,LanguageStrings.ignore))) + .onAction (ev -> + { + + try + { + + this.message.setDealtWith (true); + + EditorsEnvironment.updateMessage (this.message); + + } catch (Exception e) { + + Environment.logError ("Unable to update message: " + + this.message, + e); + + ComponentUtils.showErrorMessage (this.viewer, + getUILanguageStringProperty (editors,editor,edit,actionerror)); + //"Unable to update {editor}, please contact Quoll Writer support for assistance."); + + return; + + } + + }) + .build (); + + QuollButtonBar bb = QuollButtonBar.builder () + .button (update) + .button (ignore) + .build (); + + this.responseBox.getChildren ().add (bb); + + } + + } + + public boolean isAutoDealtWith () + { + + return false; + + } + +} diff --git a/src/com/quollwriter/editors/ui/EditorLogin.java b/src/main/java/com/quollwriter/editors/ui/EditorLogin.java similarity index 99% rename from src/com/quollwriter/editors/ui/EditorLogin.java rename to src/main/java/com/quollwriter/editors/ui/EditorLogin.java index 655e4f84..a506f34d 100644 --- a/src/com/quollwriter/editors/ui/EditorLogin.java +++ b/src/main/java/com/quollwriter/editors/ui/EditorLogin.java @@ -387,7 +387,7 @@ public void actionPerformed (ActionEvent ev) java.util.List prefix = Arrays.asList (editors,login,savepasswordwarningpopup); // Show the warning. - UIUtils.createTextInputPopup (Environment.getFocusedViewer (), + UIUtils.createTextInputPopup (null, // TODO Environment.getFocusedViewer (), getUIString (prefix,title), //"Warning!", Constants.WARN_ICON_NAME, diff --git a/src/main/java/com/quollwriter/editors/ui/EditorLoginPopup.java b/src/main/java/com/quollwriter/editors/ui/EditorLoginPopup.java new file mode 100644 index 00000000..5f641f6a --- /dev/null +++ b/src/main/java/com/quollwriter/editors/ui/EditorLoginPopup.java @@ -0,0 +1,396 @@ +package com.quollwriter.editors.ui; + +import java.nio.file.*; +import java.nio.charset.*; +import java.util.*; +import java.util.function.*; + +import javafx.beans.property.*; +import javafx.event.*; +import javafx.scene.input.*; +import javafx.scene.control.*; + +import com.quollwriter.*; +import com.quollwriter.data.*; +import com.quollwriter.data.editors.*; +import com.quollwriter.editors.*; +import com.quollwriter.ui.fx.*; +import com.quollwriter.ui.fx.components.*; +import com.quollwriter.ui.fx.viewers.*; +import com.quollwriter.ui.fx.popups.*; + +import static com.quollwriter.uistrings.UILanguageStringsManager.getUILanguageStringProperty; +import static com.quollwriter.LanguageStrings.*; + +public class EditorLoginPopup extends PopupContent +{ + + public static final String POPUP_ID = "editorlogin"; + + private Runnable onLogin = null; + private Runnable onCancel = null; + private Consumer onError = null; + private Runnable onClose = null; + private QuollTextField emailField = null; + private PasswordField passwordField = null; + private QuollCheckBox autoLogin = null; + private QuollCheckBox savePwd = null; + private boolean inited = false; + private Form form = null; + + public EditorLoginPopup () + { + + super (null); + + Form.Builder fb = Form.builder () + .confirmButton (editors,login,LanguageStrings.popup,buttons,login) + .cancelButton (editors,login,LanguageStrings.popup,buttons,cancel); + + this.emailField = QuollTextField.builder () + //.text (acc.getEmail ()) + .build (); + + String upwd = EditorsEnvironment.getEditorsProperty (Constants.QW_EDITORS_SERVICE_PASSWORD_PROPERTY_NAME); + + this.passwordField = new PasswordField (); + //passwordField.setText (upwd); + + this.savePwd = QuollCheckBox.builder () + .label (editors,login,LanguageStrings.popup,labels,savepassword) + .selected (upwd != null) + .onAction (ev -> + { + + if (this.savePwd.isSelected ()) + { + + this.savePwd.setSelected (false); + + java.util.List prefix = Arrays.asList (editors,login,savepasswordwarningpopup); + + // Show the warning. + QuollPopup qp = QuollPopup.yesConfirmTextEntryBuilder () + .styleClassName (StyleClassNames.WARNING) + .title (Utils.newList (prefix,title)) + .description (Utils.newList (prefix,text)) + .confirmButtonLabel (Utils.newList (prefix,buttons,confirm)) + .cancelButtonLabel (Utils.newList (prefix,buttons,cancel)) + .onConfirm (eev -> + { + + this.savePwd.setSelected (true); + + }) + .onCancel (eev -> + { + + this.savePwd.setSelected (false); + + }) + .build (); + + } else { + + try + { + + EditorsEnvironment.removeEditorsProperty (Constants.QW_EDITORS_SERVICE_PASSWORD_PROPERTY_NAME); + + } catch (Exception e) { + + Environment.logError ("Unable to remove editors property: " + + Constants.QW_EDITORS_SERVICE_PASSWORD_PROPERTY_NAME, + e); + + } + + } + + }) + .build (); + + this.autoLogin = QuollCheckBox.builder () + .label (editors,login,LanguageStrings.popup,labels,autologin) + .selected (EditorsEnvironment.isAutoLoginAtQWStart ()) + .onAction (ev -> + { + + try + { + + EditorsEnvironment.setEditorsProperty (Constants.QW_EDITORS_SERVICE_LOGIN_AT_QW_START_PROPERTY_NAME, + this.autoLogin.isSelected ()); + + } catch (Exception e) { + + Environment.logError ("Unable to set to login at start", + e); + + } + + }) + .build (); + + fb.item (getUILanguageStringProperty (Arrays.asList (editors,login,LanguageStrings.popup,labels,youremail)), + this.emailField); + + fb.item (getUILanguageStringProperty (Arrays.asList (editors,login,LanguageStrings.popup,labels,password)), + this.passwordField); + + fb.item (savePwd); + fb.item (autoLogin); + + this.form = fb.build (); + + this.checkButtons (); + + EventHandler onKeyPressed = ev -> + { + + this.checkButtons (); + + }; + + this.emailField.addEventHandler (KeyEvent.KEY_RELEASED, + onKeyPressed); + this.passwordField.addEventHandler (KeyEvent.KEY_RELEASED, + onKeyPressed); + + this.form.addEventHandler (Form.FormEvent.CANCEL_EVENT, + ev -> + { + + this.close (); + + if (this.onCancel != null) + { + + Environment.scheduleImmediately (this.onCancel); + + } + + }); + + this.form.addEventHandler (Form.FormEvent.CONFIRM_EVENT, + ev -> + { + + if (this.form.getConfirmButton ().isDisabled ()) + { + + return; + + } + + try + { + + if (!this.savePwd.isSelected ()) + { + + EditorsEnvironment.removeEditorsProperty (Constants.QW_EDITORS_SERVICE_PASSWORD_PROPERTY_NAME); + + } else { + + EditorsEnvironment.setEditorsProperty (Constants.QW_EDITORS_SERVICE_PASSWORD_PROPERTY_NAME, + new String (this.passwordField.getText ())); + + } + + EditorsEnvironment.setEditorsProperty (Constants.QW_EDITORS_SERVICE_LOGIN_AT_QW_START_PROPERTY_NAME, + new com.gentlyweb.properties.BooleanProperty (Constants.QW_EDITORS_SERVICE_LOGIN_AT_QW_START_PROPERTY_NAME, + this.autoLogin.isSelected ())); + + } catch (Exception e) { + + Environment.logError ("Unable to update properties", + e); + + } + + EditorsEnvironment.setLoginCredentials (this.emailField.getText ().trim ().toLowerCase (), + this.passwordField.getText ()); + + this.form.showLoading (getUILanguageStringProperty (editors,login,LanguageStrings.popup,loading)); + this.form.hideError (); + + if (this.onLogin != null) + { + + Environment.scheduleImmediately (onLogin); + + } + + }); + + this.getChildren ().add (this.form); + + } + + private void checkButtons () + { + + this.form.getConfirmButton ().setDisable (false); + + if (this.emailField != null) + { + + String email = this.emailField.getText ().trim (); + + int atInd = email.indexOf ('@'); + + int dotInd = email.indexOf ('.', + atInd); + + if ((email.length () == 0) + || + (atInd == -1) + || + (email.length () - 1 == dotInd) + || + (dotInd == -1) + ) + { + + this.form.getConfirmButton ().setDisable (true); + + } + + } + + String pwd = this.passwordField.getText (); + + if (pwd == null) + { + + this.form.getConfirmButton ().setDisable (true); + + } else { + + if ((pwd.length () == 0) + || + (pwd.length () < 8) + ) + { + + this.form.getConfirmButton ().setDisable (true); + + } + + } + + } + + public void showError (StringProperty v) + { + + this.form.hideLoading (); + this.form.showError (v); + + } + + private void initFields () + { + + final EditorAccount acc = EditorsEnvironment.getUserAccount (); + + if (acc != null) + { + + this.emailField.setText (acc.getEmail ()); + + } + + String upwd = EditorsEnvironment.getEditorsProperty (Constants.QW_EDITORS_SERVICE_PASSWORD_PROPERTY_NAME); + + this.passwordField.setText (upwd); + + this.checkButtons (); + + } + + @Override + public void show () + { + + this.initFields (); + + super.show (); + + } + + public void show (AbstractViewer viewer, + StringProperty loginReason, + Runnable onLogin, + Runnable onCancel) + { + + this.initFields (); + + this.onLogin = onLogin; + this.onCancel = onCancel; + + this.form.hideError (); + + this.form.setDescription (loginReason); + + if (viewer == null) + { + + viewer = Environment.getFocusedViewer (); + + } + + viewer.showPopup (this.getPopup ()); + + } + + public void setOnLogin (Runnable r) + { + + this.onLogin = r; + + } + + public void setOnCancel (Runnable c) + { + + this.onCancel = c; + this.getPopup ().setOnClose (c); + + } + + @Override + public QuollPopup createPopup () + { + + QuollPopup p = QuollPopup.builder () + .title (editors,login,LanguageStrings.popup,title) + .styleClassName (StyleClassNames.EDITORLOGIN) + .headerIconClassName (StyleClassNames.CONTACTS) + .hideOnEscape (true) + .withClose (true) + .content (this) + .popupId (POPUP_ID) + .removeOnClose (false) + .build (); + + p.addEventHandler (QuollPopup.PopupEvent.SHOWN_EVENT, + ev -> + { + + UIUtils.forceRunLater (() -> + { + + this.emailField.requestFocus (); + + }); + + }); + + return p; + + } + +} diff --git a/src/main/java/com/quollwriter/editors/ui/EditorProjectViewer.java b/src/main/java/com/quollwriter/editors/ui/EditorProjectViewer.java new file mode 100644 index 00000000..ce4b99cc --- /dev/null +++ b/src/main/java/com/quollwriter/editors/ui/EditorProjectViewer.java @@ -0,0 +1,1421 @@ +package com.quollwriter.editors.ui; + +import java.net.*; + +import java.security.*; + +import java.text.*; + +import java.util.*; +import java.util.function.*; + +import javafx.scene.control.*; +import javafx.scene.*; +import javafx.geometry.*; +import javafx.beans.property.*; + +import com.quollwriter.*; + +import com.quollwriter.data.*; + +import com.quollwriter.db.*; + +import com.quollwriter.events.*; +import com.quollwriter.data.comparators.*; +import com.quollwriter.text.*; +import com.quollwriter.editors.ui.sidebars.*; +import com.quollwriter.editors.ui.panels.*; +import com.quollwriter.ui.fx.viewers.*; +import com.quollwriter.ui.fx.components.*; +import com.quollwriter.ui.fx.*; +import com.quollwriter.ui.fx.panels.*; + +import com.quollwriter.editors.*; +import com.quollwriter.editors.ui.*; +import com.quollwriter.uistrings.UILanguageStringsManager; + +import static com.quollwriter.LanguageStrings.*; +import static com.quollwriter.uistrings.UILanguageStringsManager.getUILanguageStringProperty; + +public class EditorProjectViewer extends AbstractProjectViewer +{ + + public interface CommandId extends AbstractProjectViewer.CommandId + { + + String completeediting = "completeediting"; + + } + + public static final String TAB_OBJECT_TYPE = "tab"; + public static final int NEW_COMMENT_ACTION = 3002; // "newComment"; + public static final int VIEW_EDITOR_CHAPTER_INFO_ACTION = 105; // "viewEditorChapterInfo"; + + public static final int DELETE_COMMENT_ACTION = 3001; // "deleteComment"; + public static final int EDIT_COMMENT_ACTION = 3000; + public static final int COMPLETE_EDITING_ACTION = 3003; + + private Date sessionStart = new Date (); + private EditorProjectSideBar sideBar = null; + //private DefaultChapterItemViewPopupProvider chapterItemViewPopupProvider = null; + + public EditorProjectViewer () + //throws GeneralException + { + + final EditorProjectViewer _this = this; +/* + this.chapterItemViewPopupProvider = new DefaultChapterItemViewPopupProvider () + { + + @Override + public boolean canEdit (ChapterItem it) + { + + if (it instanceof Note) + { + + Note n = (Note) it; + + return !n.isDealtWith (); + + } + + return true; + + } + + @Override + public boolean canDelete (ChapterItem it) + { + + if (it instanceof Note) + { + + Note n = (Note) it; + + return !n.isDealtWith (); + + } + + return true; + + } + + }; + + this.chapterItemViewPopupProvider.setShowLinks (false); + this.chapterItemViewPopupProvider.setFormatDetails (Note.OBJECT_TYPE, + new NoteFormatDetails () + { + + @Override + public String getTitle (Note item) + { + + return getUIString (objectnames,singular,comment); + //"{Comment}"; + + } + + @Override + public String getIcon (Note item) + { + + return Constants.COMMENT_ICON_NAME; + + } + + @Override + public String getItemDescription (Note item) + { + + return item.getDescription ().getMarkedUpText (); + + } + + @Override + public ActionListener getEditItemActionHandler (Note item, + ChapterItemViewer ep) + { + + return new CommentActionHandler (item, + ep); + + } + + @Override + public ActionListener getDeleteItemActionHandler (Note item, + ChapterItemViewer ep, + boolean showAtItem) + { + + // Should really add generics for this. + return new DeleteCommentActionHandler (item, + ep.getViewer (), + showAtItem); + + } + + }); +*/ + this.sideBar = new EditorProjectSideBar (this); + + this.initActionMappings (); + + } +/* + @Override + public SideBar getMainSideBar () + { + + return this.sideBar.getSideBar (); + + } +*/ +/* +TODO + public void fillFullScreenTitleToolbar (JToolBar toolbar) + { + + this.fillTitleToolbar (toolbar); + + WordCountTimerBox b = new WordCountTimerBox (this.getFullScreenFrame (), + Constants.ICON_FULL_SCREEN_ACTION, + this.getWordCountTimer ()); + + b.setBarHeight (20); + + toolbar.add (b); + + } +*/ + @Override + public Supplier> getSettingsMenuSupplier () + { + + final EditorProjectViewer _this = this; + + return () -> + { + + Set items = new LinkedHashSet<> (); + + List prefix = Arrays.asList (editors,LanguageStrings.project,settingsmenu,LanguageStrings.items); + + items.add (QuollMenuItem.builder () + .label (Utils.newList (prefix,openproject)) + .iconName (StyleClassNames.OPEN) + .onAction (ev -> + { + + _this.runCommand (CommandId.openproject); + + }) + .build ()); + + items.add (QuollMenuItem.builder () + .label (Utils.newList (prefix,closeproject)) + .iconName (StyleClassNames.CLOSE) + .onAction (ev -> + { + + _this.runCommand (CommandId.closeproject); + + }) + .build ()); + + items.add (QuollMenuItem.builder () + .label (Utils.newList (prefix,deleteproject)) + .iconName (StyleClassNames.DELETE) + .onAction (ev -> + { + + this.showCompleteEditing (); + + }) + .build ()); + + return items; + + }; + + } + + public void switchToProjectVersion (ProjectVersion pv) + { + + if (pv == null) + { + + throw new IllegalArgumentException ("Expected a project version"); + + } + + Set chaps = null; + + try + { + + chaps = ((ChapterDataHandler) this.getObjectManager ().getHandler (Chapter.class)).getChaptersForVersion (pv, + null, + null, + true); + + } catch (Exception e) { + + Environment.logError ("Unable to get project at version: " + + pv, + e); + + ComponentUtils.showErrorMessage (this, + getUILanguageStringProperty (editors,LanguageStrings.project,actions,switchtoversion,actionerror)); + //"Unable to open project at that version, please contact Quoll Writer support for assistance."); + + return; + + } + + // Close all the current panels and save the state. + this.closeAllTabs (); + + // Remove all the chapters from the book. + this.project.getBook (0).removeAllChapters (); + + for (Chapter c : chaps) + { + + this.project.getBook (0).addChapter (c); + + } + + this.project.setProjectVersion (pv); + + this.restoreTabs (); + + } + +/* + public boolean viewEditors () + throws GeneralException + { + + // See if the user has an account or has already registered, if so show the sidebar + // otherwise show the register. + if (!EditorsEnvironment.hasRegistered ()) + { + + EditorsUIUtils.showRegister (this); + + return true; + + } + + EditorsSideBar sb = new EditorsSideBar (this); + + this.addSideBar ("editors", + sb); + + this.showSideBar ("editors"); + + return true; + + } + */ + + @Override + public boolean addToAchievementsManager () + { + + return false; + + } + + private void showCompleteEditing () + { + + final EditorProjectViewer _this = this; + + final Project _proj = this.project; + + Runnable deleteProj = () -> + { + + // Check for unsent comments. + List prefix = Arrays.asList (editors,LanguageStrings.project,actions,deleteproject,popup); + + QuollPopup.yesConfirmTextEntryBuilder () + .title (Utils.newList (prefix,title)) + .styleClassName (StyleClassNames.DELETE) + //.styleSheet ("deleteeditorproject") + .inViewer (this) + .description (getUILanguageStringProperty (Utils.newList (prefix,text), + this.project.getName (), + this.project.getForEditor ().getMainName ())) + .confirmButtonLabel (Utils.newList (prefix,buttons,confirm)) + .cancelButtonLabel (Utils.newList (prefix,buttons,cancel)) + .onConfirm (ev -> + { + + EditorsEnvironment.sendProjectEditStopMessage (this.project, + () -> + { + + UIUtils.runLater (() -> + { + + Environment.setCloseDownAllowed (false); + + _this.close (true, + () -> + { + + Environment.setCloseDownAllowed (true); + + Environment.deleteProject (_proj, + () -> + { + + List prefx = Arrays.asList (editors,LanguageStrings.project,actions,deleteproject,confirmpopup); + + UIUtils.runLater (() -> + { + + QuollPopup.messageBuilder () + .title (Utils.newList (prefx,title)) + .message (getUILanguageStringProperty (Utils.newList (prefx,text), + _proj.getForEditor ().mainNameProperty ())) + .closeButton (null, + () -> + { + + Environment.showAllProjectsViewerIfNoOpenProjects (); + + }) + .build (); + + }); + + }); + + }); + + }); + + }); + + }) + .build (); + + }; + + int count = 0; + + try + { + + count = this.getUnsentComments ().size (); + + } catch (Exception e) { + + Environment.logError ("Unable to get unsent comments for project: " + + this.project, + e); + + ComponentUtils.showErrorMessage (this, + getUILanguageStringProperty (editors,LanguageStrings.project,actions,unsentcomments,actionerror)); + //"Unable to check for unsent comments, please contact Quoll Writer support for assistance."); + + // Let things through. + + } + + if (count > 0) + { + + List prefix2 = Arrays.asList (editors,LanguageStrings.project,actions,deleteproject,unsentcommentspopup); + + QuollPopup.questionBuilder () + .title (Utils.newList (prefix2,title)) + .inViewer (this) + .styleClassName (StyleClassNames.COMMENTS) + .styleSheet (StyleClassNames.COMMENTS) + .message (getUILanguageStringProperty (Utils.newList (prefix2,text), + count, + this.getProject ().getForEditor ().mainNameProperty ())) + .confirmButtonLabel (Utils.newList (prefix2,buttons,confirm)) + .cancelButtonLabel (Utils.newList (prefix2,buttons,cancel)) + .onConfirm (ev -> + { + + EditorsUIUtils.showSendUnsentComments (this, + deleteProj); + + }) + .onCancel (ev -> + { + + UIUtils.runLater (deleteProj); + + }) + .build (); + + return; + + } + + UIUtils.runLater (deleteProj); + + } + + private void initActionMappings () + { + + this.addActionMapping (() -> + { + + this.showCompleteEditing (); + + }, + CommandId.completeediting); + + this.addActionMapping (new CommandWithArgs (objs -> + { + + DataObject o = null; + + if ((objs != null) + && + (objs.length > 0) + ) + { + + o = objs[0]; + + } + + if (o == null) + { + + throw new IllegalArgumentException ("No object provided."); + + } + + this.editObject (o); + + }, + CommandId.editobject)); + + } + + public void editObject (DataObject d) + { + + if (d instanceof Chapter) + { + + this.editChapter ((Chapter) d, + null); + return; + + } + + if (d instanceof Note) + { + + this.editComment ((Note) d); + + } + + } + + public void showAddNewComment (Chapter c, + int pos) + { + + EditorChapterPanel qep = this.getEditorForChapter (c); + + qep.scrollToTextPosition (pos, + () -> + { + + qep.showAddNewComment (pos); + + }); + + } + + public void editComment (Note n) + { + + Chapter c = n.getChapter (); + + this.editChapter (c, + () -> + { + + try + { + + EditorChapterPanel editor = this.getEditorForChapter (c); + editor.editComment (n); + + } catch (Exception e) { + + Environment.logError ("Unable to edit comment: " + + n, + e); + ComponentUtils.showErrorMessage (this, + getUILanguageStringProperty (editors,LanguageStrings.project,actions,editcomment,actionerror)); + + } + + }); + + } + + @Override + public void handleNewProject () + { + + Book b = this.project.getBooks ().get (0); + + Chapter c = b.getFirstChapter (); + + // Create a new chapter for the book. + if (c == null) + { + + throw new IllegalArgumentException ("No chapter found."); + + } + + this.handleOpenProject (); + + this.editChapter (c, + null); + + } + + @Override + public String getStyleClassName () + { + + return StyleClassNames.EDITOR; + + } + + @Override + public void handleOpenProject () + { + + // TODO: Add achievements later. + // TODO Environment.getAchievementsManager ().removeViewer (this); + + // See if we have any state, if not then this is probably the first time we've opened the project + // then open the first chapter. + + if (this.getOpenTabsProperty () == null) + { + + // No state, open the first chapter. + Book b = this.project.getBooks ().get (0); + + Chapter c = b.getFirstChapter (); + + // Create a new chapter for the book. + if (c != null) + { + + this.editChapter (c, + null); + + } + + } + + final EditorProjectViewer _this = this; + + if (this.getProject ().getForEditor ().isPrevious ()) + { + + UIUtils.forceRunLater (() -> + { + + QuollPopup.messageBuilder () + .inViewer (this) + .closeButton () + .headerIconClassName (StyleClassNames.INFORMATION) + .message (editors,LanguageStrings.project,actions,openproject,openerrors,previouscontact) + .build (); + + }); + + } + + } +/* + public void expandNoteTypeInNoteTree (String type) + { + + TreeParentNode tpn = new TreeParentNode (Note.OBJECT_TYPE, + type); + + DefaultTreeModel dtm = (DefaultTreeModel) this.getNoteTree ().getModel (); + + DefaultMutableTreeNode root = (DefaultMutableTreeNode) dtm.getRoot (); + + this.getNoteTree ().expandPath (UIUtils.getTreePathForUserObject (root, + tpn)); + + } +*/ +/* + private void initNoteTree (boolean restoreSavedOpenTypes) + { + + if (restoreSavedOpenTypes) + { + + String openTypes = this.proj.getProperty (Constants.NOTE_TREE_OPEN_TYPES_PROPERTY_NAME); + + if (openTypes != null) + { + + DefaultTreeModel dtm = (DefaultTreeModel) this.getNoteTree ().getModel (); + + DefaultMutableTreeNode root = (DefaultMutableTreeNode) dtm.getRoot (); + + // Split on : + StringTokenizer t = new StringTokenizer (openTypes, + "|"); + + while (t.hasMoreTokens ()) + { + + String tok = t.nextToken ().trim (); + + TreeParentNode tpn = new TreeParentNode (Note.OBJECT_TYPE, + tok); + + this.getNoteTree ().expandPath (UIUtils.getTreePathForUserObject (root, + tpn)); + + } + + } + + } + + } +*/ +/* +TODO Remove + public void handleItemChangedEvent (ItemChangedEvent ev) + { + + if (ev.getChangedObject () instanceof Chapter) + { + + this.sideBar.reloadTreeForObjectType (Chapter.OBJECT_TYPE); + + } + + if (ev.getChangedObject () instanceof Note) + { + + this.sideBar.reloadTreeForObjectType (Note.OBJECT_TYPE); + + } + + } +*/ +/* +TODO Remove + public void reloadNoteTree () + { + + this.sideBar.reloadTreeForObjectType (Note.OBJECT_TYPE); + + } + + public void reloadChapterTree () + { + + this.sideBar.reloadTreeForObjectType (Chapter.OBJECT_TYPE); + + } +*/ + + public EditorChapterPanel getEditorForChapter (Chapter c) + { + + ChapterEditorPanelContent cp = super.getEditorForChapter (c); + + return (EditorChapterPanel) cp; + + } + + public void editChapter (final Chapter c, + final Runnable doAfterView) + { + + String pid = EditorChapterPanel.getPanelIdForChapter (c); + + if (this.showPanel (pid)) + { + + UIUtils.runLater (doAfterView); + + return; + + } + + try + { + + EditorChapterPanel p = new EditorChapterPanel (this, + c); + + this.addPanel (p); + + this.editChapter (c, + doAfterView); + + } catch (Exception e) { + + Environment.logError ("Unable to edit chapter: " + + c, + e); + + ComponentUtils.showErrorMessage (this, + getUILanguageStringProperty (Arrays.asList (LanguageStrings.project,actions,editchapter,actionerror), + c.getName ())); + + } + + } + + @Override + public void viewObject (DataObject d, + Runnable doAfterView) + { + + if (d instanceof Note) + { + + final Note n = (Note) d; + + if (n.getObject () != null) + { + + this.viewComment (n, + doAfterView); + + } + + return; + + } + + if (d instanceof Chapter) + { + + Chapter c = (Chapter) d; + + this.editChapter (c, + doAfterView); + + return; + + } + + // Record the error, then ignore. + Environment.logError ("Unable to open object: " + d); + + } + + public void viewObject (DataObject d) + { + + this.viewObject (d, + null); + + } + + public void viewComment (final Note n, + final Runnable doAfterView) + { + + try + { + + final Chapter c = n.getChapter (); + + this.editChapter (c, + () -> + { + + EditorChapterPanel pc = this.getEditorForChapter (c); + + if (pc.isReadyForUse ()) + { + + UIUtils.forceRunLater (() -> + { + + pc.showItem (n, + false); + + UIUtils.runLater (doAfterView); + + }); + + } else { + + pc.readyForUseProperty ().addListener ((pr, oldv, nev) -> + { + + UIUtils.forceRunLater (() -> + { + + pc.showItem (n, + false); + + UIUtils.runLater (doAfterView); + + }); + + }); + + } + + }); + + } catch (Exception e) + { + + Environment.logError ("Unable to show note: " + + n, + e); + + ComponentUtils.showErrorMessage (this, + getUILanguageStringProperty (editors,LanguageStrings.project,actions,viewcomment,actionerror)); + + } + + } + + public void showDeleteComment (Note n) + { + + EditorChapterPanel pc = this.getEditorForChapter (n.getChapter ()); + + pc.showDeleteCommentPopup (n, + pc.getNodeForChapterItem (n)); + + } + +/* +TODO remove + protected void addNameChangeListener (final NamedObject n, + final ProjectObjectQuollPanel qp) + { + + final EditorProjectViewer _this = this; + + qp.addObjectPropertyChangedListener (new PropertyChangedListener () + { + + @Override + public void propertyChanged (PropertyChangedEvent ev) + { + + if (ev.getChangeType ().equals (NamedObject.NAME)) + { + + _this.setTabHeaderTitle (qp, + qp.getTitle ()); + + _this.informTreeOfNodeChange (n, + _this.getTreeForObjectType (n.getObjectType ())); + + } + + } + + }); + + } +*/ + /** + * This is a top-level action so it can handle showing the user a message, it returns a boolean to indicate + * whether the chapter information is viewed. + */ + public boolean viewEditorChapterInformation (final Chapter c) + { +/* + ChapterInformationSideBar cb = new ChapterInformationSideBar (this, + c); + + this.addSideBar ("chapterinfo-" + c.getKey (), + cb); + + this.showSideBar ("chapterinfo-" + c.getKey ()); + */ + return true; + + } +/* +TODO Remove + public void addChapterToTreeAfter (Chapter newChapter, + Chapter addAfter) + { + + DefaultTreeModel model = (DefaultTreeModel) this.getChapterTree ().getModel (); + + DefaultMutableTreeNode cNode = new DefaultMutableTreeNode (newChapter); + + if (addAfter == null) + { + + // Get the book node. + TreePath tp = UIUtils.getTreePathForUserObject ((DefaultMutableTreeNode) model.getRoot (), + newChapter.getBook ()); + + if (tp != null) + { + + DefaultMutableTreeNode node = (DefaultMutableTreeNode) tp.getLastPathComponent (); + + model.insertNodeInto (cNode, + (MutableTreeNode) node, + 0); + + } else + { + + DefaultMutableTreeNode root = (DefaultMutableTreeNode) model.getRoot (); + + model.insertNodeInto (cNode, + root, + root.getChildCount ()); + + } + + } else + { + + // Get the "addAfter" node. + DefaultMutableTreeNode node = (DefaultMutableTreeNode) UIUtils.getTreePathForUserObject ((DefaultMutableTreeNode) model.getRoot (), + addAfter).getLastPathComponent (); + + model.insertNodeInto (cNode, + (MutableTreeNode) node.getParent (), + node.getParent ().getIndex (node) + 1); + + } + + this.getChapterTree ().setSelectionPath (new TreePath (cNode.getPath ())); + + } +*/ + public void deleteObject (NamedObject o, + boolean deleteChildObjects) + throws GeneralException + { + + if (o instanceof ChapterItem) + { + + this.deleteChapterItem ((ChapterItem) o, + deleteChildObjects, + true); + + return; + + } + + this.deleteObject (o); + + } + + public void deleteObject (NamedObject o) + throws GeneralException + { + + if (o instanceof Chapter) + { + + this.deleteChapter ((Chapter) o); + + } + + if (o instanceof ChapterItem) + { + + this.deleteChapterItem ((ChapterItem) o, + false, + false); + + } + + } + + public void deleteChapterItem (ChapterItem ci, + boolean deleteChildObjects, + boolean doInTransaction) + throws GeneralException + { + + if (ci.getObjectType ().equals (Note.OBJECT_TYPE)) + { + + this.deleteNote ((Note) ci, + doInTransaction); + + } + + } + + public void deleteNote (Note n, + boolean doInTransaction) + throws GeneralException + { + + Set otherObjects = n.getOtherObjectsInLinks (); + + NamedObject obj = n.getObject (); + + // Need to get the links, they may not be setup. + + this.dBMan.deleteObject (n, + false, + null); + + obj.removeNote (n); + + this.fireProjectEvent (ProjectEvent.Type.note, + ProjectEvent.Action.delete, + n); + + } + +/* +TODO? + public void scrollTo (final Chapter c, + final int pos) + { + + final EditorProjectViewer _this = this; + + this.editChapter (c, + new ActionListener () + { + + public void actionPerformed (ActionEvent ev) + { + + try + { + + _this.getEditorForChapter (c).scrollToPosition (pos); + + } catch (Exception e) + { + + Environment.logError ("Unable to show snippet at position: " + + pos, + e); + + } + + } + + }); + + } +*/ + public Set getNotesForType (String t) + { + + Set notes = this.getAllNotes (); + + Set ret = new TreeSet (new ChapterItemSorter ()); + + for (Note n : notes) + { + + if (n.getType ().equals (t)) + { + + ret.add (n); + + } + + } + + return ret; + + } + + public Set getAllNotes () + { + + Set notes = new HashSet (); + + Book b = this.project.getBooks ().get (0); + + java.util.List chapters = b.getChapters (); + + for (Chapter c : chapters) + { + + notes.addAll (c.getNotes ()); + + } + + return notes; + + } + + public void deleteChapter (Chapter c) + { + + throw new UnsupportedOperationException ("Not supported"); + + } + + @Override + public Set findText (String t) + { + + Set res = new LinkedHashSet<> (); + + FindResultsBox chres = this.findTextInChapters (t); + + if (chres != null) + { + + res.add (chres); + + } + + Set notes = this.project.getNotesContaining (t); + + if (notes.size () > 0) + { + + res.add (new NamedObjectFindResultsBox (getUILanguageStringProperty (objectnames,plural,comment), + StyleClassNames.COMMENTS, + this, + notes)); + + } + + return res; + + } + + public Set getUnsentComments (ProjectVersion pv) + throws GeneralException + { + + return this.getDealtWithNotes (pv, + false); + + } + + public Set getUnsentComments () + throws GeneralException + { + + return this.getUnsentComments (this.project.getProjectVersion ()); + + } + + public void setChapterEditComplete (Chapter chapter, + boolean editComplete) + { + + try + { + + chapter.setEditComplete (editComplete); + + EditorChapterPanel p = this.getEditorForChapter (chapter); + + int pos = -1; + + if (editComplete) + { + + if (p != null) + { + + pos = Utils.stripEnd (p.getEditor ().getText ()).length (); + + } else { + + String t = (chapter.getText () != null ? chapter.getText ().getText () : ""); + + pos = Utils.stripEnd (t).length (); + + } + + } + + chapter.setEditPosition (pos); + + this.saveObject (chapter, + false); + + p.recreateVisibleParagraphs (); + + } catch (Exception e) { + + Environment.logError ("Unable to set chapter edit complete: " + + chapter, + e); + + ComponentUtils.showErrorMessage (this, + getUILanguageStringProperty (LanguageStrings.project,editorpanel,actions,seteditcomplete,actionerror)); + + } + + } + + public void setChapterEditPosition (Chapter chapter, + int textPos) + { + + EditorChapterPanel p = this.getEditorForChapter (chapter); + + try + { + + int _textPos = 0; + int l = 0; + + if (p != null) + { + + l = Utils.stripEnd (p.getEditor ().getText ()).length (); + + _textPos = Math.min (textPos, l); + + // See if we are on the last line (it may be that the user is in the icon + // column). +/* +TODO + Rectangle2D pp = p.getEditor ().modelToView2D (_textPos); + + if (UserProperties.getAsBoolean (Constants.SET_CHAPTER_AS_EDIT_COMPLETE_WHEN_EDIT_POSITION_IS_AT_END_OF_CHAPTER_PROPERTY_NAME)) + { + + if (_textPos <= l) + { + + Rectangle2D ep = p.getEditor ().modelToView2D (l); + + chapter.setEditComplete ((Math.round (ep.getY ()) == Math.round (pp.getY ()))); + + } + + } +*/ + } else { + + String t = (chapter.getText () != null ? chapter.getText ().getText () : ""); + + l = Utils.stripEnd (t).length (); + + } + + _textPos = Math.min (_textPos, l); + + chapter.setEditComplete (false); + chapter.setEditPosition (_textPos); + + this.saveObject (chapter, + false); + + } catch (Exception e) { + + Environment.logError ("Unable to set edit position for: " + chapter, + e); + + ComponentUtils.showErrorMessage (this, + getUILanguageStringProperty (LanguageStrings.project,editorpanel,actions,seteditposition,actionerror)); + + return; + + } + + } + + public void removeChapterEditPosition (Chapter chapter) + { + + try + { + + chapter.setEditComplete (false); + chapter.setEditPosition (-1); + + this.saveObject (chapter, + false); + + } catch (Exception e) { + + Environment.logError ("Unable to remove edit position for chapter: " + + chapter, + e); + + ComponentUtils.showErrorMessage (this, + getUILanguageStringProperty (LanguageStrings.project,editorpanel,actions,removeeditposition,actionerror)); + + } + + } + + @Override + public void init (State s) + throws GeneralException + { + + super.init (s); + + this.setMainSideBar (this.sideBar); + + this.titleProperty ().unbind (); + this.titleProperty ().bind (UILanguageStringsManager.createStringPropertyWithBinding (() -> + { + + ProjectVersion pv = this.project.getProjectVersion (); + + StringProperty suff = new SimpleStringProperty (""); + + if ((pv != null) + && + (pv.getName () != null) + ) + { + + suff = getUILanguageStringProperty (Arrays.asList (editors,LanguageStrings.project,viewertitleversionwrapper), + //" (%s)", + pv.getName ()); + + } + + return getUILanguageStringProperty (Arrays.asList (editors,LanguageStrings.project,viewertitle), + //"Editing%s: %s", + suff, + this.project.getName ()).getValue (); + + }, + this.project.projectVersionProperty ())); + + } + +} diff --git a/src/main/java/com/quollwriter/editors/ui/EditorRegister.java b/src/main/java/com/quollwriter/editors/ui/EditorRegister.java new file mode 100644 index 00000000..aa273601 --- /dev/null +++ b/src/main/java/com/quollwriter/editors/ui/EditorRegister.java @@ -0,0 +1,1164 @@ +package com.quollwriter.editors.ui; + +import java.io.File; +import java.nio.file.*; + +import java.net.*; + +import java.text.*; + +import java.util.*; + +import javafx.scene.layout.*; +import javafx.scene.control.*; +import javafx.beans.property.*; + +import org.bouncycastle.openpgp.*; + +import com.quollwriter.*; + +import com.quollwriter.data.*; + +import com.quollwriter.ui.fx.*; +import com.quollwriter.ui.fx.components.*; +import com.quollwriter.ui.fx.viewers.*; +import com.quollwriter.ui.fx.popups.*; +import com.quollwriter.editors.*; + +import static com.quollwriter.LanguageStrings.*; +import static com.quollwriter.uistrings.UILanguageStringsManager.getUILanguageStringProperty; + +public class EditorRegister extends PopupContent +{ + + public static final String POPUP_ID = "editorregister"; + + private CheckBox tcAgreeField = null; + private QuollLabel tcError = null; + private QuollFileField finder = null; + private QuollTextField emailField = null; + private QuollPasswordField passwordField = null; + private QuollTextField nameField = null; + private ImageSelector avatar = null; + private PGPKeyPair keyPair = null; + private String messagingUsername = null; + private String serviceName = null; + private boolean createCalled = false; + private boolean login = false; + private boolean tcsClicked = false; + private Wizard wizard = null; + private Form loginDetailsForm = null; + + private Map steps = new HashMap<> (); + + public EditorRegister (AbstractViewer viewer) + throws Exception + { + + super (viewer); + + final EditorRegister _this = this; + + Environment.scheduleImmediately (() -> + { + + // Create our public/private key. + try + { + + _this.keyPair = EditorsUtils.generateKeyPair (); + + } catch (Exception e) { + + Environment.logError ("Unable to generate key pair", + e); + + } + + }); + + this.wizard = Wizard.builder () + .startStepId (this.getStartStepId ()) + .nextStepIdProvider (currId -> + { + + return getNextStepId (currId); + + }) + .previousStepIdProvider (currId -> + { + + return getPreviousStepId (currId); + + }) + .nextButtonLabelProvider ((currId, wizard) -> + { + + if ((currId != null) + && + (currId.equals ("existing")) + ) + { + + return getUILanguageStringProperty (LanguageStrings.wizard,buttons,Wizard.FINISH_BUTTON_ID); + //"Finish"; + + } + + if ((currId != null) + && + (currId.equals ("login-details")) + ) + { + + return getUILanguageStringProperty (editors,user,register,buttons,register); + //"Register"; + + } + + return wizard.getNextButtonLabel (currId); + + }) + .stepProvider (currId -> + { + + return getStep (currId); + + }) + .onCancel (ev -> + { + + this.close (); + + }) + .onFinish (ev -> + { + + this.handleFinish (); + + this.close (); + + }) + .nextStepCheck ((currId, nextId) -> + { + + return this.handleStepChange (currId, + nextId); + + }) + .previousStepCheck ((currId, prevId) -> + { + + return this.handleStepChange (currId, prevId); + + }) + .onStepShow (ev -> + { + + this.enableButtons (ev.getWizard (), + ev.getCurrentStepId ()); + + }) + .build (); + + VBox b = new VBox (); + VBox.setVgrow (this.wizard, Priority.ALWAYS); + b.getChildren ().addAll (this.wizard); + + this.getChildren ().addAll (b); + + } +/* + public String getWindowTitle () + { + + return "Register for the Editor Service"; + + } + + public String getHeaderTitle () + { + + return this.getWindowTitle (); + + } + + public String getHeaderIconType () + { + + return "editors"; + + } +*/ + public String getFirstHelpText () + { + + return "Help!"; + + } + + public boolean handleFinish () + { + + // Init the editors db. + try + { + + EditorsEnvironment.initDB (this.finder.getFile ()); + + } catch (Exception e) { + + Environment.logError ("Unable to init editors database", + e); + + ComponentUtils.showErrorMessage (this.viewer, + getUILanguageStringProperty (editors,user,register,actionerror)); + //"Unable to init editors database"); + + // Clean up db files? + + return true; + + } + + // Save the directory away for the editors db. (user property) + try + { + + EditorsEnvironment.setEditorsProperty (Constants.QW_EDITORS_DB_DIR_PROPERTY_NAME, + this.finder.getFile ().toString ()); + + } catch (Exception e) { + + Environment.logError ("Unable to save editors database location", + e); + + ComponentUtils.showErrorMessage (this.viewer, + getUILanguageStringProperty (editors,user,register,actionerror)); + //"Unable to save editors database location"); + + return true; + + } + + // Set the credentials. + if (!this.login) + { + + try + { + + EditorsEnvironment.initUserCredentials (this.emailField.getText ().trim ().toLowerCase (), + null, //new String (this.passwordField.getPassword ()), + this.serviceName, + this.messagingUsername, + this.keyPair.getPublicKey (), + this.keyPair.getPrivateKey ()); + + // Save the name/picture away. + String n = this.nameField.getText ().trim (); + + if (n.length () == 0) + { + + n = null; + + } + + EditorsEnvironment.setUserInformation (n, + this.avatar.getImage ()); + + } catch (Exception e) { + + Environment.logError ("Unable to save user information/credentials", + e); + + ComponentUtils.showErrorMessage (this.viewer, + getUILanguageStringProperty (editors,user,register,actionerror)); + //"Unable to save your details"); + + return true; + + } + + } else { + + EditorsEnvironment.goOnline (null, + null, + null, + null); + + } + + try + { + + this.viewer.viewEditors (); + + } catch (Exception e) { + + Environment.logError ("Unable to show editors", + e); + + } + + return true; + + } +/* +TODO Remove + public String getNextButtonLabel (String currStage) + { + + if ((currStage != null) + && + (currStage.equals ("existing")) + ) + { + + return getUIString (wizard,buttons,FINISH_BUTTON_ID); + //"Finish"; + + } + + if ((currStage != null) + && + (currStage.equals ("login-details")) + ) + { + + return getUIString (editors,user,register,buttons,register); + //"Register"; + + } + + return super.getNextButtonLabel (currStage); + + } +*/ + + public String getNextStepId (String currStage) + { + + if (currStage == null) + { + + return "start"; + + } + + if (currStage.equals ("start")) + { + + return "dir"; + + } + + if (currStage.equals ("dir")) + { + + return "about"; + + } + + if (currStage.equals ("login-details")) + { + + return "finish"; + + } + + if (currStage.equals ("about")) + { + + return "login-details"; + + } + + if (currStage.equals ("finish")) + { + + } + + return null; + + } + + public String getPreviousStepId (String currStage) + { + + if (currStage == null) + { + + return null; + + } + + if (currStage.equals ("existing")) + { + + return "start"; + + } + + if (currStage.equals ("dir")) + { + + return "start"; + + } + + if (currStage.equals ("start")) + { + + return null; + + } + + if (currStage.equals ("login-details")) + { + + return "about"; + + } + + if (currStage.equals ("about")) + { + + return "dir"; + + } + + if (currStage.equals ("finish")) + { + + return null; + + } + + return null; + + } + + public boolean handleStepChange (String oldStage, + String newStage) + { + + if (oldStage == null) + { + + return true; + + } + + if ((oldStage.equals ("finish")) + && + (this.createCalled) + ) + { + + return true; + + } + + if (("existing".equals (oldStage)) + && + ("start".equals (newStage)) + ) + { + + this.login = false; + return true; + + } + + if ((oldStage.equals ("start")) + && + (newStage.equals ("existing")) + ) + { + + return true; + + } + + if (oldStage.equals ("start")) + { + + if (!this.tcsClicked) + { + + QuollPopup.messageBuilder () + .title (editors,user,register,stages,start,reminderpopup,title) + .message (editors,user,register,stages,start,reminderpopup,text) + .inViewer (this.viewer) + .closeButton () + .build (); + + } + + } + + if (oldStage.equals ("dir")) + { + + if (newStage.equals ("start")) + { + + return true; + + } + + if (Files.exists (Utils.getQuollWriterDirFile (this.finder.getFile ()))) + { + + return false; + + } + + return true; + + } + + if ((oldStage.equals ("login-details")) + && + (newStage.equals ("finish")) + ) + { + + this.loginDetailsForm.hideLoading (); + this.loginDetailsForm.hideError (); + + final EditorRegister _this = this; + + String email = this.emailField.getText ().trim (); + + int atInd = email.indexOf ('@'); + + int dotInd = email.indexOf ('.', + atInd); + + if ((email.length () == 0) + || + (atInd == -1) + || + (dotInd == -1) + || + (email.length () - 1 == dotInd) + ) + { + + this.loginDetailsForm.showError (getUILanguageStringProperty (editors,user,register,stages,logindetails,errors,invalidemail)); + //"Please provide a valid email address."); + + return false; + + } + + String pwd = this.passwordField.getPassword1 (); + String pwd2 = this.passwordField.getPassword2 (); + + if (pwd.length () == 0) + { + + this.loginDetailsForm.showError (getUILanguageStringProperty (editors,user,register,stages,logindetails,errors,nopassword)); + //"Please provide a password."); + + return false; + + } + + if (pwd2.length () == 0) + { + + this.loginDetailsForm.showError (getUILanguageStringProperty (editors,user,register,stages,logindetails,errors,confirmpassword)); + //"Please confirm your password."); + + return false; + + } + + if (!pwd.equals (pwd2)) + { + + this.loginDetailsForm.showError (getUILanguageStringProperty (editors,user,register,stages,logindetails,errors,nomatch)); + //"Your passwords do not match."); + + return false; + + } + + if (pwd.length () < 8) + { + + this.loginDetailsForm.showError (getUILanguageStringProperty (editors,user,register,stages,logindetails,errors,minlength)); + //"Your password must be at least 8 characters long."); + + return false; + + } + + // Create the account, show the saving. + this.wizard.enableButton (Wizard.FINISH_BUTTON_ID, + false); + this.wizard.enableButton (Wizard.PREVIOUS_BUTTON_ID, + false); + this.wizard.enableButton (Wizard.CANCEL_BUTTON_ID, + false); + + this.loginDetailsForm.showLoading (getUILanguageStringProperty (editors,user,register,stages,logindetails,LanguageStrings.saving)); + + this.emailField.setDisable (true); + this.passwordField.setFieldsDisable (true); + + try + { + + EditorsEnvironment.getEditorsWebServiceHandler ().createAccount (email, + pwd, + this.keyPair.getPublicKey (), + res -> + { + + Map d = (Map) res.getReturnObject (); + + this.messagingUsername = (String) d.get ("username"); + this.serviceName = (String) d.get ("servicename"); + + this.createCalled = true; + + UIUtils.runLater (() -> + { + + this.wizard.showStep ("finish"); + + }); + + }, + res -> + { + + UIUtils.runLater (() -> + { + + this.wizard.enableButton (Wizard.FINISH_BUTTON_ID, + true); + this.wizard.enableButton (Wizard.PREVIOUS_BUTTON_ID, + true); + this.wizard.enableButton (Wizard.CANCEL_BUTTON_ID, + true); + + this.loginDetailsForm.hideLoading (); + + // Handle parameter errors, then other error types. + + _this.emailField.setDisable (false); + _this.passwordField.setFieldsDisable (false); + _this.loginDetailsForm.showError (new SimpleStringProperty (getUILanguageStringProperty (editors,user,register,actionerror).getValue () + " " + res.getErrorMessage ())); + + }); + + }); + + } catch (Exception e) { + + Environment.logError ("Unable to create account", + e); + + ComponentUtils.showErrorMessage (this.viewer, + getUILanguageStringProperty (editors,user,register,actionerror)); + //"Unable to create account, please contact Quoll Writer support for assistance."); + + } + + return false; + + } + + return true; + + } + + public String getStartStepId () + { + + return "start"; + + } + + private Wizard.Step createStartStep () + { + + Wizard.Step ws = new Wizard.Step (); + + List prefix = Arrays.asList (editors,user,register,stages,start); + + ws.title = getUILanguageStringProperty (Utils.newList (prefix,title)); + //"Getting started"; + + QuollHyperlink tc = QuollHyperlink.builder () + .label (getUILanguageStringProperty (Utils.newList (prefix,labels,viewtandc))) + .styleClassName (StyleClassNames.INFORMATION) + .onAction (ev -> + { + + this.tcsClicked = true; + UIUtils.openURL (this.viewer, + Environment.getQuollWriterHelpLink ("editor-mode/terms-and-conditions", + null)); + + }) + .build (); + + this.tcAgreeField = QuollCheckBox.builder () + .label (getUILanguageStringProperty (Utils.newList (prefix,labels,agreetandc))) + .build (); + + Form f = Form.builder () + .description (getUILanguageStringProperty (Utils.newList (prefix,text), + Environment.getQuollWriterHelpLink ("editor-mode/overview", + null))) + .item (tc) + .item (this.tcAgreeField) + .build (); + + VBox.setVgrow (f, + Priority.ALWAYS); + + this.tcAgreeField.setOnAction (ev -> + { + + f.hideError (); + + this.wizard.enableButton (Wizard.NEXT_BUTTON_ID, + this.tcAgreeField.isSelected ()); + + }); + + VBox b = new VBox (); + + QuollHyperlink reg = QuollHyperlink.builder () + .label (getUILanguageStringProperty (Utils.newList (prefix,labels,alreadyregistered))) + .styleClassName (StyleClassNames.EDITORS) + .onAction (ev -> + { + + this.wizard.showStep ("existing"); + + }) + .build (); + + b.getChildren ().addAll (f, reg); + + ws.content = b; + + return ws; + + } + + private Wizard.Step createExistingStep () + { + + Wizard.Step ws = new Wizard.Step (); + + List prefix = Arrays.asList (editors,user,register,stages,exists); + + this.login = true; + + ws.title = getUILanguageStringProperty (Utils.newList (prefix,title)); + //"Find an existing {editors} database"; + + QuollTextView desc = QuollTextView.builder () + .styleClassName (StyleClassNames.DESCRIPTION) + .inViewer (this.viewer) + .text (getUILanguageStringProperty (Utils.newList (prefix,text))) + .build (); + + QuollLabel message = QuollLabel.builder () + .styleClassName (StyleClassNames.INFORMATION) + .build (); + + message.setVisible (false); + + this.finder = QuollFileField.builder () + .chooserTitle (getUILanguageStringProperty (Utils.newList (prefix,LanguageStrings.finder,title))) + .limitTo (QuollFileField.Type.directory) + .initialFile (Environment.getUserQuollWriterDirPath ()) + .withViewer (viewer) + .findButtonTooltip (getUILanguageStringProperty (Utils.newList (prefix,LanguageStrings.finder,tooltip))) + .build (); + + this.finder.fileProperty ().addListener ((pr, oldv, newv) -> + { + + // See if it's an existing editors db, if so ask. + + if (!EditorsEnvironment.isEditorsDBDir (this.finder.getFile ())) + { + + // Show an error + message.setText (getUILanguageStringProperty (Arrays.asList (editors,user,register,stages,exists,errors,invalidvalue), + Constants.EDITORS_DB_FILE_NAME_PREFIX)); + message.pseudoClassStateChanged (StyleClassNames.ERROR_PSEUDO_CLASS, true); + + this.wizard.enableButton (Wizard.NEXT_BUTTON_ID, + false); + + this.wizard.enableButton (Wizard.FINISH_BUTTON_ID, + false); + + } else { + + // See if the project is already in their project list. + + message.setText (getUILanguageStringProperty (editors,user,register,stages,exists,labels,confirm)); + message.pseudoClassStateChanged (StyleClassNames.OK_PSEUDO_CLASS, true); + + // Set the seen sidebar property to ensure the welcome tab doesn't display. + try + { + + EditorsEnvironment.setEditorsProperty (Constants.QW_EDITORS_SERVICE_EDITORS_SIDEBAR_SEEN_PROPERTY_NAME, + true); + + } catch (Exception e) { + + Environment.logError ("Unable to set editors sidebar seen property", + e); + + } + + this.wizard.enableButton (Wizard.FINISH_BUTTON_ID, + true); + + } + + message.setVisible (true); + + // Open the database and show the information? + + }); + + VBox b = new VBox (); + + b.getChildren ().addAll (desc, message, this.finder); + + ws.content = b; + + return ws; + + } + + private Wizard.Step createDirStep () + { + + Wizard.Step ws = new Wizard.Step (); + + List prefix = Arrays.asList (editors,user,register,stages,selectfolder); + + ws.title = getUILanguageStringProperty (Utils.newList (prefix,title)); + //"Where to store editor information?"; + + QuollTextView desc = QuollTextView.builder () + .styleClassName (StyleClassNames.DESCRIPTION) + .inViewer (this.viewer) + .text (getUILanguageStringProperty (Utils.newList (prefix,text))) + .build (); + + QuollLabel finderError = QuollLabel.builder () + .label (getUILanguageStringProperty (Utils.newList (prefix,errors,invalidvalue))) + .styleClassName (StyleClassNames.ERROR) + .build (); + + finderError.setVisible (false); + + this.finder = QuollFileField.builder () + .chooserTitle (getUILanguageStringProperty (Utils.newList (prefix,LanguageStrings.finder,title))) + .limitTo (QuollFileField.Type.directory) + .initialFile (Environment.getUserPath ("editors")) + .withViewer (viewer) + .findButtonTooltip (getUILanguageStringProperty (Utils.newList (prefix,LanguageStrings.finder,tooltip))) + .build (); + + if (EditorsEnvironment.isEditorsDBDir (this.finder.getFile ())) + { + + finderError.setVisible (true); + + } + + this.finder.fileProperty ().addListener ((pr, oldv, newv) -> + { + + finderError.setVisible (false); + + // See if it's an existing editors db, if so ask. + if (EditorsEnvironment.isEditorsDBDir (this.finder.getFile ())) + { + + //if (Files.exists (Utils.getQuollWriterDirFile (this.finder.getFile ()))) + //{ + + finderError.setVisible (true); + this.wizard.enableButton (Wizard.NEXT_BUTTON_ID, + false); + + } else { + + this.wizard.enableButton (Wizard.NEXT_BUTTON_ID, + true); + + } + + }); + + // Support encryption? + + VBox b = new VBox (); + b.getChildren ().addAll (desc, finderError, this.finder); + + ws.content = b; + + return ws; + + } + + private Wizard.Step createFinishStep () + { + + Wizard.Step ws = new Wizard.Step (); + + List prefix = Arrays.asList (editors,user,register,stages,finish); + + ws.title = getUILanguageStringProperty (Utils.newList (prefix,title)); + //"Account created, just one more step"; + + QuollTextView desc = QuollTextView.builder () + .styleClassName (StyleClassNames.DESCRIPTION) + .inViewer (this.viewer) + .text (getUILanguageStringProperty (Utils.newList (prefix,text), + this.emailField.getText ().trim ())) + .build (); + + QuollLabel l = QuollLabel.builder () + .label (getUILanguageStringProperty (Utils.newList (prefix,labels,check))) + .build (); + + VBox b = new VBox (); + b.getChildren ().addAll (desc, l); + + ws.content = l; + + return ws; + + } + + private Wizard.Step createAboutStep () + { + + Wizard.Step ws = new Wizard.Step (); + + List prefix = Arrays.asList (editors,user,register,stages,about); + + ws.title = getUILanguageStringProperty (Utils.newList (prefix,title)); + //"About you"; + + QuollTextView desc = QuollTextView.builder () + .styleClassName (StyleClassNames.DESCRIPTION) + .inViewer (this.viewer) + .text (getUILanguageStringProperty (Utils.newList (prefix,text))) + .build (); + + this.nameField = QuollTextField.builder () + .build (); + + this.avatar = ImageSelector.builder () + .withViewer (this.viewer) + .build (); + + Form f = Form.builder () + .item (getUILanguageStringProperty (Utils.newList (prefix,labels,name)), + this.nameField) + .item (getUILanguageStringProperty (Utils.newList (prefix,labels,LanguageStrings.avatar)), + this.avatar) + .build (); + + VBox b = new VBox (); + b.getChildren ().addAll (desc, f); + ws.content = b; + + return ws; + + } + + private Wizard.Step createLoginDetailsStep () + { + + Wizard.Step ws = new Wizard.Step (); + List prefix = Arrays.asList (editors,user,register,stages,logindetails); + + ws.title = getUILanguageStringProperty (Utils.newList (prefix,title)); + //"Your login details"; + + this.emailField = QuollTextField.builder () + .build (); + this.passwordField = QuollPasswordField.builder () + .passwordLabel (getUILanguageStringProperty (Utils.newList (prefix,labels,password))) + .confirmLabel (getUILanguageStringProperty (Utils.newList (prefix,labels,confirmpassword))) + .build (); + + this.loginDetailsForm = Form.builder () + .description (getUILanguageStringProperty (Utils.newList (prefix,text))) + .item (getUILanguageStringProperty (Utils.newList (prefix,labels,email)), + this.emailField) + .item (getUILanguageStringProperty (Utils.newList (prefix,labels,password)), + this.passwordField.getPasswordField1 ()) + .item (getUILanguageStringProperty (Utils.newList (prefix,labels,confirmpassword)), + this.passwordField.getPasswordField2 ()) + .build (); + + // TODO Use form error/loading? + VBox b = new VBox (); + b.getChildren ().addAll (this.loginDetailsForm); + + ws.content = b; + + return ws; + + } + + public Wizard.Step getStep (String stepId) + { + + final EditorRegister _this = this; + + Wizard.Step ws = this.steps.get (stepId); + + if (ws != null) + { + + return ws; + + } + + if (stepId.equals ("start")) + { + + ws = this.createStartStep (); + + } + + if (stepId.equals ("existing")) + { + + ws = this.createExistingStep (); + + } + + if (stepId.equals ("dir")) + { + + ws = this.createDirStep (); + + } + + if (stepId.equals ("finish")) + { + + ws = this.createFinishStep (); + + } + + if (stepId.equals ("about")) + { + + ws = this.createAboutStep (); + + } + + if (stepId.equals ("login-details")) + { + + ws = this.createLoginDetailsStep (); + + } + + this.steps.put (stepId, + ws); + + return ws; + + } + + private void enableButtons (Wizard wiz, + String currentStage) + { + + if ("dir".equals (currentStage)) + { + + if (EditorsEnvironment.isEditorsDBDir (this.finder.getFile ())) + { + + this.wizard.enableButton (Wizard.NEXT_BUTTON_ID, + false); + + return; + + } + + } + + if ("start".equals (currentStage)) + { + + if ((this.tcAgreeField == null) + || + (!this.tcAgreeField.isSelected ()) + ) + { + + wiz.enableButton (Wizard.NEXT_BUTTON_ID, + false); + return; + + } + + } + + wiz.enableButton (Wizard.NEXT_BUTTON_ID, + true); + + if (currentStage.equals ("existing")) + { + + wiz.enableButton (Wizard.FINISH_BUTTON_ID, + false); + + } + + } + + @Override + public QuollPopup createPopup () + { + + QuollPopup p = QuollPopup.builder () + .title (getUILanguageStringProperty (editors,user,register,LanguageStrings.popup,title)) + .styleClassName (StyleClassNames.EDITORREGISTER) + .styleSheet (StyleClassNames.EDITORREGISTER) + .headerIconClassName (StyleClassNames.CONTACTS) + .hideOnEscape (true) + .withClose (true) + .content (this) + .popupId (POPUP_ID) + .withViewer (this.viewer) + .removeOnClose (true) + .build (); + p.requestFocus (); + + return p; + + } + +} diff --git a/src/main/java/com/quollwriter/editors/ui/EditorRemovedMessageBox.java b/src/main/java/com/quollwriter/editors/ui/EditorRemovedMessageBox.java new file mode 100644 index 00000000..e3233ce4 --- /dev/null +++ b/src/main/java/com/quollwriter/editors/ui/EditorRemovedMessageBox.java @@ -0,0 +1,149 @@ +package com.quollwriter.editors.ui; + +import java.util.*; + +import javafx.beans.property.*; +import javafx.scene.layout.*; +import javafx.scene.control.*; +import javafx.scene.*; + +import com.quollwriter.*; +import com.quollwriter.data.*; +import com.quollwriter.data.editors.*; +import com.quollwriter.editors.messages.*; +import com.quollwriter.editors.*; +import com.quollwriter.ui.fx.components.*; +import com.quollwriter.ui.fx.viewers.*; +import com.quollwriter.ui.fx.*; + +import static com.quollwriter.LanguageStrings.*; +import static com.quollwriter.uistrings.UILanguageStringsManager.getUILanguageStringProperty; + +public class EditorRemovedMessageBox extends MessageBox +{ + + private VBox responseBox = null; + + public EditorRemovedMessageBox (EditorRemovedMessage mess, + AbstractViewer viewer) + { + + super (mess, + viewer); + + this.getStyleClass ().add (StyleClassNames.EDITORREMOVED); + + this.binder.addChangeListener (mess.dealtWithProperty (), + (pr, oldv, newv) -> + { + + if (this.message.isDealtWith ()) + { + + if (this.responseBox != null) + { + + this.responseBox.setVisible (false); + + } + + } + + }); + + StringProperty title = getUILanguageStringProperty (editors,messages,contactremoved,(this.message.isSentByMe () ? sent : received),LanguageStrings.title); + StringProperty text = getUILanguageStringProperty (Arrays.asList (editors,messages,contactremoved,(this.message.isSentByMe () ? sent : received),LanguageStrings.text), + this.message.getEditor ().mainNameProperty ()); + + this.getChildren ().add (Header.builder () + .title (title) + .iconClassName (StyleClassNames.DELETE) + .styleClassName (StyleClassNames.SUBTITLE) + .build ()); + + this.getChildren ().add (QuollTextView.builder () + .styleClassName (StyleClassNames.DESCRIPTION) + .text (text) + .inViewer (this.viewer) + .build ()); + + if (!this.message.isDealtWith ()) + { + + // Show the response. + this.responseBox = new VBox (); + this.responseBox.managedProperty ().bind (this.responseBox.visibleProperty ()); + + this.getChildren ().add (this.responseBox); + + this.responseBox.getChildren ().add (QuollTextView.builder () + .text (getUILanguageStringProperty (Arrays.asList (editors,messages,contactremoved,received,undealtwith,LanguageStrings.text), + //"Clicking on the button below will remove %s from your list of current {contacts}. You can still get access to them in the options menu of the {Contacts} sidebar via the View the previous {contacts} item.", + this.message.getEditor ().mainNameProperty ())) + .inViewer (this.viewer) + .styleClassName (StyleClassNames.DESCRIPTION) + .build ()); + + final EditorEditor ed = this.message.getEditor (); + + this.getChildren ().add (QuollButtonBar.builder () + .button (QuollButton.builder () + .label (editors,messages,contactremoved,received,undealtwith,buttons,confirm) + .onAction (ev -> + { + + try + { + + // Unsubscribe. + EditorsEnvironment.getMessageHandler ().unsubscribeFromEditor (ed); + + // For all projects, if they are a project editor then set them as previous. + EditorsEnvironment.removeEditorAsProjectEditorForAllProjects (ed); + + // Uupdate the editor to be previous. + ed.setEditorStatus (EditorEditor.EditorStatus.previous); + + EditorsEnvironment.updateEditor (ed); + + this.responseBox.setVisible (false); + + this.message.setDealtWith (true); + + EditorsEnvironment.updateMessage (this.message); + + // Offer to remove any projects we are editing for them. + EditorsUIUtils.showDeleteProjectsForEditor (this.viewer, + this.message.getEditor (), + null); + + } catch (Exception e) { + + Environment.logError ("Unable to update editor: " + + ed, + e); + + ComponentUtils.showErrorMessage (this.viewer, + getUILanguageStringProperty (editors,messages,update,actionerror)); + //"Unable to update {contact}, please contact Quoll Writer support for assistance."); + + return; + + } + + }) + .build ()) + .build ()); + + } + + } + + public boolean isAutoDealtWith () + { + + return false; + + } + +} diff --git a/src/main/java/com/quollwriter/editors/ui/EditorsUIUtils.java b/src/main/java/com/quollwriter/editors/ui/EditorsUIUtils.java new file mode 100644 index 00000000..cb615ff0 --- /dev/null +++ b/src/main/java/com/quollwriter/editors/ui/EditorsUIUtils.java @@ -0,0 +1,3849 @@ +package com.quollwriter.editors.ui; + +import java.util.*; +import java.util.function.*; +import java.util.stream.*; +import java.net.*; +import java.io.*; +import java.awt.image.*; +import java.time.*; + +import javafx.beans.property.StringProperty; +import javafx.beans.property.SimpleStringProperty; +import javafx.scene.*; +import javafx.scene.control.*; +import javafx.scene.layout.*; +import javafx.scene.image.*; +import javafx.scene.input.*; +import javafx.embed.swing.*; +import javafx.collections.*; + +import org.josql.*; + +import com.quollwriter.*; +import com.quollwriter.events.*; +import com.quollwriter.data.comparators.*; +import com.quollwriter.editors.ui.sidebars.*; +import com.quollwriter.data.*; +import com.quollwriter.data.editors.*; +import com.quollwriter.ui.fx.*; +import com.quollwriter.ui.fx.panels.*; +import com.quollwriter.ui.fx.components.*; +import com.quollwriter.editors.*; +import com.quollwriter.editors.messages.*; +import com.quollwriter.text.*; + +import com.quollwriter.ui.fx.components.ComponentUtils; +import com.quollwriter.ui.fx.components.QuollPopup; +import com.quollwriter.ui.fx.components.Form; +import com.quollwriter.ui.fx.components.Viewer; +import com.quollwriter.ui.fx.components.QuollHyperlink; +import com.quollwriter.ui.fx.components.QuollLabel; +import com.quollwriter.ui.fx.components.QuollTextView; +import com.quollwriter.ui.fx.components.QuollButtonBar; +import com.quollwriter.ui.fx.components.QuollButton; +import com.quollwriter.ui.fx.components.QScrollPane; +import com.quollwriter.ui.fx.components.QuollTextArea; +import com.quollwriter.ui.fx.components.ImageSelector; +import com.quollwriter.ui.fx.components.NamedObjectTree; +import com.quollwriter.ui.fx.components.QuollTreeView; +import com.quollwriter.ui.fx.components.QuollTextField; +import com.quollwriter.ui.fx.components.Notification; +import com.quollwriter.ui.fx.StyleClassNames; +import com.quollwriter.ui.fx.State; +import com.quollwriter.ui.fx.viewers.*; +import com.quollwriter.ui.fx.popups.*; +import com.quollwriter.ui.fx.UIUtils; +import com.quollwriter.ui.fx.sidebars.*; +import com.quollwriter.uistrings.UILanguageStringsManager; + +import static com.quollwriter.LanguageStrings.*; +import static com.quollwriter.uistrings.UILanguageStringsManager.getUILanguageStringProperty; + +public class EditorsUIUtils +{ + + private static EditorLoginPopup editorLogin = null; + private static EditorMessageFilter defaultViewableMessageFilter = null; + private static EditorMessageFilter importantMessageFilter = null; + + static + { + + // Defines the messages that can be "viewed" by the user. + Project np = null; + + EditorsUIUtils.defaultViewableMessageFilter = new DefaultEditorMessageFilter (np, + EditorChatMessage.MESSAGE_TYPE, + EditorInfoMessage.MESSAGE_TYPE, + NewProjectMessage.MESSAGE_TYPE, + NewProjectResponseMessage.MESSAGE_TYPE, + ProjectCommentsMessage.MESSAGE_TYPE, + InviteMessage.MESSAGE_TYPE, + InviteResponseMessage.MESSAGE_TYPE, + ProjectEditStopMessage.MESSAGE_TYPE, + UpdateProjectMessage.MESSAGE_TYPE, + EditorRemovedMessage.MESSAGE_TYPE); + + EditorsUIUtils.importantMessageFilter = new EditorMessageFilter () + { + + @Override + public boolean accept (EditorMessage m) + { + + if (!EditorsUIUtils.getDefaultViewableMessageFilter ().accept (m)) + { + + return false; + + } + + if (m.isDealtWith ()) + { + + return false; + + } + /* + if (m.getMessageType ().equals (EditorChatMessage.MESSAGE_TYPE)) + { + + return false; + + } + */ + /* + if (m.getMessageType ().equals (ProjectCommentsMessage.MESSAGE_TYPE)) + { + + return false; + + } +*/ + return true; + + } + + }; + + }; + + public static EditorMessageFilter getImportantMessageFilter () + { + + return EditorsUIUtils.importantMessageFilter; + + } + + public static EditorMessageFilter getDefaultViewableMessageFilter () + { + + return EditorsUIUtils.defaultViewableMessageFilter; + + } + + public static void showDeleteAccount (final AbstractViewer viewer) + { + + // Remove all editors. + + // Send project edit stop for all projects they are editing. + + // Remove account. + + java.util.List prefix = Arrays.asList (editors,user,deleteaccount,popup); + + //String s = "To delete your account please enter the word Yes in the box below.

    Note: Your {contacts} database will not be deleted allowing you to keep a record of what you have sent and received. If you create another account you will not be able to use your current database.

    Warning: deleting your account means you will no longer be able to send messages to any of your {contacts} or receive messages from them. A message will be sent to each of them telling them you have removed them.

    "; + + QuollPopup.yesConfirmTextEntryBuilder () + .styleClassName (StyleClassNames.DELETE) + .title (Utils.newList (prefix,title)) + .description (Utils.newList (prefix,text)) + .confirmButtonLabel (Utils.newList (prefix,buttons,confirm)) + .cancelButtonLabel (Utils.newList (prefix,buttons,cancel)) + .onConfirm (ev -> + { + + final String dbDir = EditorsEnvironment.getEditorsProperty (Constants.QW_EDITORS_DB_DIR_PROPERTY_NAME); + + final Notification notify = viewer.addNotification (getUILanguageStringProperty (editors,user,deleteaccount,notification), + //"Deleting your Editors Service account, please wait. This sometimes takes a little while...", + StyleClassNames.DELETE, + -1); + + EditorsEnvironment.deleteUserAccount (() -> + { + + UIUtils.runLater (() -> + { + // Remove the editors sidebar. + Environment.removeSideBarFromAllProjectViewers (EditorsSideBar.SIDEBAR_ID); + + viewer.removeNotification (notify); + + String url = ""; + + try + { + + url = new File (dbDir).toURI ().toURL ().toString (); + + } catch (Exception e) { + + Environment.logError ("Unable to convert file: " + + dbDir + + " to a url", + e); + + } + + QuollPopup.messageBuilder () + .inViewer (viewer) + .title (editors,user,deleteaccount,confirmpopup,title) + .message (getUILanguageStringProperty (Arrays.asList (editors,user,deleteaccount,confirmpopup,text), + url)) + .closeButton () + .build (); + + }); + + }, + // On error + (exp) -> + { + + ComponentUtils.showErrorMessage (getUILanguageStringProperty (editors,user,deleteaccount,actionerror)); + //"Unable to delete your account, please contact Quoll Writer support for assistance."); + + }); + + }) + .build (); + + } + + /** + * If we are editing any projects for any editors then show a popup offering to delete + * the projects. Once the delete is complete (or there are no projects) call onRemoveComplete. + * If any of the projects are open then they are force closed first. + * + */ + public static void showDeleteProjectsForAllEditors (final AbstractViewer viewer, + final Runnable onRemoveComplete) + { + + Set eds = new HashSet (); + + Set edProjs = null; + + try + { + + edProjs = Environment.getAllProjectInfos (Project.EDITOR_PROJECT_TYPE); + + } catch (Exception e) { + + Environment.logError ("Unable to get all editor projects", + e); + + ComponentUtils.showErrorMessage (viewer, + getUILanguageStringProperty (editors,user,deletealleditorprojects,actionerror)); + //"Unable to get all {projects}, please contact Quoll Support for assistance."); + + if (onRemoveComplete != null) + { + + Environment.scheduleImmediately (onRemoveComplete); + + } + + return; + + } + + for (ProjectInfo p : edProjs) + { + + eds.add (p.getForEditor ()); + + } + + if (edProjs.size () > 0) + { + + final Runnable deleteEditorProjs = () -> + { + + Set _edProjs = null; + + try + { + + _edProjs = Environment.getAllProjectInfos (Project.EDITOR_PROJECT_TYPE); + + } catch (Exception e) { + + Environment.logError ("Unable to get all editor projects", + e); + + ComponentUtils.showErrorMessage (viewer, + getUILanguageStringProperty (editors,user,deletealleditorprojects,actionerror)); + //"Unable to get all {projects}, please contact Quoll Support for assistance."); + + if (onRemoveComplete != null) + { + + Environment.scheduleImmediately (onRemoveComplete); + + } + + return; + + } + + for (ProjectInfo p : _edProjs) + { + + try + { + + Environment.deleteProject (p, + (Runnable) null); + + } catch (Exception e) { + + Environment.logError ("Unable to delete project: " + + p, + e); + + ComponentUtils.showErrorMessage (viewer, + getUILanguageStringProperty (editors,user,deletealleditorprojects,actionerror)); + + } + + } + + if (onRemoveComplete != null) + { + + Environment.scheduleImmediately (onRemoveComplete); + + } + + }; + + java.util.List prefix = Arrays.asList (editors,user,deletealleditorprojects,popup); + + QuollPopup.yesConfirmTextEntryBuilder () + .title (Utils.newList (prefix,title)) + .styleClassName (StyleClassNames.DELETE) + .description (getUILanguageStringProperty (Utils.newList (prefix,text), + Environment.formatNumber (edProjs.size ()), + Environment.formatNumber (eds.size ()))) + .confirmButtonLabel (Utils.newList (prefix,buttons,confirm)) + .cancelButtonLabel (Utils.newList (prefix,buttons,cancel)) + .onConfirm (ev -> + { + + Environment.scheduleImmediately (deleteEditorProjs); + + }) + .onCancel (ev -> + { + + Environment.scheduleImmediately (onRemoveComplete); + + }) + .build (); + + } else { + + if (onRemoveComplete != null) + { + + Environment.scheduleImmediately (onRemoveComplete); + + } + + } + + } + + /** + * If we are editing any projects for the specified editor then show a popup offering to delete + * the projects. Once the delete is complete (or there are no projects) call onRemoveComplete. + * If any of the projects are open then they are force closed first. + * + */ + public static void showDeleteProjectsForEditor (final AbstractViewer viewer, + final EditorEditor ed, + final Runnable onRemoveComplete) + { + + // Remove all projects for the editor. + Set edProjs = null; + + try + { + + edProjs = EditorsEnvironment.getProjectsForEditor (ed); + + } catch (Exception e) { + + Environment.logError ("Unable to get projects for editor: " + + ed, + e); + + ComponentUtils.showErrorMessage (viewer, + getUILanguageStringProperty (editors,user,deleteprojectsforeditor,actionerror)); + //"Unable to get {projects} for {editor}, please contact Quoll Writer support for assistance."); + + return; + + } + + if (edProjs.size () > 0) + { + + final Runnable deleteEditorProjs = () -> + { + + Set _edProjs = null; + + try + { + + _edProjs = EditorsEnvironment.getProjectsForEditor (ed); + + } catch (Exception e) { + + Environment.logError ("Unable to get projects for editor: " + + ed, + e); + + ComponentUtils.showErrorMessage (viewer, + getUILanguageStringProperty (editors,user,deleteprojectsforeditor,actionerror)); + //"Unable to get {projects} for {contact}, please contact Quoll Writer support for assistance."); + + return; + + } + + for (ProjectInfo p : _edProjs) + { + + // Just to be sure. + if (!p.getType ().equals (Project.EDITOR_PROJECT_TYPE)) + { + + continue; + + } + + Environment.deleteProject (p); + + } + + if (onRemoveComplete != null) + { + + Environment.scheduleImmediately (onRemoveComplete); + + } + + }; + + List prefix = Arrays.asList (editors,user,deleteprojectsforeditor,popup); + + QuollPopup.yesConfirmTextEntryBuilder () + .title (Utils.newList (prefix,title)) + .styleClassName (StyleClassNames.DELETE) + .description (getUILanguageStringProperty (Utils.newList (prefix,text), + Environment.formatNumber (edProjs.size ()), + ed.mainNameProperty ())) + .confirmButtonLabel (Utils.newList (prefix,buttons,confirm)) + .cancelButtonLabel (Utils.newList (prefix,buttons,cancel)) + .onConfirm (ev -> + { + + Environment.scheduleImmediately (deleteEditorProjs); + + }) + .onCancel (ev -> + { + + Environment.scheduleImmediately (onRemoveComplete); + + }) + .build (); + + } else { + + if (onRemoveComplete != null) + { + + Environment.scheduleImmediately (onRemoveComplete); + + } + + } + + } + + public static void showRemoveEditor (final AbstractViewer viewer, + final EditorEditor ed, + final Runnable onRemoveComplete) + { + + // If the editor is pending then just remove them and remove the invite. + if (ed.isPending ()) + { + + List prefix = Arrays.asList (editors,editor,remove,popup); + + QuollPopup.yesConfirmTextEntryBuilder () + .styleClassName (StyleClassNames.DELETE) + .title (Utils.newList (prefix,title)) + .description (getUILanguageStringProperty (Utils.newList (prefix,text), + ed.mainNameProperty ())) + .confirmButtonLabel (Utils.newList (prefix,buttons,confirm)) + .cancelButtonLabel (Utils.newList (prefix,buttons,cancel)) + .onConfirm (ev -> + { + + EditorsEnvironment.removePendingEditor (ed, + onRemoveComplete); + + }) + .build (); + + return; + + } + + final Runnable onComplete = () -> + { + + List prefix = Arrays.asList (editors,editor,remove,confirmpopup); + + UIUtils.runLater (() -> + { + + QuollPopup.messageBuilder () + .withViewer (viewer) + .styleClassName (StyleClassNames.DELETE) + .title (Utils.newList (prefix,title)) + .closeButton () + .message (getUILanguageStringProperty (Utils.newList (prefix,text), + ed.getMainName ())) + .build (); + + }); + + }; + + java.util.List prefix = Arrays.asList (editors,editor,remove,popup); + + QuollPopup.yesConfirmTextEntryBuilder () + .title (Utils.newList (prefix,title)) + .styleClassName (StyleClassNames.DELETE) + .description (getUILanguageStringProperty (Utils.newList (prefix,text), + ed.getMainName ())) + .confirmButtonLabel (Utils.newList (prefix,buttons,confirm)) + .cancelButtonLabel (Utils.newList (prefix,buttons,cancel)) + .onConfirm (ev -> + { + + EditorsEnvironment.removeEditor (ed, + () -> + { + + EditorsUIUtils.showDeleteProjectsForEditor (Environment.getFocusedViewer (), + ed, + onComplete); + + }); + + }) + .build (); + + } + + /* + * Maybe move this to be a Form. + */ + public static void updateYourInfo (final AbstractViewer viewer) + { + + java.util.List prefix = Arrays.asList (editors,user,edit,info,popup); + + Form.Builder fb = Form.builder () + .inViewer (viewer) + .confirmButton (getUILanguageStringProperty (Utils.newList (prefix,buttons,confirm))) + .cancelButton (getUILanguageStringProperty (Utils.newList (prefix,buttons,cancel))) + .description (Utils.newList (prefix,text)); + + EditorAccount acc = EditorsEnvironment.getUserAccount (); + + final String accName = (acc.getName ()); + + QuollTextField nameF = QuollTextField.builder () + .text (accName) + .build (); + + fb.item (getUILanguageStringProperty (Utils.newList (prefix,labels,name)), + nameF); + + Image im = acc.getAvatar (); + + ImageSelector avatarSel = ImageSelector.builder () + .image (im) + .styleClassName (StyleClassNames.AVATAR) + .withViewer (viewer) + .build (); + + fb.item (getUILanguageStringProperty (Utils.newList (prefix,labels,LanguageStrings.avatar)), + avatarSel); + + Form f = fb.build (); + + QuollPopup qp = QuollPopup.formBuilder () + .title (Utils.newList (prefix,title)) + .styleClassName (StyleClassNames.EDIT) + .styleSheet ("updateeditorcontactinfo") + .form (f) + .build (); + + f.addEventHandler (Form.FormEvent.CANCEL_EVENT, + ev -> + { + + qp.close (); + + }); + + f.addEventHandler (Form.FormEvent.CONFIRM_EVENT, + ev -> + { + + f.hideError (); + + // Update the user data. + String newName = nameF.getText ().trim (); + + if (newName.length () == 0) + { + + f.showError (getUILanguageStringProperty (Utils.newList (prefix,errors,noname)));//"Please provide your name."); + return; + + } + + try + { + + EditorsEnvironment.setUserInformation (newName, + avatarSel.getImage ()); + + EditorsEnvironment.sendUserInformationToAllEditors (() -> + { + + if (EditorsEnvironment.getEditors ().size () > 0) + { + + List prefix2 = Arrays.asList (editors,user,edit,info,confirmpopup); + + UIUtils.runLater (() -> + { + + QuollPopup.messageBuilder () + .title (Utils.newList (prefix2,title)) + .message (Utils.newList (prefix2,text)) + .closeButton () + .build (); + + qp.close (); + + }); + + } + + }, + null, + null); + + } catch (Exception e) { + + Environment.logError ("Unable to update user information", + e); + + ComponentUtils.showErrorMessage (viewer, + getUILanguageStringProperty (editors,user,edit,info,actionerror)); + //"Unable to update user information, please contact Quoll Writer support for assistance."); + + } + + }); + + } + + /* + * Maybe move this to be a Form. + */ + public static void updateEditorInfo (final AbstractViewer viewer, + final EditorEditor ed) + { + + List prefix = Arrays.asList (editors,editor,edit,popup); + + Form.Builder fb = Form.builder () + .inViewer (viewer) + .confirmButton (getUILanguageStringProperty (Utils.newList (prefix,buttons,confirm))) + .cancelButton (getUILanguageStringProperty (Utils.newList (prefix,buttons,cancel))) + .description (getUILanguageStringProperty (Utils.newList (prefix,text), + ed.getMainName ())); + + String name = ed.getMyNameForEditor (); + + if (name == null) + { + + name = ed.getMainName (); + + } + + QuollTextField nameF = QuollTextField.builder () + .text (name) + .build (); + + String edOrigName = (ed.getName () != null ? ed.getName () : ed.getEmail ()); + + HBox nb = new HBox (); + nb.getChildren ().add (nameF); + HBox.setHgrow (nameF, + Priority.ALWAYS); + nb.getChildren ().add (QuollButton.builder () + .iconName (StyleClassNames.RESET) + .tooltip (getUILanguageStringProperty (Utils.newList (prefix,labels,reset,tooltip), + edOrigName)) + .onAction (ev -> + { + + nameF.setText (edOrigName); + + }) + .build ()); + + fb.item (getUILanguageStringProperty (Utils.newList (prefix,labels,LanguageStrings.name)), + nb); + + Image im = ed.getMainAvatar (); + + ImageSelector avatarSel = ImageSelector.builder () + .image (im) //(im != null) ? SwingFXUtils.toFXImage (im, null) : null) + .styleClassName (StyleClassNames.AVATAR) + .withViewer (viewer) + .build (); + + fb.item (getUILanguageStringProperty (Utils.newList (prefix,labels,LanguageStrings.avatar)), + avatarSel); + + Form f = fb.build (); + + QuollPopup qp = QuollPopup.formBuilder () + .title (Utils.newList (prefix,title)) + .headerIconClassName (StyleClassNames.EDIT) + .styleSheet ("updateeditorcontactinfo") + .form (f) + .build (); + + f.addEventHandler (Form.FormEvent.CANCEL_EVENT, + ev -> + { + + qp.close (); + + }); + + f.addEventHandler (Form.FormEvent.CONFIRM_EVENT, + ev -> + { + + f.hideError (); + + // Update the user data. + String newName = nameF.getText ().trim (); + + if (newName.length () == 0) + { + + f.showError (getUILanguageStringProperty (editors,editor,edit,popup,errors,noname));//"Please provide your name."); + return; + + } + + ed.setMyAvatarForEditor (avatarSel.getImage ()); + ed.setMyNameForEditor (nameF.getText ().trim ()); + + try + { + + EditorsEnvironment.updateEditor (ed); + + qp.close (); + + } catch (Exception e) { + + Environment.logError ("Unable to update editor: " + ed, + e); + + ComponentUtils.showErrorMessage (viewer, + getUILanguageStringProperty (editors,editor,edit,actionerror)); + //"Unable to update {editor}, please contact Quoll Writer support for assistance."); + + } + + }); + + } + + public static Form createSendProjectPanel (final AbstractProjectViewer viewer, + final EditorEditor ed, + final Runnable onSend, + final Runnable onCancel) + { + + // See what the last send/update message was, if any. + try + { + + EditorsEnvironment.loadMessagesForEditor (ed); + + } catch (Exception e) { + + Environment.logError ("Unable to load messages for editor: " + + ed, + e); + + ComponentUtils.showErrorMessage (viewer, + getUILanguageStringProperty (editors,user,sendorupdateproject,actionerror)); + //"Unable to show send {project} window, please contact Quoll Writer support for assistance."); + + return null; + + } + + Project p = viewer.getProject (); + + StringProperty updateText = new SimpleStringProperty (""); + + SortedSet messages = ed.getMessages (p.getId (), + NewProjectMessage.MESSAGE_TYPE, + UpdateProjectMessage.MESSAGE_TYPE); + + SortedSet projRes = ed.getMessages (p.getId (), + NewProjectResponseMessage.MESSAGE_TYPE); + + boolean update = false; + + Set chapterIds = new HashSet<> (); + + if ((messages != null) + && + (messages.size () > 0) + ) + { + + java.util.List prefix2 = Arrays.asList (editors,user,updateproject,popup,labels); + + // Get the last one. + EditorMessage last = messages.last (); + + update = (projRes.size () > 0); + + AbstractProjectMessage pm = (AbstractProjectMessage) last; + + Set chaps = pm.getChapters (); + String verName = pm.getProjectVersion ().getName (); + + updateText = UILanguageStringsManager.createStringPropertyWithBinding (() -> + { + + String ut = ""; + + if (last instanceof NewProjectMessage) + { + + if (verName != null) + { + + ut = getUILanguageStringProperty (Utils.newList (prefix2,firstupdatewithversion), + verName, + Environment.formatDate (last.getWhen ())).getValue (); + //"You sent version %s of the {project} on %s."; + + } else { + + ut = getUILanguageStringProperty (Utils.newList (prefix2,firstupdate), + Environment.formatDate (last.getWhen ())).getValue (); + //)"You sent the {project} on %s."; + + } + + // TODO: Add link to view what was sent. + + } + + if (last instanceof UpdateProjectMessage) + { + + if (verName != null) + { + + ut = getUILanguageStringProperty (Utils.newList (prefix2,lastupdatewithversion), + verName, + Environment.formatDate (last.getWhen ())).getValue (); + //"You last sent version %s of the {project} on %s."; + + } else { + + ut = getUILanguageStringProperty (Utils.newList (prefix2,lastupdate), + Environment.formatDate (last.getWhen ())).getValue (); + //"You last sent the {project} on %s."; + + } + + } + + return "

    " + ut + getUILanguageStringProperty (Utils.newList (prefix2,updatesuffix)).getValue (); + + }); + //" The {chapters} you previously sent have been pre-selected."; + + for (Chapter c : chaps) + { + + chapterIds.add (c.getId ()); + + } + + } else { + + // Add all chapters, first send. + Book b = (Book) p.getBooks ().get (0); + + List chaps = b.getChapters (); + + for (Chapter c : chaps) + { + + chapterIds.add (c.getId ()); + + } + + } + + // Check to see if we should be sending the project as new. + if (update) + { + + messages = ed.getMessages (p.getId (), + ProjectEditStopMessage.MESSAGE_TYPE); + + if ((messages != null) + && + (messages.size () > 0) + ) + { + + // Send a new project. Even though the editor has stopped editing this project + // in the past. + update = false; + + } + + } + + java.util.List prefix = Arrays.asList (editors,user,sendorupdateproject,popup); + + final boolean fupdate = update; + + Form.Builder f = Form.builder () + .inViewer (viewer) + .confirmButton (getUILanguageStringProperty (Utils.newList (prefix,LanguageStrings.buttons,LanguageStrings.send))) + .cancelButton (getUILanguageStringProperty (Utils.newList (prefix,LanguageStrings.buttons,LanguageStrings.cancel))) + .description (getUILanguageStringProperty (Utils.newList (prefix,text), + ed.getMainName (), + updateText)); + + // TODO Add pervious version? + QuollTextField version = QuollTextField.builder () + .build (); + + QuollTextArea notes = QuollTextArea.builder () + .maxChars (5000) + .placeholder (getUILanguageStringProperty (Utils.newList (prefix,labels,LanguageStrings.notes,tooltip), + ed.getMainName ())) + .build (); + + ZonedDateTime cal = ZonedDateTime.now (); + cal = cal.plusDays (7); + + DatePicker date = new DatePicker (LocalDate.from (cal)); + + List objs = new ArrayList<> (viewer.getProject ().getBooks ().get (0).getChapters ()); + + TreeItem root = new TreeItem<> (viewer.getProject ()); + + for (Chapter c : objs) + { + + CheckBoxTreeItem ci = new CheckBoxTreeItem<> (c); + ci.setSelected (chapterIds.contains (c.getId ())); + root.getChildren ().add (ci); + + } + + QuollTreeView chapterTree = NamedObjectTree.builder () + .project (viewer.getProject ()) + .root (root) + .labelProvider (treeItem -> + { + + NamedObject n = treeItem.getValue (); + + if (n instanceof Project) + { + + return new Label (); + + } + + QuollLabel l = QuollLabel.builder () + .label (n.nameProperty ()) + .styleClassName (n.getObjectType ()) + .build (); + + l.setOnMouseClicked (ev -> + { + + if (ev.getButton () != MouseButton.PRIMARY) + { + + return; + + } + + l.requestFocus (); + + viewer.viewObject (n); + + }); + + return l; + + }) + .build (); + + VBox b = new VBox (); + VBox.setVgrow (chapterTree, + Priority.ALWAYS); + QuollCheckBox cb = QuollCheckBox.builder () + .label (getUILanguageStringProperty (actions,selectall)) + .styleClassName (StyleClassNames.SELECT) + .build (); + cb.setOnAction (ev -> + { + + chapterTree.walkTree (ti -> + { + + if (ti instanceof CheckBoxTreeItem) + { + + CheckBoxTreeItem cti = (CheckBoxTreeItem) ti; + + cti.setSelected (cb.isSelected ()); + + } + + }); + + }); + b.getChildren ().addAll (cb, new QScrollPane (chapterTree)); + + f.item (getUILanguageStringProperty (Utils.newList (prefix,labels,project)), + QuollLabel.builder () + .label (new SimpleStringProperty (p.getName ())) + .build ()); + + f.item (getUILanguageStringProperty (Utils.newList (prefix,labels,LanguageStrings.version)), + version); + + f.item (getUILanguageStringProperty (Utils.newList (prefix,labels,LanguageStrings.notes,text)), + notes); + + f.item (getUILanguageStringProperty (Utils.newList (prefix,labels,dueby)), + date); + + f.item (getUILanguageStringProperty (Utils.newList (prefix,labels,chapters)), + b); + + Form form = f.build (); + + form.addEventHandler (Form.FormEvent.CONFIRM_EVENT, + ev -> + { + + form.hideError (); + + Set chapters = new LinkedHashSet<> (); + + Set errors = new LinkedHashSet<> (); + + chapterTree.walkTree (item -> + { + + if (item instanceof CheckBoxTreeItem) + { + + CheckBoxTreeItem cti = (CheckBoxTreeItem) item; + + if (!cti.isSelected ()) + { + + return; + + } + + if (cti.getValue () instanceof Chapter) + { + + chapters.add ((Chapter) cti.getValue ()); + + } + + } + + }); + + if (chapters.size () == 0) + { + + // Show the error. + errors.add (getUILanguageStringProperty (editors,user,sendorupdateproject,popup,LanguageStrings.errors,nochapters)); + //"Please select at least 1 {chapter}."; + + } else { + + for (Chapter c : chapters) + { + + ChapterEditorPanelContent qp = viewer.getEditorForChapter (c); + + if (qp != null) + { + + if (qp.hasUnsavedChanges ()) + { + + errors.add (getUILanguageStringProperty (editors,user,sendorupdateproject,popup,LanguageStrings.errors,unsavedchanges)); + //"One of the selected {chapters} has unsaved changes, please save your work before sending the {project}."; + + break; + + } + + } + + } + + } + + if (notes.getText ().trim ().length () > 5000) + { + + errors.add (getUILanguageStringProperty (editors,user,sendorupdateproject,popup,LanguageStrings.errors,maxchars)); + //"Notes can be a maximum of 5000 characters."; + + } + + if (errors.size () > 0) + { + + form.showErrors (errors); + ev.consume (); + return; + + } + + form.getConfirmButton ().setDisable (true); + + String n = notes.getText ().trim (); + + if (n.length () == 0) + { + + n = null; + + } + + String verName = version.getText ().trim (); + + if (verName.length () == 0) + { + + verName = null; + + } + + ProjectVersion pv = new ProjectVersion (); + pv.setName (verName); + pv.setDueDate (Utils.localDateToDate (date.getValue ())); + pv.setDescription (new StringWithMarkup (n)); + + // Need to snapshot the chapters. + Set nchapters = null; + + try + { + + nchapters = viewer.snapshotChapters (chapters, + pv); + + } catch (Exception e) { + + Environment.logError ("Unable to snapshot chapters: " + + chapters, + e); + + ComponentUtils.showErrorMessage (viewer, + getUILanguageStringProperty (editors,user,sendorupdateproject,actionerror)); + //"Unable to send new project to {editor}, please contact Quoll Writer support for assistance."); + + return; + + } + + EditorMessage mess = null; + + if (fupdate) + { + + mess = new UpdateProjectMessage (viewer.getProject (), + nchapters, + pv, + ed); + + } else { + + mess = new NewProjectMessage (viewer.getProject (), + nchapters, + pv, + ed, + ed.getEditorStatus () == EditorEditor.EditorStatus.pending ? EditorsEnvironment.getUserAccount () : null); + + } + + // Since we are sending the message we have dealt with it. + mess.setDealtWith (true); + + form.showLoading (getUILanguageStringProperty (Utils.newList (prefix,loading))); + + EditorsEnvironment.sendMessageToEditor (mess, + // On send. + () -> + { + + UIUtils.runLater (() -> + { + + // See if we already have the project editor, this can happen if we have previously + // sent the project but they deleted it and we are re-sending. + ProjectEditor pe = null; + + try + { + + pe = EditorsEnvironment.getProjectEditor (viewer.getProject (), + ed); + + } catch (Exception e) { + + Environment.logError ("Unable to get project editor for project: " + + viewer.getProject () + + " and editor: " + + ed, + e); + + // Oh bugger... + + } + + if (pe == null) + { + + pe = new ProjectEditor (viewer.getProject (), + ed); + + pe.setStatus (ProjectEditor.Status.invited); + + pe.setStatusMessage (Arrays.asList (editors,user,sendproject,editorstatus), + //"{Project} sent: %s", + Arrays.asList (Environment.formatDate (new Date ()))); + + // Add the editor to the list of editors + // for the project. A little dangerous to do it here + // since it's not in the same transaction as the message. + // TODO: Maybe have the message have a "side-effect" or "after save" + // TODO: that will add the editor to the project in the same transaction. + try + { + + EditorsEnvironment.addProjectEditor (pe); + + viewer.getProject ().addProjectEditor (pe); + + } catch (Exception e) { + + // Goddamn it! + // Nothing worse than having to show an error and success at the same time. + Environment.logError ("Unable to add editor: " + + ed + + " to project: " + + viewer.getProject (), + e); + + ComponentUtils.showErrorMessage (viewer, + getUILanguageStringProperty (editors,user,sendorupdateproject,actionerror)); + //"Unable to add {editor} " + ed.getMainName () + " to the {project}. Please contact Quoll Writer support for assistance."); + + } + + } else { + + try + { + + // Update them to be current. + pe.setCurrent (true); + pe.setEditorFrom (new Date ()); + pe.setEditorTo (null); + + pe.setStatusMessage (Arrays.asList (editors,user,updateproject,editorstatus), + //"{Project} updated: %s", + Arrays.asList (Environment.formatDate (new Date ()))); + + EditorsEnvironment.updateProjectEditor (pe); + + } catch (Exception e) { + + // Goddamn it! + // Nothing worse than having to show an error and success at the same time. + Environment.logError ("Unable to add editor: " + + ed + + " to project: " + + viewer.getProject (), + e); + + ComponentUtils.showErrorMessage (viewer, + getUILanguageStringProperty (editors,user,sendorupdateproject,actionerror)); + //"Unable to add {editor} " + ed.getMainName () + " to the {project}. Please contact Quoll Writer support for assistance."); + + } + + } + + }); + + UIUtils.runLater (() -> + { + + form.hideLoading (); + + QuollPopup.messageBuilder () + .inViewer (viewer) + .title (editors,user,sendorupdateproject,confirmpopup,title) + .message (getUILanguageStringProperty (Arrays.asList (editors,user,sendorupdateproject,confirmpopup,text), + viewer.getProject ().getName (), + ed.getMainName ())) + .closeButton () + .build (); + + }); + + if (onSend != null) + { + + Environment.scheduleImmediately (onSend); + + } + + }, + // On cancel of login. + () -> + { + + UIUtils.runLater (() -> + { + + form.getConfirmButton ().setDisable (false); + form.hideLoading (); + + }); + + }, + null); + + }); + + form.addEventHandler (Form.FormEvent.CANCEL_EVENT, + ev -> + { + + if (ed.isPending ()) + { +/* +TODO Removed for now, not sure this is the desired behaviour. + InviteMessage invite = new InviteMessage (EditorsEnvironment.getUserAccount ()); + + invite.setEditor (ed); + + form.showLoading (getUILanguageStringProperty (Utils.newList (prefix,loading))); + + // Send an invite. + EditorsEnvironment.sendMessageToEditor (invite, + () -> + { + + UIUtils.runLater (() -> + { + + form.hideLoading (); + form.getConfirmButton ().setDisable (false); + + QuollPopup.messageBuilder () + .inViewer (viewer) + .title (editors,user,invitesent,popup,title) + .message (getUILanguageStringProperty (Arrays.asList (editors,user,invitesent,popup,text), + ed.getEmail ())) + .closeButton () + .build (); + + }); + + }, + onCancel, + null); +*/ + } + + }); + + return form; + + } + + public static void showSendProject (final AbstractProjectViewer viewer, + final EditorEditor ed, + final Runnable onSend) + { + + Form f = EditorsUIUtils.createSendProjectPanel (viewer, + ed, + () -> + { + + // Need to close the popup. + + if (onSend != null) + { + + Environment.scheduleImmediately (onSend); + + } + + }, + null); + + QuollPopup qp = QuollPopup.formBuilder () + .title (editors,user,sendproject,popup,title) + .styleClassName (StyleClassNames.SEND) + .styleSheet ("sendproject") + .inViewer (viewer) + .form (f) + .build (); + + f.addEventHandler (Form.FormEvent.CONFIRM_EVENT, + ev -> + { + + qp.close (); + + }); + + } + + public static void showUpdateProject (final AbstractProjectViewer viewer, + final EditorEditor ed, + final Runnable onSend) + { + + if (ed.isPending ()) + { + + throw new IllegalStateException ("Can only update a project for a non-pending editor."); + + } + + QuollPopup qp = QuollPopup.formBuilder () + .title (editors,user,updateproject,popup,title) + .styleClassName (StyleClassNames.SEND) + .styleSheet ("sendproject") + .inViewer (viewer) + .form (EditorsUIUtils.createSendProjectPanel (viewer, + ed, + () -> + { + + // Need to close the popup. + + if (onSend != null) + { + + Environment.scheduleImmediately (onSend); + + } + + }, + null)) + .build (); + + } + + public static void showSendUnsentComments (final AbstractProjectViewer viewer, + final Runnable onSend) + { + + List prefix = Arrays.asList (editors,user,sendunsentcomments,popup); + + final EditorEditor ed = viewer.getProject ().getForEditor (); + + Form.Builder fb = Form.builder () + .inViewer (viewer) + .description (getUILanguageStringProperty (Utils.newList (prefix,text), + ed.getMainName ())) + .confirmButton (getUILanguageStringProperty (Utils.newList (prefix,buttons,LanguageStrings.send))) + .cancelButton (getUILanguageStringProperty (Utils.newList (prefix,buttons,LanguageStrings.cancel))); + + QuollTextArea genComments = QuollTextArea.builder () + .placeholder (Utils.newList (prefix,labels,notes,tooltip)) + .maxChars (5000) + .build (); + + List objs = new ArrayList<> (viewer.getProject ().getBooks ().get (0).getChapters ()); + + TreeItem root = new TreeItem<> (viewer.getProject ()); + + for (Chapter c : objs) + { + + CheckBoxTreeItem ci = new CheckBoxTreeItem<> (c); + root.getChildren ().add (ci); + + for (Note n : c.getNotes ()) + { + + if (n.isDealtWith ()) + { + + continue; + + } + + CheckBoxTreeItem nci = new CheckBoxTreeItem<> (n); + ci.getChildren ().add (nci); + + } + + } + + QuollTreeView tree = NamedObjectTree.builder () + .project (viewer.getProject ()) + .root (root) + .labelProvider (treeItem -> + { + + NamedObject n = treeItem.getValue (); + + if (n instanceof Project) + { + + return new Label (); + + } + + QuollLabel l = QuollLabel.builder () + .label (n.nameProperty ()) + .styleClassName (n.getObjectType ()) + .build (); + + l.setOnMouseClicked (ev -> + { + + if (ev.getButton () != MouseButton.PRIMARY) + { + + return; + + } + + l.requestFocus (); + + viewer.viewObject (n); + + }); + + return l; + + }) + .build (); + + ScrollPane sp = new ScrollPane (tree); + + fb.item (getUILanguageStringProperty (Utils.newList (prefix,labels,LanguageStrings.notes,text)), + genComments); + + fb.item (getUILanguageStringProperty (Utils.newList (prefix,labels,comments)), + sp); + + Form f = fb.build (); + + QuollPopup qp = QuollPopup.formBuilder () + .inViewer (viewer) + .styleClassName (StyleClassNames.SEND) + .title (Utils.newList (prefix,title)) + .form (f) + .build (); + + f.addEventHandler (Form.FormEvent.CONFIRM_EVENT, + ev -> + { + + // Get a count. + f.hideError (); + + Set selected = new LinkedHashSet<> (); + + tree.walkTree (item -> + { + + if (item instanceof CheckBoxTreeItem) + { + + CheckBoxTreeItem cti = (CheckBoxTreeItem) item; + + if (!cti.isSelected ()) + { + + return; + + } + + if (cti.getValue () instanceof Note) + { + + selected.add (cti.getValue ()); + + } + + } + + }); + + final Set comments = new LinkedHashSet<> (); + + for (NamedObject n : selected) + { + + if (n instanceof Note) + { + + comments.add ((Note) n); + + } + + } + + if (comments.size () == 0) + { + + f.showError (getUILanguageStringProperty (Utils.newList (prefix,errors,novalue))); + return; + + } + + String gc = genComments.getText ().trim (); + + if (gc.length () == 0) + { + + gc = null; + + } + + ProjectCommentsMessage mess = new ProjectCommentsMessage (viewer.getProject (), + gc, + comments, + viewer.getProject ().getProjectVersion (), + ed); + + // Since we are sending the message we have dealt with it. + mess.setDealtWith (true); + + // Do this here because we don't know how long it will take to actually send. + final Date sentDate = new Date (); + + EditorsEnvironment.sendMessageToEditor (mess, + // On send. + () -> + { + + // Update the comments to be dealt with. + for (Note n : comments) + { + + n.setDealtWith (sentDate); + + } + + try + { + + // Should really change the underlying method + // but can't be bothered at the moment! + // TODO + viewer.saveObjects (new ArrayList (comments), + true); + + } catch (Exception e) { + + Environment.logError ("Unable to update comments", + e); + + ComponentUtils.showErrorMessage (viewer, + getUILanguageStringProperty (editors,user,sendunsentcomments,actionerror)); + //"Your comments have been sent but Quoll Writer is unable to update the comments in your local db, please contact Quoll Writer support for assistance."); + + return; + + } + + UIUtils.runLater (() -> + { + + // Fire an event for each note. + for (Note n : comments) + { + + viewer.fireProjectEvent (ProjectEvent.Type.note, + ProjectEvent.Action.edit, + n); + + } + + QuollPopup.messageBuilder () + .title (editors,user,sendunsentcomments,confirmpopup,title) + .message (getUILanguageStringProperty (Arrays.asList (editors,user,sendunsentcomments,confirmpopup,text), + ed.getMainName ())) + .inViewer (viewer) + .closeButton () + .build (); + + qp.close (); + + }); + + if (onSend != null) + { + + Environment.scheduleImmediately (onSend); + + } + + }, + // On cancel of login. + null, + null); + + + }); + + f.addEventHandler (Form.FormEvent.CANCEL_EVENT, + ev -> + { + + qp.close (); + + }); + + } + + public static void showReportMessage (final MessageBox mess, + final AbstractViewer viewer, + final IPropertyBinder binder) + { + + URL url = null; + + try + { + + url = EditorsEnvironment.getReportMessageURL (); + + } catch (Exception e) { + + Environment.logError ("Unable to get report message url", + e); + + ComponentUtils.showErrorMessage (viewer, + getUILanguageStringProperty (editors,user,reportmessage,actionerror)); + //"Unable to show report message popup, please contact Quoll Writer support for assistance."); + + return; + + } + + final URL reportURL = url; + + List prefix = Arrays.asList (editors,user,reportmessage,popup); + + Form.Builder fb = Form.builder () + .inViewer (viewer) + .description (Utils.newList (prefix,text)) + .confirmButton (getUILanguageStringProperty (Utils.newList (prefix,buttons,send))) + .cancelButton (getUILanguageStringProperty (Utils.newList (prefix,buttons,cancel))); + + fb.sectionTitle (Utils.newList (prefix,sectiontitles,message)); + + Image im = null; + + try + { + + im = UIUtils.getImageOfNode (mess); + + } catch (Exception e) { + + Environment.logError ("Unable to create message box for: " + + mess, + e); + + ComponentUtils.showErrorMessage (viewer, + getUILanguageStringProperty (editors,user,reportmessage,actionerror)); + //"Unable to show report message popup, please contact Quoll Writer support for assistance."); + + return; + + } + + ImageView iv = new ImageView (im); + + fb.item (iv); + fb.sectionTitle (Utils.newList (prefix,sectiontitles,from)); + + EditorInfoBox edB = null; + + try + { + + edB = new EditorInfoBox (mess.getMessage ().getEditor (), + viewer, + false, + binder); + + } catch (Exception e) { + + Environment.logError ("Unable to create editor box for: " + + mess.getMessage ().getEditor (), + e); + + ComponentUtils.showErrorMessage (viewer, + getUILanguageStringProperty (editors,user,reportmessage,actionerror)); + //"Unable to show report message popup, please contact Quoll Writer support for assistance."); + + return; + + } + + fb.item (edB); + + fb.sectionTitle (Utils.newList (prefix,sectiontitles,reason)); + + QuollTextArea notes = QuollTextArea.builder () + .styleClassName (StyleClassNames.NOTES) + .placeholder (Utils.newList (prefix,labels,reason,tooltip)) + .maxChars (5000) + .build (); + + fb.item (notes); + + Form f = fb.build (); + + QuollPopup qp = QuollPopup.formBuilder () + .withViewer (viewer) + .form (f) + .styleSheet (StyleClassNames.REPORTMESSAGE) + .styleClassName (StyleClassNames.REPORTMESSAGE) + .title (Utils.newList (prefix,title)) + .build (); + + f.addEventHandler (Form.FormEvent.CONFIRM_EVENT, + ev -> + { + + f.hideError (); + + if (notes.getText ().trim ().length () == 0) + { + + f.showError (getUILanguageStringProperty (Utils.newList (prefix,errors,novalue))); + return; + + } + + f.showLoading (getUILanguageStringProperty (Utils.newList (prefix,loading))); + + EditorsEnvironment.goOnline (getUILanguageStringProperty (editors,login,reasons,reportmessage), + //"To report a message you must first login.", + () -> + { + + Map data = new HashMap (); + data.put ("message", + mess.getMessage ()); + data.put ("editor", + mess.getMessage ().getEditor ()); + data.put ("user", + EditorsEnvironment.getUserAccount ()); + data.put ("reason", + notes.getText ().trim ()); + + Map headers = new HashMap (); + headers.put ("Authorization", + EditorsEnvironment.getUserAccount ().getWebServiceSessionId ()); + + try + { + + Utils.postToURL (reportURL, + headers, + JSONEncoder.encode (data, + true, + ""), + (ret, resCode) -> + { + + UIUtils.runLater (() -> + { + + qp.close (); + + QuollPopup.messageBuilder () + .withViewer (viewer) + .title (editors,user,reportmessage,confirmpopup,title) + .message (editors,user,reportmessage,confirmpopup,text) + .closeButton () + .build (); + + }); + + }, + (ret, resCode) -> + { + + UIUtils.runLater (() -> + { + + qp.close (); + + Environment.logError ("Unable to report message:" + + ev); + + ComponentUtils.showErrorMessage (viewer, + getUILanguageStringProperty (editors,user,reportmessage,actionerror)); + //"Unable to report the message, please contact Quoll Writer support for assistance."); + + }); + + }, + (exp) -> + { + + UIUtils.runLater (() -> + { + + qp.close (); + + Environment.logError ("Unable to report message, got fail", + exp); + + ComponentUtils.showErrorMessage (viewer, + getUILanguageStringProperty (editors,user,reportmessage,actionerror)); + //"Unable to report the message, please contact Quoll Writer support for assistance."); + + }); + + }, + null); + + } catch (Exception e) { + + qp.close (); + + Environment.logError ("Unable to report message", + e); + + ComponentUtils.showErrorMessage (viewer, + getUILanguageStringProperty (editors,user,reportmessage,actionerror)); + //"Unable to report the message, please contact Quoll Writer support for assistance."); + + } + + }, + null, + null); + + }); + + f.addEventHandler (Form.FormEvent.CANCEL_EVENT, + ev -> + { + + qp.close (); + + }); + + } + + public static void showRegister (final AbstractViewer viewer) + throws Exception + { + + QuollPopup qp = viewer.getPopupById (EditorRegister.POPUP_ID); + + if (qp != null) + { + + qp.toFront (); + return; + + } + + new EditorRegister (viewer).show (); + + } + + public static void hideLogin () + { + + if (EditorsUIUtils.editorLogin == null) + { + + return; + + } + + EditorsUIUtils.editorLogin.close (); + + } + + public static void showChangePassword (final AbstractViewer viewer) + { + + java.util.List prefix = Arrays.asList (editors,user,changepassword,popup); + + Form.Builder fb = Form.builder () + .description (prefix,text) + .confirmButton (getUILanguageStringProperty (Utils.newList (prefix,buttons,confirm))) + .cancelButton (getUILanguageStringProperty (Utils.newList (prefix,buttons,cancel))); + + PasswordField pass1 = new PasswordField (); + PasswordField pass2 = new PasswordField (); + + fb.item (getUILanguageStringProperty (Utils.newList (prefix,labels,newpassword)), + pass1); + + fb.item (getUILanguageStringProperty (Utils.newList (prefix,labels,confirmpassword)), + pass2); + + Form form = fb.build (); + + QuollPopup qp = QuollPopup.formBuilder () + .styleClassName (StyleClassNames.CHANGEPASSWORD) + .headerIconClassName (StyleClassNames.EDIT) + .title (Utils.newList (prefix,title)) + .inViewer (viewer) + .form (form) + .build (); + + form.addEventHandler (Form.FormEvent.CANCEL_EVENT, + ev -> + { + + qp.close (); + + }); + + form.addEventHandler (Form.FormEvent.CONFIRM_EVENT, + ev -> + { + + List prefix2 = Arrays.asList (editors,user,changepassword,popup,errors); + + form.hideError (); + + // Update the user data. + String pwd = pass1.getText (); + + if (pwd.length () == 0) + { + + form.showError (getUILanguageStringProperty (Utils.newList (prefix2,nopassword))); + return; + + } + + String pwd2 = pass2.getText (); + + if (pwd2.length () == 0) + { + + form.showError (getUILanguageStringProperty (Utils.newList (prefix2,confirmpassword))); + return; + + } + + if (!pwd.equals (pwd2)) + { + + form.showError (getUILanguageStringProperty (Utils.newList (prefix2,nomatch))); + return; + + } + + EditorsEnvironment.updateUserPassword (pwd); + + qp.close (); + + }); + + } + + public static void showLogin (final AbstractViewer viewer, + final StringProperty loginReason, + final Runnable onLogin, + final Runnable onCancel) + { + + UIUtils.runLater (() -> + { + + if (EditorsUIUtils.editorLogin == null) + { + + EditorsUIUtils.editorLogin = new EditorLoginPopup (); + + } + + EditorsUIUtils.editorLogin.setVisible (true); + + EditorsUIUtils.editorLogin.show (viewer, + loginReason, + onLogin, + onCancel); + + }); + + } + + public static void showLoginError (EditorsWebServiceResult res) + { + + StringProperty reason = null; + //"Please contact Quoll Writer support for assistance, quoting error code: " + res.getReturnCode () + (res.getReturnCode () == 401 ? ("/" + res.getErrorType ()) : ""); + + if (res.getReturnCode () == 401) + { + + String errType = res.getErrorType (); + + if (errType != null) + { + + if (errType.equals ("InvalidCredentials")) + { + + reason = getUILanguageStringProperty (editors,login,errors,invalidcredentials); + //"Please check your email/password and try again."; + + } + + if (errType.equals ("AccountNotActive")) + { + + reason = getUILanguageStringProperty (editors,login,errors,inactiveaccount); + + } + + } + + } else { + + reason = getUILanguageStringProperty (Arrays.asList (editors,login,errors,general), + res.getReturnCode () + "/" + res.getErrorType ()); + + } + + EditorsUIUtils.showLoginError (reason); + //"Unable to login to the Editors service.
    " + reason); + + } + + public static void showLoginError (StringProperty error) + { + + EditorsUIUtils.showLoginError (error, + null, + null); + + } + + public static void showLoginError (StringProperty error, + Runnable onLogin, + Runnable onCancel) + { + + if (error == null) + { + + throw new NullPointerException ("Error must be provided."); + + } + + UIUtils.runLater (() -> + { + + if (EditorsUIUtils.editorLogin == null) + { + + EditorsUIUtils.editorLogin = new EditorLoginPopup (); + + } + + /* + if (EditorsUIUtils.editorLogin.getParent () == null) + { + + AbstractProjectViewer viewer = Environment.getFocusedProjectViewer (); + + UIUtils.showErrorMessage (viewer, + "Unable to show login form, please contact Quoll Writer support for assistance."); + + return; + + } + */ + + EditorsUIUtils.editorLogin.show (); + + EditorsUIUtils.editorLogin.showError (error); + + if (onLogin != null) + { + + EditorsUIUtils.editorLogin.setOnLogin (onLogin); + + } + + if (onCancel != null) + { + + EditorsUIUtils.editorLogin.setOnCancel (onCancel); + //EditorsUIUtils.editorLogin.setOnClose (onCancel); + + } + + }); + + //EditorsUIUtils.editorLogin.resize (); + + } + + public static void showContacts ( ObservableList editors, + StringProperty title, + final AbstractProjectViewer viewer, + Consumer onSelect, + Node extra) + { + + ShowObjectSelectPopup.builder () + .withViewer (viewer) + .title (title) + .styleClassName (StyleClassNames.OBJECTSELECT) + .headerIconClassName (StyleClassNames.CONTACTS) + //.styleSheet ("selectcontact") + .popupId ("showcontacts") + .objects (editors) + .showBelowObjects (extra) + .cellProvider ((obj, popupContent) -> + { + + QuollLabel l = QuollLabel.builder () + .label (obj.mainNameProperty ()) + .styleClassName (StyleClassNames.CONTACT) + .build (); + // TODO Not the proper way to do this... + l.setOnMouseReleased (ev -> + { + + if (onSelect != null) + { + + onSelect.accept (obj); + popupContent.close (); + + } + + }); + IconBox ib = IconBox.builder () + .image (obj.mainAvatarProperty ()) + .build (); + + ib.pseudoClassStateChanged (StyleClassNames.NOAVATAR_PSEUDO_CLASS, (obj.mainAvatarProperty ().getValue () == null)); + l.setGraphic (ib); + + return l; + + }) + .build () + .show (); + + } + + public static void showInviteEditor (final AbstractViewer viewer) + { + + final java.util.List prefix = Arrays.asList (editors,user,inviteeditor,popup); + + String popupId = "inviteeditor"; + + QuollPopup.textEntryBuilder () + .popupId (popupId) + .styleClassName (StyleClassNames.INVITEEDITOR) + .headerIconClassName (StyleClassNames.ADD) + .title (Utils.newList (prefix,title)) + .description (Utils.newList (prefix,text)) + .removeOnClose (true) + .hideOnEscape (true) + .withClose (true) + .withViewer (viewer) + .confirmButtonLabel (Utils.newList (prefix,buttons,invite)) + .cancelButtonLabel (Utils.newList (prefix,buttons,cancel)) + .onConfirm (ev -> + { + + TextField tf = (TextField) ev.getForm ().lookup ("#text"); + + String v = tf.getText ().trim (); + + EditorsEnvironment.sendInvite (v, + viewer); + + viewer.getPopupById (popupId).close (); + + }) + .onCancel (ev -> + { + + //viewer.getPopupById (popupId).close (); + + }) + .validator (v -> + { + + if ((v == null) + || + (v.trim ().equals ("")) + ) + { + + return getUILanguageStringProperty (Utils.newList (prefix,errors,noemail)); + //"The email address must be specified."; + + } + + if (v.indexOf ("@") < 0) + { + + return getUILanguageStringProperty (Utils.newList (prefix,errors,invalidemail)); + //"Please provide a valid email address."; + + } + + if (v.equals (EditorsEnvironment.getUserAccount ().getEmail ())) + { + + return getUILanguageStringProperty (Utils.newList (prefix,errors,self)); + //"Inviting yourself? O_o"; + + } + + EditorEditor ed = EditorsEnvironment.getEditorByEmail (v); + + // Check to see if we already have the editor. + if (ed != null) + { + + String type = alreadyinvited; + //"You have already invited %s (%s)."; + + if (ed.getEditorStatus () == EditorEditor.EditorStatus.rejected) + { + + type = previousrejected; + //"You have already invited: %s (%s). Your invitation was rejected."; + + } + + if (ed.isPrevious ()) + { + + type = previous; + //"%s (%s) is a previous {contact}."; + + } + + return getUILanguageStringProperty (Utils.newList (prefix,errors,type), + ed.mainNameProperty (), + ed.emailProperty ()); + + } + + return null; + + }) + .build (); + + } + + public static void showResultError (final EditorsWebServiceResult res) + { + + ComponentUtils.showErrorMessage (new SimpleStringProperty (res.getErrorMessage ())); + + } + + public static TreeItem createChapterTreeItem (Chapter c) + { + + TreeItem cii = new TreeItem<> (c); + + cii.getChildren ().addAll (c.getNotes ().stream () + .map (n -> new TreeItem (n)) + .collect (Collectors.toList ())); + + return cii; + + } + + public static TreeItem createChaptersTree (Project proj) + { + + TreeItem root = new TreeItem<> (proj); + + Book b = (Book) proj.getBooks ().get (0); + + root.getChildren ().addAll (b.getChapters ().stream () + .map (c -> EditorsUIUtils.createChapterTreeItem (c)) + .collect (Collectors.toList ())); + + return root; + + } + + public static void showProjectComments (final ProjectCommentsMessage message, + final AbstractViewer parentViewer, + final Consumer onShow) + { + + // Load up the project with the specific text. + // See if we have a project viewer for the project. + ProjectInfo proj = null; + + try + { + + proj = Environment.getProjectById (message.getForProjectId (), + (message.isSentByMe () ? Project.EDITOR_PROJECT_TYPE : Project.NORMAL_PROJECT_TYPE)); + + } catch (Exception e) { + + Environment.logError ("Unable to get project for: " + + message.getForProjectId (), + e); + + ComponentUtils.showErrorMessage (parentViewer, + getUILanguageStringProperty (project,actions,openproject,openerrors,comments)); + //"Unable to show {comments}, please contact Quoll Writer support for assistance."); + + return; + + } + + if (proj == null) + { + + Environment.logError ("No project for: " + + message.getForProjectId ()); + + ComponentUtils.showErrorMessage (parentViewer, + getUILanguageStringProperty (project,actions,openproject,openerrors,comments)); + //"Unable to show {comments}, please contact Quoll Writer support for assistance."); + + return; + + } + + final ProjectInfo _proj = proj; + + Consumer open = pwd -> + { + + //String pwd = _proj.getFilePassword (); + + if ((pwd != null) + && + (pwd.equals ("")) + ) + { + + pwd = null; + + } + + Set chaps = null; + + try + { + + chaps = Environment.getVersionedChapters (_proj, + message.getChapters (), + pwd); + + } catch (Exception e) { + + Environment.logError ("Unable to get versioned chapters for project: " + + _proj, + e); + + ComponentUtils.showErrorMessage (parentViewer, + getUILanguageStringProperty (project,actions,openproject,openerrors,comments)); + //"Unable to show {comments}, please contact Quoll Writer support for assistance."); + + return; + + } + + ProjectVersion pv = null; + + try + { + + pv = Environment.getProjectVersionById (_proj, + message.getProjectVersion ().getId (), + pwd); + + } catch (Exception e) { + + Environment.logError ("Unable to get project version: " + + message.getProjectVersion ().getId () + + " for project: " + + _proj, + e); + + ComponentUtils.showErrorMessage (parentViewer, + getUILanguageStringProperty (project,actions,openproject,openerrors,comments)); + //"Unable to show {comments}, please contact Quoll Writer support for assistance."); + + return; + + } + + if (pv == null) + { + + Environment.logError ("Unable to find project version: " + + message.getProjectVersion ().getId () + + " for project: " + + _proj); + + ComponentUtils.showErrorMessage (parentViewer, + getUILanguageStringProperty (project,actions,openproject,openerrors,comments)); + //"Unable to show {comments}, please contact Quoll Writer support for assistance."); + + return; + + + } + + try + { + + // Need to "fill up" the project with the chapters and comments. + // Create a new project object just to be safe (in case the getProjectById call changes in the future). + Project np = new Project (); + np.setName (_proj.getName ()); + np.setProjectVersion (pv); + + np.setType (Project.EDITOR_PROJECT_TYPE); + np.setId (message.getForProjectId ()); + np.setName (message.getForProjectName ()); + + Book b = new Book (np, + np.getName ()); + + np.addBook (b); + + // Need to prevent an O^n performance hit here. + + Map kchaps = new HashMap<> (); + + for (Chapter c : chaps) + { + + b.addChapter (c); + + kchaps.put (c.getId (), + c); + + c.setEditPosition (-1); + c.setEditComplete (false); + + } + + long k = 1; + + for (Note n : message.getComments ()) + { + + // Need to give it a fake key. + n.setKey (k++); + n.setType (Note.EDIT_NEEDED_NOTE_TYPE); + + // Get the fake chapter. + Chapter fakec = n.getChapter (); + + // Get the real chapter. + Chapter realc = kchaps.get (fakec.getId ()); + + if (realc == null) + { + + // God damnit... + // TODO: Handle when a chapter no longer exists but have comments for it. + + } + + realc.addNote (n); + + } + + ProjectCommentsViewer pcv = new ProjectCommentsViewer (np, + message); + + pcv.createViewer (); + pcv.init (new State ()); + + if (onShow != null) + { + + UIUtils.runLater (() -> + { + + onShow.accept (pcv); + + }); + + } + + } catch (Exception e) { + + Environment.logError ("Unable to view comments for project: " + + _proj, + e); + + ComponentUtils.showErrorMessage (parentViewer, + getUILanguageStringProperty (project,actions,openproject,openerrors,comments)); + //"Unable to show {comments}, please contact Quoll Writer support for assistance."); + + return; + + } + + }; + + UIUtils.askForPasswordForProject (proj, + null, + open, + null, + parentViewer); + + } + + public static void showProjectUpdate (final UpdateProjectMessage message, + final AbstractViewer parentViewer, + final Runnable onShow) + { + + // Load up the project with the specific text. + // See if we have a project viewer for the project. + ProjectInfo proj = null; + + try + { + + proj = Environment.getProjectById (message.getForProjectId (), + Project.EDITOR_PROJECT_TYPE); + + } catch (Exception e) { + + Environment.logError ("Unable to get project for: " + + message.getForProjectId (), + e); + + ComponentUtils.showErrorMessage (parentViewer, + getUILanguageStringProperty (editors,messages,projectupdated,actionerror)); + //"Unable to show {project} update, please contact Quoll Writer support for assistance."); + + return; + + } + + final ProjectInfo _proj = proj; + + if (proj == null) + { + + QuollPopup.messageBuilder () + .message (editors,messages,projectupdated,errors,novalue) + .inViewer (parentViewer) + .build (); + + message.setDealtWith (true); + + try + { + + EditorsEnvironment.updateMessage (message); + + } catch (Exception e) { + + Environment.logError ("Unable to update project message: " + + message, + e); + + } + + return; + + } + + Consumer open = (pwd) -> + { + + if ((pwd != null) + && + (pwd.equals ("")) + ) + { + + pwd = null; + + } + + try + { + + Environment.updateToNewVersions (_proj, + message.getProjectVersion (), + message.getChapters (), + pwd); + + message.setDealtWith (true); + + EditorsEnvironment.updateMessage (message); + + } catch (Exception e) { + + Environment.logError ("Unable to update project to new versions of chapters: " + + _proj, + e); + + ComponentUtils.showErrorMessage (parentViewer, + getUILanguageStringProperty (editors,messages,projectupdated,actionerror)); + //"Unable to update {project}, please contact Quoll Writer support for assistance."); + + return; + + } + + try + { + + Environment.openProject (_proj); + + AbstractProjectViewer pv = Environment.getProjectViewer (_proj); + + if (!(pv instanceof EditorProjectViewer)) + { + + Environment.logError ("Unable to open project at version: " + + message.getProjectVersion () + + ", project: " + + _proj); + + ComponentUtils.showErrorMessage (parentViewer, + getUILanguageStringProperty (editors,messages,projectupdated,actionerror)); + //"Unable to view updated {project}, please contact Quoll Writer support for assistance."); + + return; + + } + + EditorProjectViewer epv = (EditorProjectViewer) pv; + + epv.switchToProjectVersion (message.getProjectVersion ()); + + UIUtils.runLater (onShow); + + } catch (Exception e) { + + Environment.logError ("Unable to for project: " + + _proj, + e); + + ComponentUtils.showErrorMessage (parentViewer, + getUILanguageStringProperty (editors,messages,projectupdated,actionerror)); + //"Unable to show {comments}, please contact Quoll Writer support for assistance."); + + return; + + } + + }; + + UIUtils.askForPasswordForProject (proj, + null, + open, + null, + parentViewer); + + } + + public static Node getProjectVersionPanel (final ProjectVersion pv, + final AbstractProjectViewer viewer) + { + + if (pv == null) + { + + return null; + + } + + String ver = pv.getName (); + final String genComments = (pv.getDescription () != null ? pv.getDescription ().getText () : null); + Date due = pv.getDueDate (); + + List prefix = Arrays.asList (editors,project,sidebar,comments,labels); + + Form.Builder f = Form.builder () + .layoutType (Form.LayoutType.column) + .styleClassName (StyleClassNames.PROJECTVERSIONINFO); + + if (ver != null) + { + + StringProperty l = new SimpleStringProperty (); + l.bind (UILanguageStringsManager.createStringBinding (() -> + { + + String v = ver; + + if (pv.isLatest ()) + { + + v += getUILanguageStringProperty (Utils.newList (prefix,LanguageStrings.latest)).getValue (); + + } + + return v; + + })); + + f.item (getUILanguageStringProperty (Utils.newList (prefix,version)), + QuollLabel.builder () + .label (l) + .build ()); + + } + + if (due != null) + { + + f.item (getUILanguageStringProperty (Utils.newList (prefix,LanguageStrings.due)), + QuollLabel.builder () + .label (new SimpleStringProperty (Environment.formatDate (due))) + .build ()); + + } + + if (genComments != null) + { + + String commText = genComments; + + TextIterator ti = new TextIterator (commText); + + if (ti.getSentenceCount () > 1) + { + + commText = ti.getFirstSentence ().getText (); + + commText += getUILanguageStringProperty (Utils.newList (prefix,more)); + //"
    More, click to view all."; + + } + + QuollTextView v = QuollTextView.builder () + .text (commText) + .inViewer (viewer) + .build (); + + f.item (getUILanguageStringProperty (Utils.newList (prefix,notes)), + v); + + v.setOnMouseClicked (ev -> + { + + QuollPopup.messageBuilder () + .withViewer (viewer) + .title (editors,project,sidebar,comments,notes,popup,title) + .message (new SimpleStringProperty (genComments)) + .closeButton () + .build (); + + }); + + } + + Form form = f.build (); + VBox.setVgrow (form, + Priority.NEVER); + + return form; + + } + + public static void showMessagesInPopup (StringProperty title, + String className, + StringProperty help, + Set messages, + boolean showAttentionBorder, + AbstractViewer viewer, + Node showAt) + { + + try + { + + // Sort the messages in descending when order or newest first. + Query q = new Query (); + q.parse (String.format ("SELECT * FROM %s ORDER BY when DESC", + EditorMessage.class.getName ())); + + QueryResults qr = q.execute (messages); + + messages = new LinkedHashSet (qr.getResults ()); + + } catch (Exception e) { + + Environment.logError ("Unable to sort messages", + e); + + } + + VBox content = new VBox (); + content.getChildren ().add (QuollTextView.builder () + .text (UILanguageStringsManager.createStringPropertyWithBinding (() -> + { + + return help.getValue () + getUILanguageStringProperty (editors,LanguageStrings.messages,show,suffix).getValue (); + + }, + help)) + .styleClassName (StyleClassNames.DESCRIPTION) + .inViewer (viewer) + .build ()); + + VBox projBox = new VBox (); + QScrollPane sp = new QScrollPane (projBox); + VBox.setVgrow (sp, + Priority.ALWAYS); + + for (EditorMessage m : messages) + { + + MessageBox mb = null; + + try + { + + mb = MessageBoxFactory.getMessageBoxInstance (m, + viewer); + mb.setShowAttentionBorder (true);//showAttentionBorder); + + } catch (Exception e) { + + Environment.logError ("Unable to get message box for message: " + + m, + e); + + } + + projBox.getChildren ().add (mb); + + } + + QuollPopup qp = QuollPopup.builder () + .title (title) + .styleClassName (className != null ? className : StyleClassNames.EDIT) + .withClose (true) + .styleSheet (StyleClassNames.EDITORMESSAGES) + .withViewer (viewer) + .hideOnEscape (true) + .removeOnClose (true) + .content (content) + .show () + .build (); + + QuollButtonBar bb = QuollButtonBar.builder () + .button (QuollButton.builder () + .buttonType (ButtonBar.ButtonData.FINISH) + .label (buttons,close) + .onAction (ev -> + { + + qp.close (); + + }) + .build ()) + .build (); + + content.getChildren ().addAll (sp, bb); + + } + + public static void showAllMessagesForEditor (EditorEditor ed, + AbstractViewer viewer, + Node showAt) + { + + Project np = null; + + Set messages = ed.getMessages (new DefaultEditorMessageFilter (np, + EditorInfoMessage.MESSAGE_TYPE, + NewProjectMessage.MESSAGE_TYPE, + NewProjectResponseMessage.MESSAGE_TYPE, + ProjectCommentsMessage.MESSAGE_TYPE, + InviteResponseMessage.MESSAGE_TYPE, + InviteMessage.MESSAGE_TYPE, + ProjectEditStopMessage.MESSAGE_TYPE, + UpdateProjectMessage.MESSAGE_TYPE, + EditorRemovedMessage.MESSAGE_TYPE)); + + java.util.List prefix = Arrays.asList (editors,LanguageStrings.messages,show,all,popup); + + EditorsUIUtils.showMessagesInPopup (getUILanguageStringProperty (Utils.newList (prefix,title)), + //"All messages", + StyleClassNames.FIND, + getUILanguageStringProperty (Utils.newList (prefix,text), + //"All messages you've sent to and/or received from %s.", + ed.mainNameProperty ()), + messages, + false, + viewer, + showAt); + + } + + public static void showImportantMessagesForEditor (EditorEditor ed, + AbstractViewer viewer, + Node showAt) + { + + // Get undealt with messages that are not chat. + // If there is just one then show it, otherwise show a link that will display a popup of them. + Set undealtWith = ed.getMessages (EditorsUIUtils.importantMessageFilter); + + java.util.List prefix = Arrays.asList (editors,messages,show,important,popup); + + EditorsUIUtils.showMessagesInPopup (getUILanguageStringProperty (Utils.newList (prefix,title)), + //"Important messages", + StyleClassNames.IMPORTANT, + getUILanguageStringProperty (Utils.newList (prefix,text), + //"New and important messages from %s that require your attention.", + ed.mainNameProperty ()), + undealtWith, + false, + viewer, + showAt); + + } + + public static void showProjectMessagesForEditor (EditorEditor ed, + AbstractProjectViewer viewer, + Node showAt) + { + + Set messages = ed.getMessages (new DefaultEditorMessageFilter (viewer.getProject (), + NewProjectMessage.MESSAGE_TYPE, + UpdateProjectMessage.MESSAGE_TYPE, + NewProjectResponseMessage.MESSAGE_TYPE, + ProjectEditStopMessage.MESSAGE_TYPE)); + + ProjectEditor pe = viewer.getProject ().getProjectEditor (ed); + + java.util.List prefix = Arrays.asList (editors,LanguageStrings.messages,show,project,popup); + + EditorsUIUtils.showMessagesInPopup (getUILanguageStringProperty (Utils.newList (prefix,title)), + //"{Project} updates sent/received", + StyleClassNames.PROJECTMESSAGES, + getUILanguageStringProperty (Utils.newList (prefix,text), + //"All {project} updates you have sent to or received from %s for {project} %s. The latest update is shown first.", + ed.mainNameProperty (), + viewer.getProject ().nameProperty ()), + messages, + true, + viewer, + showAt); + + } + + public static void showAllCommentsForEditor (EditorEditor ed, + AbstractProjectViewer viewer, + Node showAt) + { + + Set comments = ed.getMessages (new DefaultEditorMessageFilter (viewer.getProject (), + ProjectCommentsMessage.MESSAGE_TYPE)); +/* + if (comments.size () == 0) + { + + UIUtils.showMessage ((PopupsSupported) viewer, + "No comments sent/received", + "No comments have been sent or received yet."); + + return; + + } +*/ + boolean sentByMe = comments.iterator ().next ().isSentByMe (); + + java.util.List prefix = Arrays.asList (editors,messages,show,(sentByMe ? commentssent : commentsreceived),popup); + + //String suffix = (sentByMe ? "sent" : "received"); + //String suffix2 = (sentByMe ? "sent to" : "received from"); + + EditorsUIUtils.showMessagesInPopup (getUILanguageStringProperty (Utils.newList (prefix,title)), + //String.format ("{Comments} %s", + // suffix), + StyleClassNames.COMMENTS, + getUILanguageStringProperty (Utils.newList (prefix,text), + //"All {comments} you have %s %s for {project} %s. The latest {comments} are shown first.", + // suffix2, + ed.mainNameProperty (), + viewer.getProject ().nameProperty ()), + comments, + true, + viewer, + showAt); + + } + + public static void showProjectsUserIsEditingForEditor (EditorEditor editor, + AbstractViewer viewer) + { + + Set projs = new LinkedHashSet (); + + try + { + + Set allProjs = Environment.getAllProjectInfos (); + + for (ProjectInfo p : allProjs) + { + + if (p.isEditorProject ()) + { + + EditorEditor ed = EditorsEnvironment.getEditorByEmail (p.getForEditor ().getEmail ()); + + if (ed == editor) + { + + projs.add (p); + + } + + } + + } + + } catch (Exception e) { + + Environment.logError ("Unable to get all projects", + e); + + ComponentUtils.showErrorMessage (viewer, + getUILanguageStringProperty (editors,LanguageStrings.editor,showprojectseditingforcontact,actionerror)); + //String.format ("Unable to show {projects} you are editing for %s.", + // editor.getShortName ())); + + return; + + } + + List prefix = Arrays.asList (editors,LanguageStrings.editor,showprojectseditingforcontact,popup); + + VBox content = new VBox (); + content.getChildren ().add (QuollTextView.builder () + .text (getUILanguageStringProperty (Utils.newList (prefix,text), + editor.mainNameProperty ())) + .styleClassName (StyleClassNames.DESCRIPTION) + .inViewer (viewer) + .build ()); + + VBox projBox = new VBox (); + QScrollPane sp = new QScrollPane (projBox); + VBox.setVgrow (sp, + Priority.ALWAYS); + + for (ProjectInfo p : projs) + { + + QuollLabel l = QuollLabel.builder () + .label (p.nameProperty ()) + .build (); + projBox.getChildren ().add (l); + + // TODO Allow click to open... + + } + + QuollPopup qp = QuollPopup.builder () + .title (Utils.newList (prefix,title)) + .styleClassName (StyleClassNames.EDIT) + .withClose (true) + .withViewer (viewer) + .hideOnEscape (true) + .removeOnClose (true) + .content (content) + .show () + .build (); + + QuollButtonBar bb = QuollButtonBar.builder () + .button (QuollButton.builder () + .buttonType (ButtonBar.ButtonData.FINISH) + .label (buttons,close) + .onAction (ev -> + { + + qp.close (); + + }) + .build ()) + .build (); + + content.getChildren ().addAll (sp, bb); + + } + + public static void showProjectsEditorIsEditingForUser (EditorEditor editor, + AbstractViewer viewer) + { + + final Set projs = new LinkedHashSet<> (); + + Set messages = editor.getMessages (new EditorMessageFilter () + { + + public boolean accept (EditorMessage m) + { + + if (m.isSentByMe ()) + { + + return false; + + } + + if (!m.getMessageType ().equals (NewProjectResponseMessage.MESSAGE_TYPE)) + { + + return false; + + } + + NewProjectResponseMessage nprm = (NewProjectResponseMessage) m; + + if (!nprm.isAccepted ()) + { + + return false; + + } + + try + { + + projs.add (Environment.getProjectById (nprm.getForProjectId (), + Project.NORMAL_PROJECT_TYPE)); + + } catch (Exception e) { + + Environment.logError ("Unable to get normal project with id: " + + nprm.getForProjectId (), + e); + + } + + return true; + + } + + }); + + List prefix = Arrays.asList (editors,LanguageStrings.editor,showprojectscontactisediting,popup); + + VBox content = new VBox (); + content.getChildren ().add (QuollTextView.builder () + .text (getUILanguageStringProperty (Utils.newList (prefix,text), + editor.mainNameProperty ())) + .styleClassName (StyleClassNames.DESCRIPTION) + .inViewer (viewer) + .build ()); + + VBox projBox = new VBox (); + QScrollPane sp = new QScrollPane (projBox); + VBox.setVgrow (sp, + Priority.ALWAYS); + + for (ProjectInfo p : projs) + { + + // TODO + + } + + QuollPopup qp = QuollPopup.builder () + .title (Utils.newList (prefix,title)) + .styleClassName (StyleClassNames.EDIT) + .withClose (true) + .withViewer (viewer) + .hideOnEscape (true) + .removeOnClose (true) + .content (content) + .show () + .build (); + + QuollButtonBar bb = QuollButtonBar.builder () + .button (QuollButton.builder () + .buttonType (ButtonBar.ButtonData.FINISH) + .label (buttons,close) + .onAction (ev -> + { + + qp.close (); + + }) + .build ()) + .build (); + + content.getChildren ().addAll (sp, bb); + + } + + + public static Node getProjectMessageDetails (final AbstractProjectMessage message, + final AbstractViewer viewer, + final MessageBox parentMessageBox) + { + + String plural = ""; + + List prefix = Arrays.asList (editors,messages,newupdateproject,labels); + + if (message.getChapters ().size () > 1) + { + + plural = "s"; + + } + + ProjectVersion projVer = message.getProjectVersion (); + Date dueDate = projVer.getDueDate (); + + String notes = ((projVer.getDescription () != null) ? projVer.getDescription ().getText () : null); + String verName = projVer.getName (); + + ProjectInfo proj = null; + + try + { + + proj = Environment.getProjectById (message.getForProjectId (), + (message.isSentByMe () ? Project.NORMAL_PROJECT_TYPE : Project.EDITOR_PROJECT_TYPE)); + + } catch (Exception e) { + + Environment.logError ("Unable to get project for id: " + + message.getForProjectId (), + e); + + } + + final ProjectInfo fproj = proj; + + // Show: + // * Project + // * Sent + // * Version (optional) + // * Word/chapter count + // * Due by + // * Notes (optional) + // * View link + + Form.Builder f = Form.builder () + .layoutType (Form.LayoutType.column); + + Node projLabel = null; + + if (proj != null) + { + + projLabel = QuollHyperlink.builder () + .label (new SimpleStringProperty (message.getForProjectName ())) + .tooltip (Utils.newList (prefix,open)) + .styleClassName (StyleClassNames.VIEWPROJECT) + .onAction (ev -> + { + + if (fproj != null) + { + + try + { + + Environment.openProject (fproj); + + } catch (Exception e) { + + Environment.logError ("Unable to open project: " + + fproj, + e); + + } + + } + + }) + .build (); + + } else { + + projLabel = QuollLabel.builder () + .label (new SimpleStringProperty (message.getForProjectName ())) + .build (); + + } + + f.item (getUILanguageStringProperty (Utils.newList (prefix,Project.OBJECT_TYPE)), + projLabel); + + f.item (getUILanguageStringProperty (Utils.newList (prefix, (message.isSentByMe () ? sent : received))), + QuollLabel.builder () + .label (new SimpleStringProperty (Environment.formatDateTime (message.getWhen ()))) + .build ()); + + if (verName != null) + { + + f.item (getUILanguageStringProperty (Utils.newList (prefix,version)), + QuollLabel.builder () + .label (new SimpleStringProperty (verName)) + .build ()); + + } + + f.item (QuollLabel.builder () + .label (getUILanguageStringProperty (Utils.newList (prefix,detail), + Environment.formatNumber (message.getWordCount ()), + Environment.formatNumber (message.getChapters ().size ()))) + .build ()); + //Environment.replaceObjectNames (String.format ("%s words, %s {chapter%s}", + // Environment.formatNumber (message.getWordCount ()), + // message.getChapters ().size (), + // plural)), + + f.item (getUILanguageStringProperty (Utils.newList (prefix,dueby)), + QuollLabel.builder () + .label ((dueDate != null ? new SimpleStringProperty (Environment.formatDate (dueDate)) : getUILanguageStringProperty (Utils.newList (prefix,notspecified)))) + .build ()); + + if (notes != null) + { + + f.item (getUILanguageStringProperty (Utils.newList (prefix,LanguageStrings.notes)), + QuollTextView.builder () + .text (notes) + .build ()); + + } + + if (message.isSentByMe ()) + { + + Node viewProj = null; + + if (proj == null) + { + + viewProj = QuollLabel.builder () + .styleClassName (StyleClassNames.ERROR) + .label (editors,messages,newupdateproject,sent,labels,projectdeleted) + .build (); + //"{Project} has been deleted"); + + } else { + + viewProj = QuollHyperlink.builder () + .label (editors,messages,newupdateproject,sent,labels,clicktoview) + .styleClassName (StyleClassNames.VIEW) + .onAction (ev -> + { + + AbstractViewer childViewer = parentMessageBox.getChildViewer (); + + if (childViewer != null) + { + + childViewer.getViewer ().setIconified (false); + childViewer.getViewer ().toFront (); + + return; + + } + + // Load up the project with the specific text. + // See if we have a project viewer for the project. + ProjectInfo nproj = null; + + try + { + + nproj = Environment.getProjectById (message.getForProjectId (), + Project.NORMAL_PROJECT_TYPE); + + } catch (Exception e) { + + Environment.logError ("Unable to get project for: " + + message.getForProjectId (), + e); + + ComponentUtils.showErrorMessage (viewer, + getUILanguageStringProperty (editors,projectsent,actions,openproject,actionerror)); + //"Unable to show the {project}, please contact Quoll Writer support for assistance."); + + return; + + } + + final ProjectInfo _proj = nproj; + + Consumer open = (_pwd) -> + { + + String pwd = _proj.getFilePassword (); + +/* + ev.getActionCommand (); + + if (pwd.equals ("")) + { + + pwd = null; + + } +*/ + Set chaps = null; + + try + { + + chaps = Environment.getVersionedChapters (_proj, + message.getChapters (), + pwd); + + } catch (Exception e) { + + Environment.logError ("Unable to get versioned chapters for project: " + + _proj, + e); + + ComponentUtils.showErrorMessage (viewer, + getUILanguageStringProperty (editors,projectsent,actions,openproject,actionerror)); + //"Unable to show {comments}, please contact Quoll Writer support for assistance."); + + return; + + } + + try + { + + // Need to "fill up" the project with the chapters and comments. + // Create a new project object just to be safe (in case the getProjectById call changes in the future). + Project np = new Project (); + np.setName (_proj.getName ()); + + np.setType (Project.EDITOR_PROJECT_TYPE); + np.setId (message.getForProjectId ()); + np.setName (message.getForProjectName ()); + + Book b = new Book (np, + np.getName ()); + + np.addBook (b); + + for (Chapter c : chaps) + { + + b.addChapter (c); + + } + + final int chapterCount = chaps.size (); + + ProjectSentReceivedViewer pcv = new ProjectSentReceivedViewer (np, + message) + { + + @Override + public void init (State s) + throws GeneralException + { + + super.init (s); + + this.setMainSideBar (new ProjectSentReceivedSideBar<> (this, + this.message) + { + + @Override + public String getStyleSheet () + { + + return "projectsentreceived"; + + } + + @Override + public String getStyleClassName () + { + + return StyleClassNames.COMMENTS; + + } + + @Override + public StringProperty getTitle () + { + + return getUILanguageStringProperty (editors,projectsent,LanguageStrings.sidebar,title); + + } + + @Override + public StringProperty getItemsTitle () + { + + return getUILanguageStringProperty (editors,projectsent,LanguageStrings.sidebar,chapters,title); + + } + + @Override + public Node getMessageDetails (AbstractProjectMessage message) + { + + List prefix = Arrays.asList (editors,projectsent,LanguageStrings.sidebar,labels); + + ProjectVersion projVer = message.getProjectVersion (); + + String verName = projVer.getName (); + + final String notes = (projVer.getDescription () != null ? projVer.getDescription ().getText () : null); + + Form.Builder fb = Form.builder () + .item (getUILanguageStringProperty (Utils.newList (prefix,sent)), + UILanguageStringsManager.createStringPropertyWithBinding (() -> + { + + return Environment.formatDateTime (message.getWhen ()); + + })); + + if (verName != null) + { + + fb.item (getUILanguageStringProperty (Utils.newList (prefix,version)), + new SimpleStringProperty (verName)); + + } + + if (notes != null) + { + + QuollTextView notesT = QuollTextView.builder () + .inViewer (this.viewer) + .text (UILanguageStringsManager.createStringPropertyWithBinding (() -> + { + + String commText = notes; + + TextIterator ti = new TextIterator (commText); + + if (ti.getSentenceCount () > 1) + { + + commText = ti.getFirstSentence ().getText (); + + commText += getUILanguageStringProperty (Utils.newList (prefix,more)).getValue (); + //"
    More, click to view all."; + + } + + return commText; + + })) + .build (); + + notesT.setOnMouseClicked (ev -> + { + + QuollPopup.messageBuilder () + .withViewer (this.viewer) + .title (getUILanguageStringProperty (editors,projectsent,LanguageStrings.sidebar,LanguageStrings.notes,popup,title)) + .message (new SimpleStringProperty (notes)) + .closeButton () + .build (); + + }); + + fb.item (getUILanguageStringProperty (Utils.newList (prefix,LanguageStrings.notes)), + notesT); + + } + + return fb.build (); + + } + + }); + + } + + @Override + public String getStyleClassName () + { + + return StyleClassNames.COMMENTS; + + } + + }; + + pcv.createViewer (); + pcv.init (new State ()); + + parentMessageBox.setChildViewer (pcv); + + pcv.getViewer ().addEventHandler (Viewer.ViewerEvent.CLOSE_EVENT, + (eev -> + { + + parentMessageBox.setChildViewer (null); + + })); + + } catch (Exception e) { + + Environment.logError ("Unable to view project: " + + _proj, + e); + + ComponentUtils.showErrorMessage (viewer, + getUILanguageStringProperty (editors,projectsent,actions,openproject,actionerror)); + //"Unable to show {project}, please contact Quoll Writer support for assistance."); + + return; + + } + + }; + + UIUtils.askForPasswordForProject (_proj, + null, + open, + null, + viewer); + + }) + .build (); + + } + + f.item (viewProj); + + } + + return f.build (); + + } + + public static Node getNewProjectMessageDetails (final NewProjectMessage mess, + final AbstractProjectViewer viewer, + final MessageBox parentMessageBox) + { + + return EditorsUIUtils.getProjectMessageDetails (mess, + viewer, + parentMessageBox); + + } + +} diff --git a/src/main/java/com/quollwriter/editors/ui/InviteMessageBox.java b/src/main/java/com/quollwriter/editors/ui/InviteMessageBox.java new file mode 100644 index 00000000..a1f43231 --- /dev/null +++ b/src/main/java/com/quollwriter/editors/ui/InviteMessageBox.java @@ -0,0 +1,169 @@ +package com.quollwriter.editors.ui; + +import java.util.*; +import javafx.beans.property.*; +import javafx.scene.*; +import javafx.scene.control.*; +import javafx.scene.layout.*; + +import com.quollwriter.*; +import com.quollwriter.data.*; +import com.quollwriter.data.editors.*; +import com.quollwriter.editors.messages.*; +import com.quollwriter.editors.*; +import com.quollwriter.ui.fx.*; +import com.quollwriter.ui.fx.viewers.*; +import com.quollwriter.ui.fx.components.*; + +import static com.quollwriter.LanguageStrings.*; +import static com.quollwriter.uistrings.UILanguageStringsManager.getUILanguageStringProperty; + +public class InviteMessageBox extends MessageBox +{ + + private VBox responseBox = null; + + public InviteMessageBox (InviteMessage mess, + AbstractViewer viewer) + { + + super (mess, + viewer); + + StringProperty title = getUILanguageStringProperty (editors,messages,invite,sent,LanguageStrings.title); + //"Sent invitation"; + + if (!this.message.isSentByMe ()) + { + + title = getUILanguageStringProperty (editors,messages,invite,received,LanguageStrings.title); + + } + + this.binder.addChangeListener (this.message.dealtWithProperty (), + (pr, oldv, newv) -> + { + + this.responseBox.setVisible (!this.message.isDealtWith ()); + + }); + + this.getStyleClass ().add (StyleClassNames.INVITEMESSAGE); + + this.getChildren ().add (Header.builder () + .title (title) + .iconClassName (StyleClassNames.INVITEMESSAGE) + .build ()); + + if ((!this.message.isDealtWith ()) + && + (!this.message.isSentByMe ()) + ) + { + + this.responseBox = new VBox (); + + this.getChildren ().add (this.responseBox); +/* + this.responseBox.getChildren ().add (QuollLabel.builder () + .label (editors,messages,invite,received,response) + .styleClassName (StyleClassNames.SUBTITLE) + .build ()); +*/ + QuollButtonBar bb = QuollButtonBar.builder () + .button (QuollButton.builder () + .label (editors,messages,invite,received,buttons,LanguageStrings.confirm,text) + .tooltip (editors,messages,invite,received,buttons,LanguageStrings.confirm,tooltip) + .buttonType (ButtonBar.ButtonData.YES) + .onAction (ev -> + { + + this.handleResponse (true); + + }) + .build ()) + .button (QuollButton.builder () + .label (editors,messages,invite,received,buttons,LanguageStrings.reject,text) + .tooltip (editors,messages,invite,received,buttons,LanguageStrings.reject,text) + .buttonType (ButtonBar.ButtonData.NO) + .onAction (ev -> + { + + this.handleResponse (false); + + }) + .build ()) + .build (); + + this.responseBox.getChildren ().add (bb); + + } + + } + + @Override + public boolean isShowAttentionBorder () + { + + return false; + + } + + @Override + public boolean isAutoDealtWith () + { + + return false; + + } + + private void handleResponse (boolean accepted) + { + + EditorEditor ed = this.message.getEditor (); + + InviteResponseMessage rm = new InviteResponseMessage (accepted, + EditorsEnvironment.getUserAccount ()); + rm.setEditor (ed); + + Runnable onComplete = () -> + { + + this.message.setDealtWith (true); + + try + { + + EditorsEnvironment.updateMessage (this.message); + + } catch (Exception e) { + + Environment.logError ("Unable to update message: " + + this.message, + e); + + ComponentUtils.showErrorMessage (this.viewer, + getUILanguageStringProperty (editors,messages,update,actionerror)); + //"Unable to update invite, please contact Quoll Writer support for assistance."); + + } + + }; + + if (accepted) + { + + EditorsEnvironment.acceptInvite (ed, + rm, + onComplete); + + } else { + + EditorsEnvironment.rejectInvite (ed, + rm, + onComplete); + + } + + } +} diff --git a/src/main/java/com/quollwriter/editors/ui/InviteResponseMessageBox.java b/src/main/java/com/quollwriter/editors/ui/InviteResponseMessageBox.java new file mode 100644 index 00000000..a741ca1c --- /dev/null +++ b/src/main/java/com/quollwriter/editors/ui/InviteResponseMessageBox.java @@ -0,0 +1,184 @@ +package com.quollwriter.editors.ui; + +import java.util.*; +import javafx.beans.property.*; +import javafx.scene.*; +import javafx.scene.control.*; +import javafx.scene.layout.*; +import javafx.embed.swing.*; + +import com.quollwriter.*; +import com.quollwriter.data.*; +import com.quollwriter.data.editors.*; +import com.quollwriter.editors.messages.*; +import com.quollwriter.editors.*; +import com.quollwriter.ui.fx.*; +import com.quollwriter.ui.fx.viewers.*; +import com.quollwriter.ui.fx.components.*; + +import static com.quollwriter.LanguageStrings.*; +import static com.quollwriter.uistrings.UILanguageStringsManager.getUILanguageStringProperty; + +// Use an annotation? +//@MessageBox(messageClass=InviteResponseMessage) +public class InviteResponseMessageBox extends MessageBox +{ + + private VBox responseBox = null; + + public InviteResponseMessageBox (InviteResponseMessage mess, + AbstractViewer viewer) + { + + super (mess, + viewer); + + if (!this.message.isDealtWith ()) + { + + // Show the response. + this.responseBox = new VBox (); + this.responseBox.managedProperty ().bind (this.responseBox.visibleProperty ()); + this.getStyleClass ().add (StyleClassNames.INVITEMESSAGE); + + this.getChildren ().add (Header.builder () + .title (editors,messages,inviteresponse,undealtwith,(this.message.isAccepted () ? accepted : rejected),title) + .iconClassName (this.message.isAccepted () ? StyleClassNames.ACCEPTED : StyleClassNames.REJECTED) + .build ()); + + this.getChildren ().add (this.responseBox); + + if (this.message.isAccepted ()) + { + + if ((this.message.getEditorName () != null) + || + (this.message.getEditorAvatar () != null) + ) + { + + this.responseBox.getChildren ().add (QuollTextView.builder () + .text (getUILanguageStringProperty (editors,messages,inviteresponse,undealtwith,accepted,text)) + .inViewer (this.viewer) + .build ()); + + HBox editorInfo = new HBox (); + editorInfo.getStyleClass ().add (StyleClassNames.DETAILS); + + this.responseBox.getChildren ().add (editorInfo); + + if (this.message.getEditorAvatar () != null) + { + + editorInfo.getChildren ().add (UIUtils.getImageView (this.message.getEditorAvatar ())); + + } + + if (this.message.getEditorName () != null) + { + + editorInfo.getChildren ().add (QuollLabel.builder () + .label (this.message.getEditorName ()) + .build ()); + + } + + } + + } + + final EditorEditor ed = this.message.getEditor (); + + this.responseBox.getChildren ().add (QuollButtonBar.builder () + .button (QuollButton.builder () + .label (editors,messages,inviteresponse,undealtwith,buttons,confirm) + .onAction (ev -> + { + + try + { + + if (this.message.isAccepted ()) + { + + ed.setEditorStatus (EditorEditor.EditorStatus.current); + + if (this.message.getEditorName () != null) + { + + ed.setName (this.message.getEditorName ()); + + } + + if (this.message.getEditorAvatar () != null) + { + + ed.setAvatar (this.message.getEditorAvatar ()); + + } + + EditorsEnvironment.updateEditor (ed); + + // Is this response for an invite message or just out of the blue from a web service invite? + if (!EditorsEnvironment.hasSentMessageOfTypeToEditor (ed, + InviteMessage.MESSAGE_TYPE)) + { + + EditorsEnvironment.sendUserInformationToEditor (ed, + null, + null, + null); + + } + + } else { + + ed.setEditorStatus (EditorEditor.EditorStatus.rejected); + + EditorsEnvironment.updateEditor (ed); + + } + + this.message.setDealtWith (true); + + EditorsEnvironment.updateMessage (this.message); + + this.responseBox.setVisible (false); + + } catch (Exception e) { + + Environment.logError ("Unable to update editor: " + + ed, + e); + + ComponentUtils.showErrorMessage (this.viewer, + getUILanguageStringProperty (editors,editor,edit,actionerror)); + //"Unable to update {editor}, please contact Quoll Writer support for assistance."); + + return; + + } + + }) + .build ()) + .build ()); + + return; + + } + + this.getChildren ().add (Header.builder () + .iconClassName (this.message.isAccepted () ? StyleClassNames.ACCEPTED : StyleClassNames.REJECTED) + .title (editors,messages,inviteresponse,dealtwith,(this.message.isAccepted () ? LanguageStrings.accepted : rejected),title) + .build ()); + + } + + public boolean isAutoDealtWith () + { + + return false; + + } + +} diff --git a/src/main/java/com/quollwriter/editors/ui/MessageAccordionItem.java b/src/main/java/com/quollwriter/editors/ui/MessageAccordionItem.java new file mode 100644 index 00000000..e9f1e2e0 --- /dev/null +++ b/src/main/java/com/quollwriter/editors/ui/MessageAccordionItem.java @@ -0,0 +1,197 @@ +package com.quollwriter.editors.ui; + +import java.util.*; +import javafx.scene.*; +import javafx.beans.property.*; +import javafx.scene.layout.*; + +import com.quollwriter.data.*; +import com.quollwriter.data.editors.*; +import com.quollwriter.*; +import com.quollwriter.editors.messages.*; +import com.quollwriter.ui.fx.components.*; +import com.quollwriter.ui.fx.*; +import com.quollwriter.ui.fx.viewers.*; +import com.quollwriter.uistrings.UILanguageStringsManager; + +import static com.quollwriter.LanguageStrings.*; +import static com.quollwriter.uistrings.UILanguageStringsManager.getUILanguageStringProperty; + +public class MessageAccordionItem extends VBox +{ + + protected AbstractViewer viewer = null; + protected Date date = null; + protected AccordionItem accItem = null; + private StringProperty titleProp = new SimpleStringProperty (); + + public MessageAccordionItem (AbstractViewer viewer, + Date d, + Set messages) + { + + if (messages == null) + { + + throw new IllegalArgumentException ("Messages is null."); + + } + + this.managedProperty ().bind (this.visibleProperty ()); + this.date = d; + + //this.getStyleClass ().add (StyleClassNames.CHATMESSAGES); + + this.viewer = viewer; + + for (E m : messages) + { + + this.addMessage (m); + + } + + this.updateHeaderTitle (); + + } + + public void updateHeaderTitle () + { + + StringProperty dateName = null; + + if (Utils.isToday (this.date)) + { + + dateName = getUILanguageStringProperty (times,today); + //"Today"; + + } + + if (Utils.isYesterday (this.date)) + { + + dateName = getUILanguageStringProperty (times,yesterday); + //"Yesterday"; + + } + + if (dateName == null) + { + + dateName = UILanguageStringsManager.createStringPropertyWithBinding (() -> + { + + return Environment.formatDate (this.date); + + }); + + } + + int c = this.getChildren ().size (); + + this.titleProp.unbind (); + this.titleProp.bind (getUILanguageStringProperty (Arrays.asList (editors,editor,view,chatmessages,title), + dateName, + c)); + + } + + public AccordionItem getAccordionItem () + { + + if (this.accItem == null) + { + + this.accItem = this.createAccordionItem (); + + } + + return this.accItem; + + } + + public AccordionItem createAccordionItem () + { + + AccordionItem acc = AccordionItem.builder () + .openContent (this) + .title (this.titleProp) + .styleClassName (StyleClassNames.CHATMESSAGES) + .build (); + + return acc; + + } + + public void addMessage (E m) + { + + Node mb = this.getMessageBox (m); + + if (mb == null) + { + + return; + + } + + this.getChildren ().add (mb); + + this.updateHeaderTitle (); + + } + + public Node getMessageBox (E m) + { + + MessageBox mb = null; + + try + { + + mb = MessageBoxFactory.getMessageBoxInstance (m, + this.viewer); + + } catch (Exception e) { + + Environment.logError ("Unable to get message box for message: " + + m, + e); + + return null; + + } +/* + Box b = new Box (BoxLayout.Y_AXIS); + b.setAlignmentX (Component.LEFT_ALIGNMENT); + + Box details = new Box (BoxLayout.X_AXIS); + details.setAlignmentX (Component.LEFT_ALIGNMENT); + + String name = m.getEditor ().getMainName (); + + if (m.isSentByMe ()) + { + + name = "Me"; + + } + + details.add (this.createLabel (name)); + details.add (Box.createHorizontalGlue ()); + details.add (this.createLabel (Environment.formatTime (m.getWhen ()))); + + b.add (details); + + b.add (Box.createVerticalStrut (5)); + + mb.setAlignmentX (Component.LEFT_ALIGNMENT); + + b.add (mb); +*/ + return mb; + + } + +} diff --git a/src/main/java/com/quollwriter/editors/ui/MessageBox.java b/src/main/java/com/quollwriter/editors/ui/MessageBox.java new file mode 100644 index 00000000..adca26ac --- /dev/null +++ b/src/main/java/com/quollwriter/editors/ui/MessageBox.java @@ -0,0 +1,338 @@ +package com.quollwriter.editors.ui; + +import java.util.*; +import java.util.concurrent.*; +import javafx.scene.layout.*; +import javafx.scene.control.*; +import javafx.scene.input.*; + +import com.quollwriter.*; +import com.quollwriter.data.*; +import com.quollwriter.events.*; +import com.quollwriter.editors.messages.*; +import com.quollwriter.editors.*; +import com.quollwriter.ui.fx.*; +import com.quollwriter.ui.fx.components.*; +import com.quollwriter.ui.fx.viewers.*; + +import static com.quollwriter.LanguageStrings.*; +import static com.quollwriter.uistrings.UILanguageStringsManager.getUILanguageStringProperty; + +public abstract class MessageBox extends VBox implements EditorMessageListener +{ + + protected AbstractViewer viewer = null; + protected E message = null; + protected boolean showAttentionBorder = true; + private PropertyChangedListener updateListener = null; + private AbstractViewer childViewer = null; + private ScheduledFuture updateAttention = null; + protected IPropertyBinder binder = null; + + public MessageBox (E mess, + AbstractViewer viewer) + { + + this.binder = new PropertyBinder (); + this.message = mess; + this.viewer = viewer; + + // TODO ADD SCENE LISTENER + + this.getStyleClass ().add (StyleClassNames.MESSAGE); + + this.binder.addChangeListener (this.message.dealtWithProperty (), + (pr, oldv, newv) -> + { + + this.update (); + + this.pseudoClassStateChanged (StyleClassNames.ATTENTIONREQUIRED_PSEUDO_CLASS, !newv && this.showAttentionBorder); + + UIUtils.setTooltip (this, + getUILanguageStringProperty (Arrays.asList (editors,messages,view,tooltip,(this.message.isSentByMe () ? sent : received)), + //"%s %s", + //this.message.isSentByMe () ? "Sent" : "Received", + Environment.formatDateTime (this.message.getWhen ()))); + + }); + + this.addEventHandler (MouseEvent.MOUSE_ENTERED, + ev -> + { + + if (this.updateAttention != null) + { + + this.updateAttention.cancel (true); + + } + + }); + + this.addEventHandler (MouseEvent.MOUSE_EXITED, + ev -> + { + + if ((!this.message.isDealtWith ()) + && + (this.isAutoDealtWith ()) + ) + { + + this.updateAttention = Environment.schedule (() -> + { + + this.message.setDealtWith (true); + + try + { + + EditorsEnvironment.updateMessage (this.message); + + } catch (Exception e) { + + Environment.logError ("Unable to update message: " + + this.message, + e); + + } + + }, + 750, + -1); + + } + + }); + + this.setOnContextMenuRequested (ev -> + { + + if (this.getProperties ().get ("context-menu") != null) + { + + ((ContextMenu) this.getProperties ().get ("context-menu")).hide (); + + } + + if (!this.message.isSentByMe ()) + { + + ContextMenu m = new ContextMenu (); + + m.getItems ().add (QuollMenuItem.builder () + .label (editors,messages,report,popupmenu,items,report) + .iconName (StyleClassNames.REPORTMESSAGE) + .onAction (eev -> + { + + EditorsUIUtils.showReportMessage (this, + this.viewer, + this.binder); + + }) + .build ()); + + m.show (this, ev.getScreenX (), ev.getScreenY ()); + + this.getProperties ().put ("context-menu", m); + + ev.consume (); + + } + + }); + + this.update (); + + } + + private void update () + { + + this.pseudoClassStateChanged (StyleClassNames.ATTENTIONREQUIRED_PSEUDO_CLASS, !this.message.isDealtWith () && this.showAttentionBorder); + + if ((!this.message.isDealtWith ()) + && + (this.showAttentionBorder) + ) + { + + UIUtils.setTooltip (this, + getUILanguageStringProperty (editors,messages,view,attention,tooltip));//"This message needs your attention!"); + + } else { + + UIUtils.setTooltip (this, + getUILanguageStringProperty (Arrays.asList (editors,messages,view,tooltip,(this.message.isSentByMe () ? sent : received)), + //"%s %s", + //this.message.isSentByMe () ? "Sent" : "Received", + Environment.formatDateTime (this.message.getWhen ()))); + + } + + } + + public abstract boolean isAutoDealtWith (); + + public AbstractViewer getChildViewer () + { + + return this.childViewer; + + } + + public void setChildViewer (AbstractViewer v) + { + + this.childViewer = v; + + } + +/* + @Override + public Component add (Component c) + { + + if (c instanceof JLayer) + { + + return super.add (c); + + } + + return this.content.add (c); + + } +*/ + public void setShowAttentionBorder (boolean v) + { + + this.showAttentionBorder = v; + + this.update (); + + } + + public boolean isShowAttentionBorder () + { + + return this.showAttentionBorder; + + } + + public EditorMessage getMessage () + { + + return this.message; + + } + + public boolean isDealtWith () + { + + return this.message.isDealtWith (); + + } + + public String getOpenMessageLink (EditorMessage m, + String link) + { + + return String.format ("%s", + Constants.OPENEDITORMESSAGE_PROTOCOL, + m.getKey (), + link); + + } + + @Override + /** + * Listens for message events relating to the underlying message this box is displaying. + * If the event is for our message and the message has been changed then {@link #update()} is called. + * + * @param ev The event. + */ + public void handleMessage (EditorMessageEvent ev) + { + + // Is this message for us? + if ((ev.getMessage ().equals (this.message)) + && + (ev.getType () == EditorMessageEvent.MESSAGE_CHANGED) + ) + { + + this.update (); + + } + + } +/* + protected JComponent getMessageQuoteComponent (String message) + { + + Box b = new Box (BoxLayout.X_AXIS); + + ImagePanel ip = new ImagePanel (Environment.getIcon (Constants.MESSAGE_ICON_NAME, + Constants.ICON_POPUP), + null); + + ip.setAlignmentY (Component.TOP_ALIGNMENT); + + //b.add (ip); + //b.add (Box.createHorizontalStrut (5)); + + JComponent t = UIUtils.createHelpTextPane (message, + this.viewer); + t.setAlignmentY (Component.TOP_ALIGNMENT); + + t.setBorder (null); + t.setOpaque (false); + + b.add (t); + + b.setAlignmentX (Component.LEFT_ALIGNMENT); + + return b; + + } +*/ +/* + protected JComponent getMessageComponent (String message, + String iconName) + { + + Box b = new Box (BoxLayout.X_AXIS); + + if (iconName != null) + { + + ImagePanel ip = new ImagePanel (Environment.getIcon (iconName, + Constants.ICON_EDITOR_MESSAGE), + null); + + ip.setAlignmentY (Component.TOP_ALIGNMENT); + + b.add (ip); + b.add (Box.createHorizontalStrut (5)); + + } + + JComponent t = UIUtils.createHelpTextPane (message, + this.viewer); + t.setAlignmentY (Component.TOP_ALIGNMENT); + + t.setBorder (null); + t.setOpaque (false); + + b.add (t); + + b.setAlignmentX (Component.LEFT_ALIGNMENT); + + return b; + + } +*/ +} diff --git a/src/com/quollwriter/editors/ui/MessageBoxFactory.java b/src/main/java/com/quollwriter/editors/ui/MessageBoxFactory.java similarity index 91% rename from src/com/quollwriter/editors/ui/MessageBoxFactory.java rename to src/main/java/com/quollwriter/editors/ui/MessageBoxFactory.java index 777db326..8097bb00 100644 --- a/src/com/quollwriter/editors/ui/MessageBoxFactory.java +++ b/src/main/java/com/quollwriter/editors/ui/MessageBoxFactory.java @@ -4,7 +4,7 @@ import java.lang.reflect.*; import com.quollwriter.*; -import com.quollwriter.ui.*; +import com.quollwriter.ui.fx.viewers.*; import com.quollwriter.editors.messages.*; /** @@ -14,21 +14,21 @@ */ public class MessageBoxFactory { - + private static final Map boxTypes = new HashMap (); - + static { - + Map m = MessageBoxFactory.boxTypes; - + // See the discussion of how this is handled in MessageFactory, the same arguments // can (and should) be made here. - + // This is a little more complex however since there are times when a user may want to // use their own representation of messages. // TODO: Make more flexible in a future release, especially to allow custom representations. - + // TODO: Move this setup to a config file that dynamically loads the classes. m.put (EditorChatMessage.MESSAGE_TYPE, ChatMessageBox.class); @@ -50,9 +50,9 @@ public class MessageBoxFactory UpdateProjectMessageBox.class); m.put (EditorRemovedMessage.MESSAGE_TYPE, EditorRemovedMessageBox.class); - - } - + + } + /** * Create a new message box for the message. May be null if the message isn't supported. * The message box WON'T be inited before return. @@ -66,67 +66,67 @@ public static MessageBox getMessageBoxInstance (EditorMessage mess, AbstractViewer viewer) throws Exception { - + if (mess == null) { - + throw new IllegalArgumentException ("No message specified."); - + } - + Class c = MessageBoxFactory.boxTypes.get (mess.getMessageType ()); - + if (c == null) { - + return null; - + } - + // Get the constructor. Constructor cons = null; - + try { - + cons = c.getConstructor (mess.getClass (), AbstractViewer.class); - + } catch (Exception e) { - + throw new GeneralException ("Unable to get constructor for message type: " + mess.getMessageType (), e); - + } - + if (cons == null) { - + throw new IllegalArgumentException ("Class: " + c.getName () + " does not have the correct constructor"); - + } - + MessageBox mb = null; - + try { - + mb = (MessageBox) cons.newInstance (mess, viewer); - + } catch (Exception e) { - + throw new GeneralException ("Unable to create new instance of: " + c.getName (), e); - + } - + return mb; - + } - -} \ No newline at end of file + +} diff --git a/src/main/java/com/quollwriter/editors/ui/NewProjectMessageBox.java b/src/main/java/com/quollwriter/editors/ui/NewProjectMessageBox.java new file mode 100644 index 00000000..ec8d6897 --- /dev/null +++ b/src/main/java/com/quollwriter/editors/ui/NewProjectMessageBox.java @@ -0,0 +1,658 @@ +package com.quollwriter.editors.ui; + +import java.util.*; + +import java.io.*; +import java.nio.file.*; + +import javafx.beans.property.*; +import javafx.scene.*; +import javafx.scene.control.*; +import javafx.scene.layout.*; + +import com.quollwriter.*; +import com.quollwriter.data.*; +import com.quollwriter.editors.messages.*; +import com.quollwriter.editors.*; +import com.quollwriter.text.*; +import com.quollwriter.events.*; +import com.quollwriter.ui.fx.*; +import com.quollwriter.ui.fx.viewers.*; +import com.quollwriter.ui.fx.components.*; + +import static com.quollwriter.LanguageStrings.*; +import static com.quollwriter.uistrings.UILanguageStringsManager.getUILanguageStringProperty; + +public class NewProjectMessageBox extends MessageBox +{ + + private VBox responseBox = null; + private ProjectSentReceivedViewer sentViewer = null; + private Label previousLabel = null; + private QuollButtonBar responseButs = null; + + public NewProjectMessageBox (NewProjectMessage mess, + AbstractViewer viewer) + { + + super (mess, + viewer); + + this.getStyleClass ().add (StyleClassNames.NEWPROJECT); + + final NewProjectMessageBox _this = this; + + StringProperty text = getUILanguageStringProperty (editors,messages,newproject,sent,title); + //"Sent {project}"; + + if (!this.message.isSentByMe ()) + { + + text = getUILanguageStringProperty (editors,messages,newproject,received,title); + //"Received an invitation to edit a {project}"; + + } + + this.getStyleClass ().add (StyleClassNames.NEWPROJECTMESSAGE); + + this.getChildren ().add (Header.builder () + .title (text) + .styleClassName (StyleClassNames.HEADER) + .iconClassName (StyleClassNames.PROJECT) + .build ()); + + this.binder.addChangeListener (this.message.dealtWithProperty (), + (pr, oldv, newv) -> + { + + this.update (); + + }); + + this.binder.addChangeListener (this.message.getEditor ().editorStatusProperty (), + (pr, oldv, newv) -> + { + + this.update (); + + }); + + Node details = EditorsUIUtils.getProjectMessageDetails (this.message, + this.viewer, + this); + + details.getStyleClass ().add (StyleClassNames.MESSAGEDETAILS); + this.getChildren ().add (details); + + this.responseBox = new VBox (); + this.responseBox.getStyleClass ().add (StyleClassNames.RESPONSE); + this.responseBox.managedProperty ().bind (this.responseBox.visibleProperty ()); + this.responseBox.setVisible (false); + this.getChildren ().add (this.responseBox); +/* + if (!this.message.isSentByMe ()) + { + + // Not sent by me. + if ((!this.message.isDealtWith ()) + && + (!this.message.getEditor ().isPrevious ()) + ) + { + + Button update = QuollButton.builder () + .label (editors,messages,updateproject,received,undealtwith,buttons,LanguageStrings.update) + .onAction (ev -> + { + + EditorsUIUtils.showProjectUpdate (this.message, + this.viewer, + null); + + }) + .build (); + + this.responseBox.getChildren ().add (update); + this.responseBox.setVisible (true); + + } + + } +*/ + this.previousLabel = QuollLabel.builder () + .styleClassName (StyleClassNames.PREVIOUS) + .build (); + + if ((!this.message.isDealtWith ()) + && + (!this.message.isSentByMe ()) + && + (!this.message.getEditor ().isPrevious ()) + ) + { + + this.responseBox.setVisible (true); + + this.responseBox.getChildren ().add (Header.builder () + .title (editors,messages,newproject,received,undealtwith,LanguageStrings.text) + .build ()); + + this.responseButs = QuollButtonBar.builder () + .button (QuollButton.builder () + .label (editors,messages,newproject,received,undealtwith,buttons,LanguageStrings.accept,LanguageStrings.text) + .buttonType (ButtonBar.ButtonData.YES) + .onAction (ev -> + { + + this.handleNewProjectResponse (true); + + }) + .tooltip (editors,messages,newproject,received,undealtwith,buttons,LanguageStrings.accept,tooltip) + .build ()) + .button (QuollButton.builder () + .label (editors,messages,newproject,received,undealtwith,buttons,LanguageStrings.reject,LanguageStrings.text) + .buttonType (ButtonBar.ButtonData.NO) + .onAction (ev -> + { + + this.handleNewProjectResponse (false); + + }) + .tooltip (editors,messages,newproject,received,undealtwith,buttons,LanguageStrings.reject,tooltip) + .build ()) + .build (); + + this.responseBox.getChildren ().add (this.responseButs); + + } + + } + + @Override + public boolean isAutoDealtWith () + { + + return false; + + } + + @Override + public boolean isShowAttentionBorder () + { + + if (this.message.getEditor ().isPrevious ()) + { + + return false; + + } + + return super.isShowAttentionBorder (); + + } + + private void update () + { + + this.previousLabel.setVisible (false); + + if (this.message.isDealtWith ()) + { + + this.responseBox.setVisible (false); + + } + + if ((!this.message.isDealtWith ()) + && + (this.message.getEditor ().isPrevious ()) + ) + { + + this.previousLabel.textProperty ().unbind (); + this.previousLabel.textProperty ().bind (getUILanguageStringProperty (Arrays.asList (editors,messages,newproject,received,undealtwith,previouseditor), + //"%s is a previous {contact}. This message can no longer be acted upon.", + this.message.getEditor ().getMainName ())); + this.previousLabel.setVisible (true); + this.responseBox.setVisible (false); + + } + + } + + private void handleNewProjectAccept () + { + + List prefix = Arrays.asList (editors,messages,newproject,received,undealtwith,LanguageStrings.accepted,popup); + + VBox content = new VBox (); + + QuollPopup qp = QuollPopup.builder () + .headerIconClassName (StyleClassNames.PROJECT) + .styleClassName (StyleClassNames.ACCEPT) + .styleSheet ("editoracceptproject") + .title (Utils.newList (prefix,title)) + .content (content) + .inViewer (this.viewer) + .hideOnEscape (true) + .removeOnClose (true) + .withClose (true) + .build (); +/* +TODO Remove + content.getChildren ().add (Header.builder () + .title (Utils.newList (prefix,labels,where)) + .build ()); +*/ +/* +TODO Is this needed? + Path defDir = Environment.getDefaultSaveProjectDirPath (); + + try + { + + Files.createDirectories (defDir); + + } catch (Exception e) { + + Environment.logError ("Unable to create directories for: " + defDir, + e); + + // TODO Hanlde this error. + + } +*/ + + Path defDir = Environment.getDefaultSaveProjectDirPath (); + Path nf = defDir.resolve ("editor-projects/").resolve (this.message.getEditor ().getEmail ()); + + try + { + + Files.createDirectories (nf); + + } catch (Exception e) { + + Environment.logError ("Unable to create directories for: " + defDir, + e); + + // TODO Hanlde this error. + + } + + QuollFileField saveDir = QuollFileField.builder () + .styleClassName (StyleClassNames.SAVE) + .initialFile (nf) + .limitTo (QuollFileField.Type.directory) + .chooserTitle (Utils.newList (prefix,finder,tooltip)) + .withViewer (viewer) + .build (); + + QuollCheckBox encrypt = QuollCheckBox.builder () + .selected (false) + .label (Utils.newList (prefix,labels,LanguageStrings.encrypt)) + .build (); + + QuollPasswordField passwords = QuollPasswordField.builder () + .passwordLabel (getUILanguageStringProperty (Utils.newList (prefix,labels,password))) + .confirmLabel (getUILanguageStringProperty (Utils.newList (prefix,labels,confirmpassword))) + .build (); + + passwords.managedProperty ().bind (passwords.visibleProperty ()); + passwords.setVisible (false); + encrypt.selectedProperty ().addListener ((v, oldv, newv) -> + { + + passwords.setVisible (newv); + + }); + + QuollTextArea mess = QuollTextArea.builder () + .placeholder (getUILanguageStringProperty (Utils.newList (prefix,labels,sendmessage,tooltip), + //"You can optionally return a message to %s using this box.", + this.message.getEditor ().getMainName ())) + .maxChars (5000) + .build (); + + Form form = Form.builder () + //.description (desc) + .layoutType (Form.LayoutType.stacked) + .item (getUILanguageStringProperty (Utils.newList (prefix,labels,project)), + QuollLabel.builder () + .label (this.message.forProjectNameProperty ()) + .build ()) + .item (getUILanguageStringProperty (Utils.newList (prefix,labels,save)), + saveDir) + .item (encrypt) + .item (passwords) + .item (Header.builder () + .title (Utils.newList (prefix,labels,sendmessage,text)) + .styleClassName (StyleClassNames.SUBTITLE) + .build ()) + .item (mess) + .confirmButton (getUILanguageStringProperty (Utils.newList (prefix,buttons,LanguageStrings.save))) + .cancelButton (getUILanguageStringProperty (Utils.newList (prefix,buttons,LanguageStrings.cancel))) + .build (); + + content.getChildren ().add (form); + + form.setOnCancel (ev -> + { + + qp.close (); + + }); + + form.setOnConfirm (ev -> + { + + form.hideError (); + + List prefix2 = Arrays.asList (editors,messages,newproject,received,undealtwith,LanguageStrings.accepted,popup); + + // See if the project already exists. + Path pf = saveDir.getFile ().resolve (Utils.sanitizeForFilename (this.message.getForProjectName ())); + + if (Files.exists (pf)) + { + + form.showError (getUILanguageStringProperty (Utils.newList (prefix2,errors,valueexists), + //"A {project} called: %s already exists.", + this.message.forProjectNameProperty (), + pf)); + + return; + + } + + String pwd = passwords.getPassword1 (); + + if (encrypt.isSelected ()) + { + + // Make sure a password has been provided. + String pwd2 = passwords.getPassword2 (); + + if (pwd.equals ("")) + { + + form.showError (getUILanguageStringProperty (Utils.newList (prefix2,errors,nopassword))); + //"Please provide a password for securing the {project}."); + return; + + } + + if (pwd2.equals ("")) + { + + form.showError (getUILanguageStringProperty (Utils.newList (prefix2,errors,confirmpassword))); + //"Please confirm your password."); + return; + + } + + if (!pwd.equals (pwd2)) + { + + form.showError (getUILanguageStringProperty (Utils.newList (prefix2,errors,nomatch))); + //"The passwords do not match."); + return; + + } + + } + + final String responseMessage = (mess.getText ().trim ().length () == 0 ? null : mess.getText ().trim ()); + + this.message.setResponseMessage (responseMessage); + + // Create the project. + Project p = null; + + try + { + + p = this.message.createProject (); + + } catch (Exception e) { + + Environment.logError ("Unable to create project from message: " + + this.message, + e); + + form.showError (getUILanguageStringProperty (editors,messages,newproject,received,undealtwith,LanguageStrings.accepted,actionerror)); + //"Unable to save {project}, please contact Quoll Writer support for assistance."); + + return; + + } + + final Project fproj = p; + + // Put it in the user's directory. + try + { + + if (pwd.length () > 0) + { + + p.setFilePassword (pwd); + + } + + // We create the project but then close the connection pool since the user + // may not want to open the project yet. + Environment.createProject (saveDir.getFile (), + p).closeConnectionPool (); + + } catch (Exception e) { + + Environment.logError ("Unable to save editor project to: " + + saveDir + + ", message: " + + this.message, + e); + + form.showError (getUILanguageStringProperty (editors,messages,newproject,received,undealtwith,LanguageStrings.accepted,actionerror)); + //"Unable to save {project}, please contact Quoll Writer support for assistance."); + + return; + + } + + this.message.setDealtWith (true); + + Runnable onComplete = () -> + { + + String popupId = "open-editor-proj" + fproj.getId (); + + if (this.viewer.getPopupById (popupId) != null) + { + + return; + + } + + UIUtils.runLater (() -> + { + + qp.close (); + + }); + + this.message.setAccepted (true); + this.message.setDealtWith (true); + this.message.setResponseMessage (responseMessage); + + try + { + + // Update the original message. + EditorsEnvironment.updateMessage (this.message); + + } catch (Exception e) { + + Environment.logError ("Unable to update message: " + + this.message, + e); + + ComponentUtils.showErrorMessage (getUILanguageStringProperty (editors,messages,newproject,received,undealtwith,LanguageStrings.accepted,actionerror)); + //"Unable to update message, please contact Quoll Writer support for assistance."); + + // Should really carry on... maybe... + + } + + UIUtils.runLater (() -> + { + + QuollPopup.questionBuilder () + .styleClassName (StyleClassNames.OPEN) + .popupId (popupId) + .title (editors,messages,newproject,received,undealtwith,LanguageStrings.accepted,openproject,popup,title) + .message (editors,messages,newproject,received,undealtwith,LanguageStrings.accepted,openproject,popup,text) + .confirmButtonLabel (editors,messages,newproject,received,undealtwith,LanguageStrings.accepted,openproject,popup,buttons,confirm) + .cancelButtonLabel (editors,messages,newproject,received,undealtwith,LanguageStrings.accepted,openproject,popup,buttons,cancel) + .onConfirm (eev -> + { + + this.viewer.getPopupById (popupId).close (); + + try + { + + Environment.openProject (fproj, + () -> + { + + // Show the first chapter. + AbstractProjectViewer pv = Environment.getProjectViewer (fproj); + + if (pv != null) + { + + pv.viewObject (pv.getProject ().getBook (0).getChapters ().get (0)); + + } + + }); + + } catch (Exception e) { + + Environment.logError ("Unable to open project: " + + fproj, + e); + + ComponentUtils.showErrorMessage (getUILanguageStringProperty (editors,messages,newproject,received,undealtwith,LanguageStrings.accepted,openproject,actionerror)); + //"Unable to open {project}: " + fproj.getName () + " please contact Quoll Support for assistance."); + + } + + + + }) + .build (); + + }); + + }; + + NewProjectResponseMessage res = new NewProjectResponseMessage (this.message.getForProjectId (), + true, + responseMessage, + this.message.getEditor (), + EditorsEnvironment.getUserAccount ()); + + if (this.message.getEditor ().isPending ()) + { + + EditorsEnvironment.acceptInvite (this.message.getEditor (), + res, + onComplete); + + } else { + + EditorsEnvironment.sendMessageToEditor (res, + onComplete, + null, + null); + + } + + }); + + qp.show (); + + } + + public void handleNewProjectResponse (boolean accepted) + { + + if (accepted) + { + + this.handleNewProjectAccept (); + + } else { + + // Ask for a response? + final String responseMessage = null; + + this.message.setDealtWith (true); + + Runnable onComplete = () -> + { + + this.message.setAccepted (accepted); + this.message.setDealtWith (true); + this.message.setResponseMessage (responseMessage); + + try + { + + // Update the original message. + EditorsEnvironment.updateMessage (this.message); + + } catch (Exception e) { + + Environment.logError ("Unable to update message: " + + this.message, + e); + + ComponentUtils.showErrorMessage (getUILanguageStringProperty (editors,messages,update,actionerror)); + //"Unable to update message, please contact Quoll Writer support for assistance."); + + // Should really carry on... maybe... + + } + + }; + + NewProjectResponseMessage res = new NewProjectResponseMessage (this.message.getForProjectId (), + false, + responseMessage, + this.message.getEditor (), + EditorsEnvironment.getUserAccount ()); + + if (this.message.getEditor ().isPending ()) + { + + EditorsEnvironment.rejectInvite (this.message.getEditor (), + res, + onComplete); + + } else { + + EditorsEnvironment.sendMessageToEditor (res, + onComplete, + null, + null); + + } + + } + + } + +} diff --git a/src/main/java/com/quollwriter/editors/ui/NewProjectResponseMessageBox.java b/src/main/java/com/quollwriter/editors/ui/NewProjectResponseMessageBox.java new file mode 100644 index 00000000..73179802 --- /dev/null +++ b/src/main/java/com/quollwriter/editors/ui/NewProjectResponseMessageBox.java @@ -0,0 +1,596 @@ +package com.quollwriter.editors.ui; + +import java.util.*; +import javafx.beans.property.*; +import javafx.scene.layout.*; +import javafx.scene.control.*; +import javafx.scene.*; +import javafx.scene.image.*; +import javafx.embed.swing.*; + +import com.quollwriter.*; +import com.quollwriter.data.*; +import com.quollwriter.data.editors.*; +import com.quollwriter.editors.messages.*; +import com.quollwriter.editors.*; +import com.quollwriter.ui.fx.components.*; +import com.quollwriter.ui.fx.viewers.*; +import com.quollwriter.ui.fx.*; + +import static com.quollwriter.LanguageStrings.*; +import static com.quollwriter.uistrings.UILanguageStringsManager.getUILanguageStringProperty; + +// Use an annotation? +//@MessageBox(class=NewProjectResponseMessage) +public class NewProjectResponseMessageBox extends MessageBox +{ + + private VBox responseBox = null; + + public NewProjectResponseMessageBox (NewProjectResponseMessage mess, + AbstractViewer viewer) + { + + super (mess, + viewer); + + this.getStyleClass ().add (StyleClassNames.NEWPROJECTRESPONSE); + + this.binder.addChangeListener (mess.getEditor ().editorStatusProperty (), + (pr, oldv, newv) -> + { + + if (this.responseBox != null) + { + + this.responseBox.setVisible (false); + + } + + }); + + this.binder.addChangeListener (mess.dealtWithProperty (), + (pr, oldv, newv) -> + { + + if ((newv) + && + (this.responseBox != null) + ) + { + + this.responseBox.setVisible (false); + + } + + }); + + ProjectInfo proj = null; + + try + { + + proj = Environment.getProjectById (this.message.getForProjectId (), + (this.message.isSentByMe () ? Project.EDITOR_PROJECT_TYPE : Project.NORMAL_PROJECT_TYPE)); + + } catch (Exception e) { + + Environment.logError ("Unable to get project: " + + this.message.getForProjectId (), + e); + + } + + final EditorEditor ed = this.message.getEditor (); + + ProjectEditor pe = null; + + if (proj != null) + { + + try + { + + pe = EditorsEnvironment.getProjectEditor (proj, + ed); + + } catch (Exception e) { + + Environment.logError ("Unable to get project editor for project: " + + proj + + ", editor: " + + ed, + e); + + } + + } + + final ProjectEditor fpe = pe; +/* +TODO Remove, not needed + if (pe == null) + { + + Environment.logError ("Unable to get project editor for project: " + + proj + + ", editor: " + + ed); + + } +*/ + // Only do this if the editor is still pending. + if ((!this.message.isDealtWith ()) + && + (this.message.getEditor ().isPending ()) + ) + { + + // Show the response. + this.responseBox = new VBox (); + this.responseBox.managedProperty ().bind (this.responseBox.visibleProperty ()); + + this.getChildren ().add (this.responseBox); + + Header l = Header.builder () + .title (editors,messages,newprojectresponse,received,(this.message.isAccepted () ? accepted : rejected),title) + .styleClassName (StyleClassNames.HEADER) + .iconClassName (StyleClassNames.ACCEPTED) + .build (); + l.getStyleClass ().add (this.message.isAccepted () ? StyleClassNames.ACCEPTED : StyleClassNames.REJECTED); + + this.responseBox.getChildren ().add (l); + + this.responseBox.getChildren ().add (this.getResponseDetails ()); + + if (this.message.isAccepted ()) + { + + if ((this.message.getEditorName () != null) + || + (this.message.getEditorAvatar () != null) + ) + { + + this.responseBox.getChildren ().add (QuollLabel.builder () + .label (editors,messages,newprojectresponse,labels,extra) + .styleClassName (StyleClassNames.SUBTITLE) + .build ()); + + HBox editorInfo = new HBox (); + + editorInfo.getStyleClass ().add (StyleClassNames.EDITORINFO); + this.responseBox.getChildren ().add (editorInfo); + + if (this.message.getEditorAvatar () != null) + { + + ImageView iv = UIUtils.getImageView (this.message.getEditorAvatar ()); + editorInfo.getChildren ().add (iv); + iv.getStyleClass ().add (StyleClassNames.IMAGE); + + } + + if (this.message.getEditorName () != null) + { + + editorInfo.getChildren ().add (QuollLabel.builder () + .styleClassName (StyleClassNames.NAME) + .label (new SimpleStringProperty (this.message.getEditorName ())) + .build ()); + + } + + } + + } + + QuollButton ok = QuollButton.builder () + .label (editors,messages,newprojectresponse,received,undealtwith,buttons,confirm) + .onAction (ev -> + { + + try + { + + if (this.message.isAccepted ()) + { + + ed.setEditorStatus (EditorEditor.EditorStatus.current); + + if (this.message.getEditorName () != null) + { + + ed.setName (this.message.getEditorName ()); + + } + + if (this.message.getEditorAvatar () != null) + { + + ed.setAvatar (this.message.getEditorAvatar ()); + + } + + EditorsEnvironment.updateEditor (ed); + + fpe.setStatusMessage (Arrays.asList (editors,messages,newprojectresponse,received,editorstatus,accepted), + //"Accepted {project}: %s", + Arrays.asList (Environment.formatDate (this.message.getWhen ()))); + fpe.setEditorFrom (this.message.getWhen ()); + fpe.setCurrent (true); + fpe.setStatus (ProjectEditor.Status.accepted); + + EditorsEnvironment.updateProjectEditor (fpe); + + } else { + + ed.setEditorStatus (EditorEditor.EditorStatus.rejected); + + EditorsEnvironment.updateEditor (ed); + + if (fpe != null) + { + + try + { + + EditorsEnvironment.removeProjectEditor (fpe); + + } catch (Exception e) { + + Environment.logError ("Unable to remove project editor: " + + fpe, + e); + + } + + } + + } + + this.message.setDealtWith (true); + + EditorsEnvironment.updateMessage (this.message); + + this.responseBox.setVisible (false); + + } catch (Exception e) { + + Environment.logError ("Unable to update editor: " + + ed, + e); + + ComponentUtils.showErrorMessage (this.viewer, + getUILanguageStringProperty (editors,editor,edit,actionerror)); + //"Unable to update {editor}, please contact Quoll Writer support for assistance."); + + return; + + } + + }) + .build (); + + QuollButtonBar bb = QuollButtonBar.builder () + .button (ok) + .build (); + + this.responseBox.getChildren ().add (bb); + + return; + + } + + boolean accepted = this.message.isAccepted (); + //String resMessage = this.message.getResponseMessage (); + + StringProperty t = null; + + if (this.message.isSentByMe ()) + { + + //String text = "Accepted"; + + if (!accepted) + { + + t = getUILanguageStringProperty (editors,messages,newprojectresponse,sent,rejected,title); + + //text = "Rejected"; + + } else { + + t = getUILanguageStringProperty (editors,messages,newprojectresponse,sent,LanguageStrings.accepted,title); + + } + + //message = text + " {project}"; + + } else { + + //message = "{Project} accepted"; + + if (!accepted) + { + + t = getUILanguageStringProperty (editors,messages,newprojectresponse,received,rejected,title); + + //message = "{Project} rejected"; + + } else { + + t = getUILanguageStringProperty (editors,messages,newprojectresponse,received,LanguageStrings.accepted,title); + + } + + } + + Header h = Header.builder () + .title (t) + .iconClassName ((accepted ? StyleClassNames.ACCEPTED : StyleClassNames.REJECTED)) + .styleClassName (StyleClassNames.HEADER) + .build (); + + this.getChildren ().add (h); + + this.getChildren ().add (this.getResponseDetails ()); + + if ((this.message.isSentByMe ()) + && + (proj != null) + ) + { + + QuollHyperlink viewProj = QuollHyperlink.builder () + .label (editors,messages,newprojectresponse,sent,labels,clicktoview) + .styleClassName (StyleClassNames.VIEW) + .onAction (ev -> + { + + ProjectInfo proj2 = null; + + try + { + + proj2 = Environment.getProjectById (this.message.getForProjectId (), + Project.EDITOR_PROJECT_TYPE); + + } catch (Exception e) { + + Environment.logError ("Unable to get project: " + + this.message.getForProjectId (), + e); + + ComponentUtils.showErrorMessage (Environment.getFocusedViewer (), + getUILanguageStringProperty (Arrays.asList (project,actions,openproject,openerrors,general), + this.message.getForProjectId (), + getUILanguageStringProperty (project,actions,openproject,openerrors,unspecified))); + //"Unable to open {project}, please contact Quoll Writer support for assistance."); + + return; + + } + + try + { + + Environment.openProject (proj2); + + } catch (Exception e) { + + Environment.logError ("Unable to get project: " + + this.message.getForProjectId (), + e); + + ComponentUtils.showErrorMessage (Environment.getFocusedViewer (), + getUILanguageStringProperty (Arrays.asList (project,actions,openproject,openerrors,general), + this.message.getForProjectId (), + getUILanguageStringProperty (project,actions,openproject,openerrors,unspecified))); + //"Unable to open {project}, please contact Quoll Writer support for assistance."); + + return; + + } + + }) + .build (); + + // TODO Is this needed? + //this.getChildren ().add (viewProj); + + } + + if ((!this.message.isSentByMe ()) + && + (!this.message.isDealtWith ()) + ) + { + + VBox b = new VBox (); + b.managedProperty ().bind (b.visibleProperty ()); + + QuollButton ok = QuollButton.builder () + .label (editors,messages,newprojectresponse,received,undealtwith,buttons,confirm) + .onAction (ev -> + { + + try + { + + if (this.message.isAccepted ()) + { + + fpe.setStatus (ProjectEditor.Status.accepted); + + fpe.setEditorFrom (this.message.getWhen ()); + fpe.setCurrent (true); + fpe.setStatusMessage (Arrays.asList (editors,messages,newprojectresponse,received,editorstatus,LanguageStrings.accepted), + //"Accepted {project}: %s", + Arrays.asList (Environment.formatDate (this.message.getWhen ()))); + + EditorsEnvironment.updateProjectEditor (fpe); + + } else { + + fpe.setCurrent (false); + fpe.setStatusMessage (Arrays.asList (editors,messages,newprojectresponse,received,editorstatus,rejected), + //"Rejected {project}: %s", + Arrays.asList (Environment.formatDate (this.message.getWhen ()))); + + EditorsEnvironment.removeProjectEditor (fpe); + + } + + this.message.setDealtWith (true); + + EditorsEnvironment.updateMessage (this.message); + + b.setVisible (false); + + } catch (Exception e) { + + Environment.logError ("Unable to update message: " + + this.message, + e); + + ComponentUtils.showErrorMessage (this.viewer, + getUILanguageStringProperty (editors,messages,update,actionerror)); + //"Unable to update message, please contact Quoll Writer support for assistance."); + + return; + + } + + }) + .build (); + + QuollButtonBar bb = QuollButtonBar.builder () + .button (ok) + .build (); + + b.getChildren ().add (bb); + + this.getChildren ().add (b); + + } + + } + + public boolean isAutoDealtWith () + { + + return false; + + } + + private Node getResponseDetails () + { + + final NewProjectResponseMessageBox _this = this; + + ProjectInfo proj = null; + + try + { + + proj = Environment.getProjectById (this.message.getForProjectId (), + (this.message.isSentByMe () ? Project.EDITOR_PROJECT_TYPE : Project.NORMAL_PROJECT_TYPE)); + + } catch (Exception e) { + + Environment.logError ("Unable to get project: " + + this.message.getForProjectId (), + e); + + } + + Node itemVal = null; + + if (proj != null) + { + + itemVal = QuollHyperlink.builder () + .label (proj.nameProperty ()) + .tooltip (project,actions,openproject,tooltips,general) + .styleClassName (StyleClassNames.VIEWPROJECT) + .onAction (ev -> + { + + ProjectInfo proj2 = null; + + try + { + + proj2 = Environment.getProjectById (_this.message.getForProjectId (), + (_this.message.isSentByMe () ? Project.EDITOR_PROJECT_TYPE : Project.NORMAL_PROJECT_TYPE)); + + } catch (Exception e) { + + Environment.logError ("Unable to get project: " + + _this.message.getForProjectId (), + e); + + } + + if (proj2 != null) + { + + try + { + + Environment.openProject (proj2); + + } catch (Exception e) { + + Environment.logError ("Unable to open project: " + + proj2, + e); + + } + + } + + }) + .build (); + + } else { + + NewProjectMessage m = (NewProjectMessage) this.message.getEditor ().getMessage (NewProjectMessage.MESSAGE_TYPE, + this.message.getForProjectId ()); + + if (m != null) + { + + itemVal = QuollLabel.builder () + .label (new SimpleStringProperty (m.getForProjectName ())) + .build (); + + } + + } + + Form.Builder fb = Form.builder () + .layoutType (Form.LayoutType.column) + .styleClassName (StyleClassNames.RESPONSE); + + fb.item (getUILanguageStringProperty (editors,messages,newprojectresponse,labels,project), + itemVal); + + String resMessage = this.message.getResponseMessage (); + + if (resMessage != null) + { + + fb.item (getUILanguageStringProperty (editors,messages,newprojectresponse,labels,LanguageStrings.message), + QuollTextView.builder () + .text (new SimpleStringProperty (resMessage)) + .build ()); + + } + + return fb.build (); + + } + +} diff --git a/src/main/java/com/quollwriter/editors/ui/ProjectCommentsChaptersSidebarItem.java b/src/main/java/com/quollwriter/editors/ui/ProjectCommentsChaptersSidebarItem.java new file mode 100644 index 00000000..0bf3aae2 --- /dev/null +++ b/src/main/java/com/quollwriter/editors/ui/ProjectCommentsChaptersSidebarItem.java @@ -0,0 +1,480 @@ +package com.quollwriter.editors.ui; + +import java.util.*; +import java.util.function.*; + +import javafx.beans.property.*; +import javafx.scene.control.*; +import javafx.scene.*; + +import com.quollwriter.data.*; +import com.quollwriter.*; +import com.quollwriter.ui.fx.components.*; +import com.quollwriter.ui.fx.sidebars.*; +import com.quollwriter.ui.fx.viewers.*; +import com.quollwriter.ui.fx.*; +import com.quollwriter.ui.fx.panels.*; + +import static com.quollwriter.LanguageStrings.*; +import static com.quollwriter.uistrings.UILanguageStringsManager.getUILanguageStringProperty; + +// TODO: Make abstract ProjectSentReceivedChaptersAccordionItem, maybe move into ProjectSentReceivedSideBar. +public class ProjectCommentsChaptersSidebarItem extends ProjectObjectsSidebarItem +{ + + private QuollTreeView tree = null; + private IntegerProperty countProp = null; + private StringProperty title = null; + + public ProjectCommentsChaptersSidebarItem (ProjectSentReceivedViewer pv, + StringProperty title, + IPropertyBinder binder) + { + + super (pv, + binder); + + this.title = title; + this.countProp = new SimpleIntegerProperty (0); + + this.tree = NamedObjectTree.builder () + .project (pv.getProject ()) + .root (this.createTree ()) + .withViewer (this.viewer) + .labelProvider (treeItem -> + { + + NamedObject n = treeItem.getValue (); + + if (n instanceof Project) + { + + return new Label (); + + } + + QuollLabel l = QuollLabel.builder () + .styleClassName (n.getObjectType ()) + .build (); + + if (n instanceof Note) + { + + Note _n = (Note) n; + + l.setIconClassName (StyleClassNames.COMMENT); + l.getStyleClass ().add (StyleClassNames.COMMENT); + l.textProperty ().bind (n.nameProperty ()); + l.pseudoClassStateChanged (StyleClassNames.DEALTWITH_PSEUDO_CLASS, _n.isDealtWith ()); + + _n.dealtWithProperty ().addListener ((pr, oldv, newv) -> + { + + l.pseudoClassStateChanged (StyleClassNames.DEALTWITH_PSEUDO_CLASS, newv != null); + + }); + + } + +/* + l.setOnMouseClicked (ev -> + { + + if (ev.getButton () != MouseButton.PRIMARY) + { + + return; + + } + + l.requestFocus (); + + this.viewer.viewObject (n); + + }); +*/ + List prefix = Arrays.asList (project,sidebar,chapters,treepopupmenu,items); + + if (n instanceof Chapter) + { + + Chapter c = (Chapter) n; + + l.textProperty ().unbind (); + + String v = "%1$s (%2$s)"; + + l.setText (String.format (v, + c.getName (), + Environment.formatNumber (c.getNotes ().size ()))); + + } + + return l; + + }) + .contextMenuItemSupplier (obj -> + { + + Set its = new LinkedHashSet<> (); + + List prefix = Arrays.asList (editors,projectcomments,sidebar,comments,treepopupmenu); + + if (obj instanceof Note) + { + + Note n = (Note) obj; + + // Is this a project we have sent? + if (!this.viewer.getMessage ().isSentByMe ()) + { + + its.add (QuollMenuItem.builder () + .label (getUILanguageStringProperty (Utils.newList (prefix,comment,items,(n.isDealtWith () ? undealtwith : dealtwith)))) + .iconName (n.isDealtWith () ? StyleClassNames.DEALTWITH : StyleClassNames.UNDEALTWITH) + .onAction (ev -> + { + + n.setDealtWith (n.isDealtWith () ? null : new Date ()); + + }) + .build ()); + + } + + its.add (QuollMenuItem.builder () + .label (getUILanguageStringProperty (Utils.newList (prefix,comment,items,view))) + .iconName (StyleClassNames.VIEW) + .onAction (ev -> + { + + this.viewer.viewObject (n); + + }) + .build ()); + + } + + if (obj instanceof Chapter) + { + + Chapter c = (Chapter) obj; + + String chapterObjTypeName = Environment.getObjectTypeName (c).getValue (); + + // Is this a project we have sent? + if (!this.viewer.getMessage ().isSentByMe ()) + { + + int nc = 0; + + final Set notes = c.getNotes (); + + for (Note n : notes) + { + + if (n.isDealtWith ()) + { + + nc++; + + } + + } + + if (nc > 0) + { + + its.add (QuollMenuItem.builder () + .label (getUILanguageStringProperty (Utils.newList (prefix,Chapter.OBJECT_TYPE,items,undealtwith))) + .iconName (StyleClassNames.UNDEALTWITH) + .onAction (ev -> + { + + for (Note n : notes) + { + + n.setDealtWith (null); + + } + + }) + .build ()); + + } + + if (nc != notes.size ()) + { + + its.add (QuollMenuItem.builder () + .label (getUILanguageStringProperty (Utils.newList (prefix,Chapter.OBJECT_TYPE,items,dealtwith))) + .iconName (StyleClassNames.DEALTWITH) + .onAction (ev -> + { + + Date d = new Date (); + + for (Note n : notes) + { + + n.setDealtWith (d); + + } + + }) + .build ()); + + } + + } + + its.add (QuollMenuItem.builder () + .label (getUILanguageStringProperty (Utils.newList (prefix,Chapter.OBJECT_TYPE,items,view))) + .iconName (StyleClassNames.EDIT) + .onAction (ev -> + { + + this.viewer.editChapter (c, + null); + + }) + .build ()); + + its.add (QuollMenuItem.builder () + .label (getUILanguageStringProperty (Utils.newList (prefix,Chapter.OBJECT_TYPE,items,close))) + .iconName (StyleClassNames.CLOSE) + .onAction (ev -> + { + + this.viewer.closePanel (c, + null); + + }) + .build ()); + + } + + return its; + + }) + .viewObjectOnClick (true) + .build (); + + this.selectItem (); + + this.addChangeListener (this.viewer.currentPanelProperty (), + (pr, oldv, newv) -> + { + + this.selectItem (); + + }); + + } + + private void selectItem () + { + + this.tree.select (null); + this.tree.requestLayout (); + + Panel p = this.viewer.getCurrentPanel (); + + if (p == null) + { + + return; + + } + + if (p != null) + { + + if (p.getContent () instanceof NamedObjectPanelContent) + { + + NamedObjectPanelContent nc = (NamedObjectPanelContent) p.getContent (); + + if (nc.getObject () instanceof Chapter) + { + + this.tree.select ((Chapter) nc.getObject ()); + this.tree.requestLayout (); + + return; + + } + + } + + } + + } + + private TreeItem createTree () + { + + List objs = new ArrayList<> (this.viewer.getProject ().getBooks ().get (0).getChapters ()); + + TreeItem root = new TreeItem<> (this.viewer.getProject ()); + + for (Chapter c : objs) + { + + TreeItem cit = new TreeItem<> (c); + root.getChildren ().add (cit); + cit.setExpanded (true); + + c.getNotes ().stream () + .forEach (n -> cit.getChildren ().add (new TreeItem<> (n))); + + } + + this.countProp.setValue (objs.size ()); + + return root; + + } + + @Override + public Node getContent () + { + + return this.tree; + + } + + @Override + public String getId () + { + + return "projectcommentschapters"; + + } + + @Override + public StringProperty getTitle () + { + + return this.title; + + } + + @Override + public IntegerProperty getItemCount () + { + + return this.countProp; + + } + + @Override + public Supplier> getHeaderContextMenuItemSupplier () + { + + return () -> + { + + return new HashSet<> (); + + }; + + } + + @Override + public List getStyleClassNames () + { + + return Arrays.asList (StyleClassNames.COMMENTS); + + } + + @Override + public BooleanProperty showItemCountOnHeader () + { + + return new SimpleBooleanProperty (true); + + } + + @Override + public boolean canImport (NamedObject o) + { + + return false; + + } + + @Override + public void importObject (NamedObject o) + { + + // Do nothing. + + } + +/* +TODO + protected void handleViewObject (TreePath tp, + Object obj) + { + + if (obj instanceof Chapter) + { + + Chapter c = (Chapter) obj; + + if (c.getNotes ().size () > 0) + { + + Note n = c.getNotes ().iterator ().next (); + + this.viewer.viewObject (n); + + this.tree.expandPath (UIUtils.getTreePathForUserObject ((DefaultMutableTreeNode) this.tree.getModel ().getRoot (), + c)); + + return; + + } + + } + + this.viewer.viewObject ((DataObject) obj); + + } +*/ +/* + @Override + public int getViewObjectClickCount (Object d) + { + + return 1; + + } + + @Override + public boolean isAllowObjectPreview () + { + + return true; + + } + + @Override + public boolean isTreeEditable () + { + + return false; + + } + + @Override + public boolean isDragEnabled () + { + + return false; + + } +*/ +} diff --git a/src/main/java/com/quollwriter/editors/ui/ProjectCommentsMessageBox.java b/src/main/java/com/quollwriter/editors/ui/ProjectCommentsMessageBox.java new file mode 100644 index 00000000..ac63b401 --- /dev/null +++ b/src/main/java/com/quollwriter/editors/ui/ProjectCommentsMessageBox.java @@ -0,0 +1,240 @@ +package com.quollwriter.editors.ui; + +import java.util.*; +import javafx.scene.*; +import javafx.beans.property.*; + +import com.quollwriter.*; +import com.quollwriter.text.*; +import com.quollwriter.data.*; +import com.quollwriter.ui.components.ImagePanel; +import com.quollwriter.editors.messages.*; +import com.quollwriter.editors.*; +import com.quollwriter.data.editors.*; +import com.quollwriter.ui.fx.viewers.*; +import com.quollwriter.ui.fx.components.*; +import com.quollwriter.ui.fx.*; + +import static com.quollwriter.LanguageStrings.*; +import static com.quollwriter.uistrings.UILanguageStringsManager.getUILanguageStringProperty; + +//@MessageBoxFor(Message=ProjectCommentsMessage.class) +public class ProjectCommentsMessageBox extends MessageBox +{ + + private AbstractProjectViewer commentsViewer = null; + + public ProjectCommentsMessageBox (ProjectCommentsMessage mess, + AbstractViewer viewer) + { + + super (mess, + viewer); + + this.getStyleClass ().add (StyleClassNames.PROJECTCOMMENTS); + + final ProjectCommentsMessageBox _this = this; + + ProjectInfo proj = null; + + try + { + + proj = Environment.getProjectById (this.message.getForProjectId (), + (this.message.isSentByMe () ? Project.EDITOR_PROJECT_TYPE : Project.NORMAL_PROJECT_TYPE)); + + } catch (Exception e) { + + Environment.logError ("Unable to get project info for project with id: " + + this.message.getForProjectId (), + e); + + } + + this.getChildren ().add (Header.builder () + .title (getUILanguageStringProperty (Arrays.asList (editors,messages,projectcomments,(this.message.isSentByMe () ? sent : received),title), + this.message.getComments ().size ())) + .styleClassName (StyleClassNames.SUBTITLE) + .iconClassName (StyleClassNames.COMMENT) + .build ()); + + // Show + // * Sent/Received + // * Version (optional) + // * Notes (optional) + // * View comments + + ProjectVersion pv = this.message.getProjectVersion (); + String genComm = this.message.getGeneralComment (); + + String verName = pv.getName (); + + EditorEditor ed = this.message.getEditor (); + + // We are wimping out here + String projVerName = this.message.getProjectVersion ().getName (); + + String projVerId = this.message.getProjectVersion ().getId (); + + Form.Builder fb = Form.builder () + .layoutType (Form.LayoutType.column); + + if (proj != null) + { + + fb.item (getUILanguageStringProperty (editors,messages,projectcomments,labels,project), + QuollHyperlink.builder () + .label (message.forProjectNameProperty ()) + .styleClassName (StyleClassNames.VIEWPROJECT) + .tooltip (editors,messages,projectcomments,labels,clicktoviewproject) + .onAction (ev -> + { + + ProjectInfo _proj = null; + + try + { + + _proj = Environment.getProjectById (_this.message.getForProjectId (), + (_this.message.isSentByMe () ? Project.EDITOR_PROJECT_TYPE : Project.NORMAL_PROJECT_TYPE)); + + } catch (Exception e) { + + Environment.logError ("Unable to get project info for project with id: " + + _this.message.getForProjectId (), + e); + + } + + if (_proj != null) + { + + try + { + + Environment.openProject (_proj); + + } catch (Exception e) { + + Environment.logError ("Unable to open project: " + + _proj, + e); + + } + + } + + }) + .build ()); + + } else { + + fb.item (getUILanguageStringProperty (editors,messages,projectcomments,labels,project), + QuollLabel.builder () + .label (message.forProjectNameProperty ()) + .build ()); + + } + + fb.item (getUILanguageStringProperty (editors,messages,projectcomments,labels,(this.message.isSentByMe () ? sent : received)), + QuollLabel.builder () + .label (new SimpleStringProperty (Environment.formatDateTime (this.message.getWhen ()))) + .build ()); + + if (verName != null) + { + + fb.item (getUILanguageStringProperty (editors,messages,projectcomments,labels,version), + QuollLabel.builder () + .label (this.message.getProjectVersion ().nameProperty ()) + .build ()); + + } + + if (genComm != null) + { + + TextIterator ti = new TextIterator (genComm); + + if (ti.getSentenceCount () > 1) + { + + genComm = ti.getFirstSentence ().getText (); + + } + + fb.item (getUILanguageStringProperty (editors,messages,projectcomments,labels,notes), + QuollTextView.builder () + .inViewer (this.viewer) + .text (new SimpleStringProperty (genComm)) + .build ()); + + } + + if (proj != null) + { + + fb.item (QuollHyperlink.builder () + .label (editors,messages,projectcomments,labels,clicktoviewcomments) + .styleClassName (StyleClassNames.VIEW) + .onAction (ev -> + { + + this.message.setDealtWith (true); + + try + { + + EditorsEnvironment.updateMessage (this.message); + + } catch (Exception e) { + + Environment.logError ("Unable to update message: " + + this.message, + e); + + } + + if (this.commentsViewer != null) + { + + this.commentsViewer.show (); + this.commentsViewer.toFront (); + + return; + + } + + EditorsUIUtils.showProjectComments (this.message, + this.viewer, + (commViewer) -> + { + + _this.commentsViewer = commViewer; + _this.commentsViewer.getViewer ().addEventHandler (Viewer.ViewerEvent.CLOSE_EVENT, + eev -> + { + + _this.commentsViewer = null; + + }); + + }); + + }) + .build ()); + + } + + this.getChildren ().add (fb.build ()); + + } + + public boolean isAutoDealtWith () + { + + return false; + + } + +} diff --git a/src/main/java/com/quollwriter/editors/ui/ProjectCommentsViewer.java b/src/main/java/com/quollwriter/editors/ui/ProjectCommentsViewer.java new file mode 100644 index 00000000..ae90f818 --- /dev/null +++ b/src/main/java/com/quollwriter/editors/ui/ProjectCommentsViewer.java @@ -0,0 +1,219 @@ +package com.quollwriter.editors.ui; + +import java.net.*; + +import java.security.*; + +import java.text.*; + +import java.util.*; +import java.util.function.*; + +import javafx.scene.*; +import javafx.beans.property.*; + +import com.quollwriter.*; + +import com.quollwriter.data.*; +import com.quollwriter.data.editors.*; + +import com.quollwriter.db.*; + +import com.quollwriter.events.*; +import com.quollwriter.data.comparators.*; +import com.quollwriter.text.*; +import com.quollwriter.editors.ui.sidebars.*; +import com.quollwriter.editors.ui.panels.*; +import com.quollwriter.editors.*; +import com.quollwriter.editors.messages.*; +import com.quollwriter.editors.ui.*; +import com.quollwriter.ui.fx.*; +import com.quollwriter.ui.fx.components.*; +import com.quollwriter.uistrings.UILanguageStringsManager; + +import static com.quollwriter.LanguageStrings.*; +import static com.quollwriter.uistrings.UILanguageStringsManager.getUILanguageStringProperty; + +public class ProjectCommentsViewer extends ProjectSentReceivedViewer +{ + + public ProjectCommentsViewer (Project proj, + ProjectCommentsMessage message) + { + + super (proj, + message); + + } + + /* + public void switchToProjectComments (ProjectCommentsMessage pcm) + { + + if (pcm == null) + { + + throw new IllegalArgumentException ("Expected a project comments message"); + + } + + this.message = pcm; + + this.initTitle (); + + ProjectSentReceivedSideBar sb = null; + + try + { + + sb = this.getSideBar (); + + sb.init (); + + } catch (Exception e) { + + Environment.logError ("Unable to init new editor project comments side bar", + e); + + UIUtils.showErrorMessage (this, + "Unable to show comments, please contact Quoll Writer support for assistance."); + + // Need to close and reopen the project? + + return; + + } + + this.sideBar = sb; + + this.setMainSideBar (this.sideBar); + + } + */ + + @Override + public Supplier> getTitleHeaderControlsSupplier () + { + + return () -> + { + + Set controls = new LinkedHashSet<> (); + + controls.add (QuollButton.builder () + .tooltip (editors,projectcomments,title,toolbar,buttons,openproject,tooltip) + .iconName (StyleClassNames.OPEN) + .buttonId ("open") + .onAction (ev -> + { + + ProjectInfo proj = null; + + try + { + + proj = Environment.getProjectById (this.message.getForProjectId (), + this.message.isSentByMe () ? Project.EDITOR_PROJECT_TYPE : Project.NORMAL_PROJECT_TYPE); + + } catch (Exception e) { + + Environment.logError ("Unable to get project for: " + + this.message.getForProjectId (), + e); + + ComponentUtils.showErrorMessage (this, + getUILanguageStringProperty (editors,LanguageStrings.project,actions,openproject,openerrors,general)); + //"Unable to show {comments}, please contact Quoll Writer support for assistance."); + + return; + + } + + try + { + + Environment.openProject (proj); + + } catch (Exception e) { + + Environment.logError ("Unable to get project for: " + + this.message.getForProjectId (), + e); + + ComponentUtils.showErrorMessage (this, + getUILanguageStringProperty (editors,LanguageStrings.project,actions,openproject,openerrors,general)); + //"Unable to show {comments}, please contact Quoll Writer support for assistance."); + + return; + + } + + }) + .build ()); + + controls.addAll (super.getTitleHeaderControlsSupplier ().get ()); + + return controls; + + }; + + } + + @Override + public void init (State s) + throws GeneralException + { + + super.init (s); + + this.setMainSideBar (new ProjectCommentsSideBar (this, + this.message)); + + // Show the first comment in the first chapter. + this.viewObject (this.project.getBook (0).getChapters ().get (0).getNotes ().iterator ().next ()); + + } + + @Override + public String getStyleClassName () + { + + return StyleClassNames.COMMENTS; + + } + + @Override + public StringProperty titleProperty () + { + + return UILanguageStringsManager.createStringPropertyWithBinding (() -> + { + + String verName = ""; + + if (this.getProject ().getProjectVersion () != null) + { + + verName = this.getProject ().getProjectVersion ().getName (); + + if (verName != null) + { + + verName = getUILanguageStringProperty (editors,projectcomments,(this.message.isSentByMe () ? sent : received),viewertitleversionwrapper, + //" (%s)", + verName).getValue (); + + } + + } + + return getUILanguageStringProperty (editors,projectcomments,(this.message.isSentByMe () ? sent : received),viewertitle, + //"{Comments} on%s: %s", + verName, + this.project.getName ()).getValue (); + + }); + + } + +} diff --git a/src/main/java/com/quollwriter/editors/ui/ProjectEditStopMessageBox.java b/src/main/java/com/quollwriter/editors/ui/ProjectEditStopMessageBox.java new file mode 100644 index 00000000..6518f0b2 --- /dev/null +++ b/src/main/java/com/quollwriter/editors/ui/ProjectEditStopMessageBox.java @@ -0,0 +1,256 @@ +package com.quollwriter.editors.ui; + +import java.util.*; +import javafx.beans.property.*; +import javafx.scene.layout.*; +import javafx.scene.control.*; +import javafx.scene.*; +import javafx.scene.image.*; + +import com.quollwriter.*; +import com.quollwriter.data.*; +import com.quollwriter.data.editors.*; +import com.quollwriter.editors.messages.*; +import com.quollwriter.editors.*; +import com.quollwriter.ui.fx.components.*; +import com.quollwriter.ui.fx.viewers.*; +import com.quollwriter.ui.fx.*; + +import static com.quollwriter.LanguageStrings.*; +import static com.quollwriter.uistrings.UILanguageStringsManager.getUILanguageStringProperty; + +//@MessageBoxFor(Message=ProjectEditStopMessage.class) +public class ProjectEditStopMessageBox extends MessageBox +{ + + private AbstractProjectViewer commentsViewer = null; + private VBox responseBox = null; + + public ProjectEditStopMessageBox (ProjectEditStopMessage mess, + AbstractViewer viewer) + { + + super (mess, + viewer); + + final ProjectEditStopMessageBox _this = this; + + this.getStyleClass ().add ("projecteditstopmessage"); + + StringProperty title = null; + //"Stopped editing {project}"; + + if (this.message.isSentByMe ()) + { + + title = getUILanguageStringProperty (editors,messages,projecteditstop,sent,LanguageStrings.title); + + } else { + + title = getUILanguageStringProperty (editors,messages,projecteditstop,received,LanguageStrings.title); + + } + + this.getChildren ().add (Header.builder () + .title (title) + .styleClassName (StyleClassNames.HEADER) + .iconClassName (StyleClassNames.STOPPED) + .build ()); + + Form.Builder fb = Form.builder (); + fb.layoutType (Form.LayoutType.column); + + String reason = this.message.getReason (); + + ProjectInfo proj = null; + + try + { + + proj = Environment.getProjectById (_this.message.getForProjectId (), + null); + + } catch (Exception e) { + + Environment.logError ("Unable to get project info for project with id: " + + _this.message.getForProjectId (), + e); + + } + + Node projVal = null; + + if (proj != null) + { + + projVal = QuollHyperlink.builder () + .label (new SimpleStringProperty (this.message.getForProjectName ())) + .tooltip (project,actions,openproject,tooltips,general) + .onAction (ev -> + { + + ProjectInfo proj2 = null; + + try + { + + proj2 = Environment.getProjectById (this.message.getForProjectId (), + null); + + } catch (Exception e) { + + Environment.logError ("Unable to get project info for project with id: " + + this.message.getForProjectId (), + e); + + } + + if (proj2 != null) + { + + try + { + + Environment.openProject (proj2); + + } catch (Exception e) { + + Environment.logError ("Unable to open project: " + + proj2, + e); + + } + + } + + }) + .build (); + + } else { + + projVal = QuollLabel.builder () + .label (new SimpleStringProperty (this.message.getForProjectName ())) + .build (); + + } + + fb.item (getUILanguageStringProperty (editors,messages,projecteditstop,labels,project), + projVal); + + if (reason != null) + { + + fb.item (getUILanguageStringProperty (editors,messages,projecteditstop,labels,project), + QuollTextView.builder () + .text (new SimpleStringProperty (reason)) + .build ()); + + } + + this.getChildren ().add (fb.build ()); + + if (!this.message.isDealtWith ()) + { + + // Show the response. + this.responseBox = new VBox (); + this.responseBox.managedProperty ().bind (this.responseBox.visibleProperty ()); + this.responseBox.getStyleClass ().add (StyleClassNames.RESPONSE); + + this.getChildren ().add (this.responseBox); + + this.responseBox.getChildren ().add (QuollTextView.builder () + .inViewer (viewer) + .text (getUILanguageStringProperty (Arrays.asList (editors,messages,projecteditstop,received,undealtwith,text), + this.message.getEditor ().getMainName (), + this.message.getForProjectName ())) + .build ()); + + final EditorEditor ed = this.message.getEditor (); + + QuollButton ok = QuollButton.builder () + .label (editors,messages,projecteditstop,received,undealtwith,buttons,confirm) + .onAction (ev -> + { + + try + { + + ProjectInfo p = Environment.getProjectById (this.message.getForProjectId (), + Project.NORMAL_PROJECT_TYPE); + + ProjectEditor pe = EditorsEnvironment.getProjectEditor (p, + ed); + + pe.setCurrent (false); + pe.setEditorTo (new Date ()); + pe.setStatusMessage (Arrays.asList (editors,messages,projecteditstop,editorstatus), + //"Stopped editing: %s", + Arrays.asList (Environment.formatDate (pe.getEditorTo ()))); + + EditorsEnvironment.updateProjectEditor (pe); + + this.message.setDealtWith (true); + + EditorsEnvironment.updateMessage (this.message); + + } catch (Exception e) { + + Environment.logError ("Unable to update editor: " + + ed, + e); + + ComponentUtils.showErrorMessage (this.viewer, + getUILanguageStringProperty (editors,editor,edit,actionerror)); + //"Unable to update {contact}, please contact Quoll Writer support for assistance."); + + return; + + } + + }) + .build (); + + QuollButtonBar bb = QuollButtonBar.builder () + .button (ok) + .build (); + + this.responseBox.getChildren ().add (bb); + + } + + this.binder.addChangeListener (this.message.dealtWithProperty (), + (pr, oldv, newv) -> + { + + this.responseBox.setVisible (!newv); + + }); + + } + + public boolean isAutoDealtWith () + { + + return false; + + } + + public void doUpdate () + { + + if (this.message.isDealtWith ()) + { + + if (this.responseBox != null) + { + + this.responseBox.setVisible (false); + + } + + } + + } + +} diff --git a/src/main/java/com/quollwriter/editors/ui/ProjectEditorsAccordionItem.java b/src/main/java/com/quollwriter/editors/ui/ProjectEditorsAccordionItem.java new file mode 100644 index 00000000..14b82965 --- /dev/null +++ b/src/main/java/com/quollwriter/editors/ui/ProjectEditorsAccordionItem.java @@ -0,0 +1,643 @@ +package com.quollwriter.editors.ui; + +import java.util.*; +import java.util.function.*; + +import javafx.beans.value.*; +import javafx.beans.property.*; +import javafx.scene.*; +import javafx.scene.layout.*; +import javafx.scene.control.*; +import javafx.collections.*; + +import com.quollwriter.data.DataObject; +import com.quollwriter.data.NamedObject; +import com.quollwriter.data.IPropertyBinder; +import com.quollwriter.data.editors.*; +import com.quollwriter.*; +import com.quollwriter.ui.fx.*; +import com.quollwriter.ui.fx.viewers.*; +import com.quollwriter.ui.fx.sidebars.*; +import com.quollwriter.ui.fx.components.*; +import com.quollwriter.events.*; +import com.quollwriter.editors.*; +import static com.quollwriter.uistrings.UILanguageStringsManager.getUILanguageStringProperty; + +import static com.quollwriter.LanguageStrings.*; + +public class ProjectEditorsAccordionItem extends ProjectObjectsSidebarItem +{ + + private VBox content = null; + private VBox currentEditors = null; + private VBox previousEditors = null; + private boolean showPreviousEditors = false; + private boolean inited = false; + private IntegerProperty countProp = new SimpleIntegerProperty (0); + private Map> listeners = new HashMap<> (); + + public ProjectEditorsAccordionItem (ProjectViewer pv, + IPropertyBinder binder) + { + + super (pv, + //"{Editors}", + binder); + + this.content = new VBox (); + + this.currentEditors = new VBox (); + + this.previousEditors = new VBox (); + this.previousEditors.managedProperty ().bind (this.previousEditors.visibleProperty ()); + this.previousEditors.setVisible (false); + + long currSize = pv.getProject ().getProjectEditors ().stream () + .filter (pe -> !pe.isPrevious ()) + .count (); + this.countProp.setValue (currSize); + + this.content.getChildren ().addAll (this.currentEditors, this.previousEditors); + + QuollTextView help = QuollTextView.builder () + .inViewer (pv) + .styleClassName (StyleClassNames.INFORMATION) + .text (getUILanguageStringProperty (project,sidebar,editors,text)) + .build (); + + help.prefWidthProperty ().bind (this.content.widthProperty ()); + help.setVisible (currSize > 0); + help.managedProperty ().bind (help.visibleProperty ()); + + this.currentEditors.getChildren ().add (help); + + this.previousEditors.getChildren ().add (QuollLabel.builder () + .styleClassName (StyleClassNames.SUBTITLE) + .label (project,sidebar,editors,previouseditors,title) + .build ()); + + for (ProjectEditor pe : pv.getProject ().getProjectEditors ()) + { + + this.addProjectEditor (pe); + + } + + binder.addSetChangeListener (pv.getProject ().getProjectEditors (), + ev -> + { + + UIUtils.runLater (() -> + { + + long _currSize = pv.getProject ().getProjectEditors ().stream () + .filter (pe -> !pe.isPrevious ()) + .count (); + this.countProp.setValue (_currSize); + help.setVisible (_currSize > 0); + + if (ev.wasRemoved ()) + { + + ProjectEditor pe = ev.getElementRemoved (); + + pe.currentProperty ().removeListener (this.listeners.get (pe)); + + for (Node n : this.previousEditors.getChildren ()) + { + + if (!(n instanceof EditorInfoBox)) + { + + continue; + + } + + EditorInfoBox ib = (EditorInfoBox) n; + + if (ib.getEditor ().equals (pe)) + { + + this.previousEditors.getChildren ().remove (ib); + + if (this.previousEditors.getChildren ().size () == 1) + { + + this.previousEditors.setVisible (false); + + } + + return; + + } + + } + + for (Node n : this.currentEditors.getChildren ()) + { + + if (!(n instanceof EditorInfoBox)) + { + + continue; + + } + + EditorInfoBox ib = (EditorInfoBox) n; + + if (ib.getEditor ().equals (pe)) + { + + this.currentEditors.getChildren ().remove (ib); + return; + + } + + } + + } + + if (ev.wasAdded ()) + { + + ProjectEditor pe = ev.getElementAdded (); + + this.addProjectEditor (pe); + + } + + }); + + }); + + } + + private void addProjectEditor (ProjectEditor pe) + { + + // Editor is new. + EditorInfoBox infBox = null; + + try + { + + infBox = this.getEditorBox (pe); + + } catch (Exception e) { + + Environment.logError ("Unable to get editor info box for project editor: " + + pe, + e); + + return; + + } + + ChangeListener currentList = (pr, oldv, newv) -> + { + + if (!oldv && newv) + { + + for (Node n : this.previousEditors.getChildren ()) + { + + if (!(n instanceof EditorInfoBox)) + { + + continue; + + } + + EditorInfoBox ib = (EditorInfoBox) n; + + if (ib.getEditor ().equals (pe)) + { + + this.previousEditors.getChildren ().remove (ib); + this.currentEditors.getChildren ().add (1, + ib); + + } + + } + + } + + if (oldv && !newv) + { +System.out.println ("CHANGED REMOVING"); + for (Node n : this.currentEditors.getChildren ()) + { + + if (!(n instanceof EditorInfoBox)) + { + + continue; + + } + + EditorInfoBox ib = (EditorInfoBox) n; + + if (ib.getEditor ().equals (pe)) + { + + this.currentEditors.getChildren ().remove (ib); + this.previousEditors.getChildren ().add (1, + ib); + + } + + } + + } + + }; + + pe.currentProperty ().addListener (currentList); + + this.listeners.put (pe, + currentList); + + if (pe.isPrevious ()) + { + + this.previousEditors.getChildren ().add (1, + infBox); + + } else { + + this.currentEditors.getChildren ().add (1, + infBox); + + } + + } + + @Override + public Node getContent () + { + + return this.content; + + } + + @Override + public IntegerProperty getItemCount () + { + + return this.countProp; + + } + + @Override + public Supplier> getHeaderContextMenuItemSupplier () + { + + ProjectViewer viewer = this.viewer; + ProjectEditorsAccordionItem _this = this; + + return () -> + { + + List prefix = Arrays.asList (project,sidebar,editors,headerpopupmenu,items); + + Set items = new LinkedHashSet<> (); + + if (EditorsEnvironment.getUserAccount () != null) + { + + items.add (QuollMenuItem.builder () + .label (getUILanguageStringProperty (Utils.newList (prefix,invite))) + //"Invite someone to edit this {project}", + .iconName (StyleClassNames.ADD) + .onAction (ev -> + { + + List eds = new ArrayList<> (EditorsEnvironment.getEditors ()); + + List projEds = null; + + try + { + + projEds = EditorsEnvironment.getProjectEditors (viewer.getProject ().getId ()); + + } catch (Exception e) { + + Environment.logError ("Unable to get project editors for project: " + + viewer.getProject ().getId (), + e); + + ComponentUtils.showErrorMessage (viewer, + getUILanguageStringProperty (project,sidebar,editors,sendinvite,actionerror)); + //"Unable to show contacts."); + + return; + + } + + for (ProjectEditor pe : projEds) + { + + eds.remove (pe.getEditor ()); + + } + + Iterator iter = eds.iterator (); + + while (iter.hasNext ()) + { + + EditorEditor ed = iter.next (); + + if (ed.isPending ()) + { + + iter.remove (); + + } + + } + + QuollHyperlink l = QuollHyperlink.builder () + .label (project,sidebar,editors,sendinvite,popup,labels,notinlist) + .styleClassName (StyleClassNames.EMAIL) + .onAction (eev -> + { + + EditorsUIUtils.showInviteEditor (viewer); + + }) + .build (); + + EditorsUIUtils.showContacts (FXCollections.observableList (eds), + getUILanguageStringProperty (project,sidebar,editors,sendinvite,popup,title), + viewer, + ed -> + { + + EditorsUIUtils.showSendProject (viewer, + ed, + null); + + }, + l); + + }) + .build ()); + + items.add (QuollMenuItem.builder () + .label (getUILanguageStringProperty (Utils.newList (prefix,vieweditors))) + .iconName (StyleClassNames.EDITORS) + .onAction (eev -> + { + + try + { + + viewer.viewEditors (); + + } catch (Exception e) { + + Environment.logError ("Unable to view all editors", + e); + + ComponentUtils.showErrorMessage (viewer, + getUILanguageStringProperty (editors,vieweditorserror)); + //"Unable to view all {contacts}"); + + } + + }) + .build ()); + + } + + long prevCount = 0; + + if (viewer.getProject ().getProjectEditors () != null) + { + + prevCount = viewer.getProject ().getProjectEditors ().stream () + .filter (pe -> pe.isPrevious ()) + .count (); + + } + + // Get all previous editors. + if (!this.showPreviousEditors) + { + + if (prevCount > 0) + { + + items.add (QuollMenuItem.builder () + .label (getUILanguageStringProperty (Utils.newList (prefix,previouseditors), + Environment.formatNumber (prevCount))) + .iconName (StyleClassNames.PREVIOUSEDITORS) + .onAction (eev -> + { + + this.showPreviousEditors = true; + this.showPreviousEditors (); + + }) + .build ()); + + } + + } else { + + if (prevCount > 0) + { + + items.add (QuollMenuItem.builder () + .label (getUILanguageStringProperty (Utils.newList (prefix,hidepreviouseditors))) + .iconName (StyleClassNames.HIDE) + .onAction (eev -> + { + + this.showPreviousEditors = false; + this.showPreviousEditors (); + + }) + .build ()); + + } + + } + + return items; + + }; + + } + + @Override + public List getStyleClassNames () + { + + return Arrays.asList (StyleClassNames.CONTACTS); + + } + + @Override + public BooleanProperty showItemCountOnHeader () + { + + return new SimpleBooleanProperty (true); + + } + + @Override + public boolean canImport (NamedObject o) + { + + return false; + + } + + @Override + public void importObject (NamedObject o) + { + + // Do nothing. + + } + + @Override + public StringProperty getTitle () + { + + return getUILanguageStringProperty (project,sidebar,editors,title); + + } + + @Override + public String getId () + { + + return ProjectEditor.OBJECT_TYPE; + + } + + private EditorInfoBox getEditorBox (ProjectEditor pe) + throws GeneralException + { + + return this.getEditorBox (pe.getEditor ()); + + } + + private EditorInfoBox getEditorBox (EditorEditor ed) + throws GeneralException + { + + EditorInfoBox b = new EditorInfoBox (ed, + this.viewer, + true, + this.getBinder ()); + + b.addFullPopupListener (); + + return b; + + } +/* +TODO? + public void XupdateItemCount () + { + + Set pes = this.viewer.getCurrentEditors (); + + String title = String.format ("%s (%s)", + this.getTitle (), + Environment.formatNumber (pes.size ())); + + // Set the title on the header directly. + this.header.setTitle (title); + + } + */ +/* +TODO? + @Override + public void setContentVisible (boolean v) + { + + Set cpes = this.getCurrentEditors (); + + Set ppes = this.getPreviousEditors (); + + this.currentEditors.setVisible (cpes.size () > 0); + this.previousEditors.setVisible ((this.showPreviousEditors && ppes.size () > 0)); + + super.setContentVisible (this.currentEditors.isVisible () || this.previousEditors.isVisible ()); + + this.updateItemCount (); + + } +*/ + private void showPreviousEditors () + { + + this.previousEditors.setVisible (this.showPreviousEditors); + + } +/* +TODO Remove? put check on header for register or handle better? + @Override + public void init () + { + + if (this.inited) + { + + return; + + } + + this.inited = true; + + super.init (); + + final ProjectEditorsAccordionItem _this = this; + + this.getHeader ().addMouseListener (new MouseEventHandler () + { + + @Override + public void handlePress (MouseEvent ev) + { + + // TODO: Make this nicer + if (!EditorsEnvironment.hasRegistered ()) + { + + if (EditorsEnvironment.isEditorsServiceAvailable ()) + { + + try + { + + EditorsUIUtils.showRegister (_this.viewer); + + } catch (Exception e) { + + Environment.logError ("Unable to show editors service register", + e); + + } + + } + + } + + } + + }); + + } +*/ +} diff --git a/src/main/java/com/quollwriter/editors/ui/ProjectSentReceivedViewer.java b/src/main/java/com/quollwriter/editors/ui/ProjectSentReceivedViewer.java new file mode 100644 index 00000000..7dfc74b6 --- /dev/null +++ b/src/main/java/com/quollwriter/editors/ui/ProjectSentReceivedViewer.java @@ -0,0 +1,371 @@ +package com.quollwriter.editors.ui; + +import java.net.*; + +import java.security.*; + +import java.text.*; + +import java.util.*; +import java.util.function.*; + +import javafx.beans.property.*; +import javafx.scene.*; +import javafx.scene.control.*; + +//import com.gentlyweb.properties.*; + +import com.quollwriter.*; + +import com.quollwriter.data.*; +import com.quollwriter.data.editors.*; + +import com.quollwriter.db.*; + +import com.quollwriter.events.*; +import com.quollwriter.data.comparators.*; +import com.quollwriter.text.*; +import com.quollwriter.editors.ui.sidebars.*; +import com.quollwriter.editors.ui.panels.*; +import com.quollwriter.ui.fx.viewers.*; +import com.quollwriter.ui.fx.*; +import com.quollwriter.ui.fx.panels.*; +import com.quollwriter.ui.fx.components.*; +import com.quollwriter.uistrings.UILanguageStringsManager; +import com.quollwriter.editors.*; +import com.quollwriter.editors.messages.*; +import com.quollwriter.editors.ui.*; + +import static com.quollwriter.LanguageStrings.*; +import static com.quollwriter.uistrings.UILanguageStringsManager.getUILanguageStringProperty; + +public abstract class ProjectSentReceivedViewer extends AbstractProjectViewer +{ + + private EditorEditor editor = null; + protected E message = null; + + public ProjectSentReceivedViewer (Project proj, + E message) + { + + this.project = proj; + this.message = message; + this.getStyleClass ().add ("projectsentreceived"); + + // TODO Set icon of header. + + } + + @Override + public boolean addToAchievementsManager () + { + + return false; + + } + + @Override + public void init (State s) + throws GeneralException + { + + super.init (s); + + this.viewObject (this.project.getBook (0).getChapters ().get (0)); + + } + + @Override + public void close (Runnable afterClose) + { + + this.project = null; + super.close (afterClose); + + } + + public E getMessage () + { + + return this.message; + + } + + @Override + public Supplier> getTitleHeaderControlsSupplier () + { + + return () -> + { + + Set controls = new LinkedHashSet<> (); + + controls.add (this.getTitleHeaderControl (HeaderControl.contacts)); + controls.add (this.getTitleHeaderControl (HeaderControl.find)); + controls.add (this.getTitleHeaderControl (HeaderControl.close)); + + return controls; + + }; + + } + + @Override + public void handleNewProject () + { + + throw new UnsupportedOperationException ("Not supported for viewing project comments."); + + } + + @Override + public StringProperty titleProperty () + { + + return UILanguageStringsManager.createStringPropertyWithBinding (() -> + { + + return getUILanguageStringProperty (Arrays.asList (editors,projectsent,viewertitle), + this.project.getName ()).getValue (); + + }, + this.project.nameProperty ()); + + } + + @Override + public void handleOpenProject () + { + + throw new UnsupportedOperationException ("Not supported for viewing sent/received information."); + + } + + @Override + public void saveProject () + { + + // Do nothing. + + } +/* + public ChapterCommentsPanel getEditorForChapter (Chapter c) + { + + for (QuollPanel qp : this.getAllQuollPanelsForObject (c)) + { + + if (qp instanceof FullScreenQuollPanel) + { + + qp = ((FullScreenQuollPanel) qp).getChild (); + + } + + if (qp instanceof ChapterCommentsPanel) + { + + return (ChapterCommentsPanel) qp; + + } + + } + + return null; + + } +*/ + /** + * This is a top-level action so it can handle showing the user a message, it returns a boolean to indicate + * whether the chapter has been opened for editing. + */ + public void editChapter (final Chapter c, + final Runnable doAfterView) + { + + NamedObjectPanelContent p = this.getPanelForObject (c); + + if (p != null) + { + + this.showPanel (p.getPanel ().getPanelId ()); + + UIUtils.runLater (doAfterView); + + return; + + } + + try + { + + p = new ChapterCommentsPanel (this, + c); + + this.addPanel (p); + + this.editChapter (c, + doAfterView); + + } catch (Exception e) { + + Environment.logError ("Unable to edit chapter: " + + c, + e); + + ComponentUtils.showErrorMessage (this, + getUILanguageStringProperty (editors,projectsent,actions,viewchapter,actionerror)); + + } + + } + + @Override + public void viewObject (final DataObject d, + final Runnable doAfterView) + { + + if (d instanceof Note) + { + + final Note n = (Note) d; + + this.viewObject (n.getChapter (), + () -> + { + + ChapterCommentsPanel pc = (ChapterCommentsPanel) this.getEditorForChapter (n.getChapter ()); + + if (pc.isReadyForUse ()) + { + + UIUtils.forceRunLater (() -> + { + + pc.showItem (n, + false); + + }); + + } else { + + pc.readyForUseProperty ().addListener ((pr, oldv, nev) -> + { + + UIUtils.forceRunLater (() -> + { + + pc.showItem (n, + false); + + }); + + }); + + } + + }); + + return; + + } + + if (d instanceof Chapter) + { + + Chapter c = (Chapter) d; + + this.editChapter (c, + doAfterView); + + return; + + } + + // Record the error, then ignore. + Environment.logError ("Unable to open object: " + d); + + } + + public Set findText (String t) + { + + Set res = new LinkedHashSet<> (); + + FindResultsBox chres = this.findTextInChapters (t); + + if (chres != null) + { + + res.add (chres); + + } + + Set notes = this.project.getNotesContaining (t); + + if (notes.size () > 0) + { + + res.add (new NamedObjectFindResultsBox (getUILanguageStringProperty (objectnames,plural,Note.OBJECT_TYPE), + StyleClassNames.COMMENTS, + this, + notes)); + + } + + return res; + + } + + @Override + public Supplier> getSettingsMenuSupplier () + { + + final ProjectSentReceivedViewer _this = this; + + return () -> + { + + Set items = new LinkedHashSet<> (); + + List prefix = Arrays.asList (editors,LanguageStrings.project,settingsmenu,LanguageStrings.items); + + items.add (QuollMenuItem.builder () + .label (Utils.newList (prefix,openproject)) + .iconName (StyleClassNames.OPEN) + .onAction (ev -> + { + + _this.runCommand (CommandId.openproject); + + }) + .build ()); + + items.add (QuollMenuItem.builder () + .label (Utils.newList (prefix,closeproject)) + .iconName (StyleClassNames.CLOSE) + .onAction (ev -> + { + + _this.runCommand (CommandId.closeproject); + + }) + .build ()); + + return items; + + }; + + } + + @Override + public void createActionLogEntry (NamedObject n, + String m) + { + + // Do nothing. + + } + +} diff --git a/src/main/java/com/quollwriter/editors/ui/SendProjectWizard.java b/src/main/java/com/quollwriter/editors/ui/SendProjectWizard.java new file mode 100644 index 00000000..1c210d09 --- /dev/null +++ b/src/main/java/com/quollwriter/editors/ui/SendProjectWizard.java @@ -0,0 +1,1233 @@ +package com.quollwriter.editors.ui; + +import java.awt.Component; +import java.awt.Dimension; + +import java.awt.event.*; + +import java.util.List; +import java.util.Set; +import java.util.LinkedHashSet; +import java.util.Date; +import java.util.Calendar; +import java.util.GregorianCalendar; + +import javax.swing.*; +import javax.swing.tree.*; + +import com.toedter.calendar.*; + +import com.jgoodies.forms.builder.*; +import com.jgoodies.forms.factories.*; +import com.jgoodies.forms.layout.*; + +import com.quollwriter.*; +import com.quollwriter.data.editors.*; +import com.quollwriter.data.*; +import com.quollwriter.ui.*; +import com.quollwriter.ui.panels.*; +import com.quollwriter.editors.*; +import com.quollwriter.editors.messages.*; + +public class SendProjectWizard extends Wizard +{ + + private EditorEditor editor = null; + private ActionListener onSend = null; + private ProjectVersion projectVersion = null; + + private TextArea notes = null; + private JDateChooser date = null; + private JLabel error = null; + private JTree chapterTree = null; + private Box sendBox = null; + private boolean firstSend = false; + private JTextField newVerName = null; + private JLabel newVerNameError = null; + private JRadioButton createVersion = null; + private JRadioButton selectDetails = null; + + public SendProjectWizard (AbstractProjectViewer viewer, + EditorEditor ed, + ActionListener onSend) + throws Exception + { + + super (viewer); + this.editor = ed; + this.onSend = onSend; + + final SendProjectWizard _this = this; + + this.firstSend = !EditorsEnvironment.hasUserSentAProjectBefore (); + this.firstSend = true; + + this.newVerNameError = UIUtils.createErrorLabel ("Please enter a name for the version."); + + this.newVerName = new JTextField (); + + this.newVerName.addKeyListener (new KeyAdapter () + { + + public void keyPressed (KeyEvent ev) + { + + _this.enableButton ("next", + false); + + if (_this.newVerName.getText ().trim ().length () > 0) + { + + _this.enableButton ("next", + true); + + } + + } + + }); + } + + public String getFirstHelpText () + { + + return String.format ("Send your {project} to %s.", + this.editor.getMainName ()); + + } + + public int getContentPreferredHeight () + { + + return 350; + + } + + public boolean handleFinish () + { + + Set chapters = new LinkedHashSet (); + + DefaultMutableTreeNode root = (DefaultMutableTreeNode) this.chapterTree.getModel ().getRoot (); + + UIUtils.getSelectedObjects (root, + chapters); + + String err = null; + + if (chapters.size () == 0) + { + + // Show the error. + err = "Please select at least 1 {chapter}."; + + } + + for (Chapter c : chapters) + { + + AbstractEditorPanel qp = this.viewer.getEditorForChapter (c); + + if (qp != null) + { + + if (qp.hasUnsavedChanges ()) + { + + err = "One of the selected {chapters} has unsaved changes, please save your work before sending the {project}."; + + break; + + } + + } + + } + + if (this.notes.getText ().trim ().length () > 5000) + { + + err = "Notes can be a maximum of 5000 characters."; + + } + + if (err != null) + { + + this.error.setText (err); + this.error.setVisible (true); + + UIUtils.resizeParent (this); + + return false; + + } + + this.error.setVisible (false); + + // Show the sending. + this.sendBox.setVisible (true); + + UIUtils.resizeParent (this); + + String n = this.notes.getText ().trim (); + + ProjectVersion pv = new ProjectVersion (); + pv.setName (this.newVerName.getText ().trim ()); + pv.setDueDate (this.date.getDate ()); + pv.setDescription (new StringWithMarkup (n)); + + // Need to snapshot the chapters. + Set nchapters = null; + + try + { + + nchapters = this.viewer.snapshotChapters (chapters, + pv); + + } catch (Exception e) { + + Environment.logError ("Unable to snapshot chapters: " + + chapters, + e); + + UIUtils.showErrorMessage (this.viewer, + "Unable to send new project to {editor}, please contact Quoll Writer support for assistance."); + + return false; + + } + + NewProjectMessage mess = new NewProjectMessage (this.viewer.getProject (), + nchapters, + pv, + this.editor, + this.editor.getEditorStatus () == EditorEditor.EditorStatus.pending ? EditorsEnvironment.getUserAccount () : null); + + // Since we are sending the message we have dealt with it. + mess.setDealtWith (true); + + final SendProjectWizard _this = this; + + EditorsEnvironment.sendMessageToEditor (mess, + // On send. + () -> + { + + ProjectEditor pe = new ProjectEditor (_this.viewer.getProject (), + _this.editor); + + pe.setStatus (ProjectEditor.Status.invited); + //pe.setStatusMessage ("{Project} sent: " + Environment.formatDate (new Date ())); + + // Add the editor to the list of editors + // for the project. A little dangerous to do it here + // since it's not in the same transaction as the message. + // TODO: Maybe have the message have a "side-effect" or "after save" + // TODO: that will add the editor to the project in the same transaction. + try + { + + EditorsEnvironment.addProjectEditor (pe); + + _this.viewer.getProject ().addProjectEditor (pe); + + } catch (Exception e) { + + // Goddamn it! + // Nothing worse than having to show an error and success at the same time. + Environment.logError ("Unable to add editor: " + + _this.editor + + " to project: " + + _this.viewer.getProject (), + e); + + UIUtils.showErrorMessage (_this.viewer, + "Unable to add {editor} " + _this.editor.getMainName () + " to the {project}. Please contact Quoll Writer support for assistance."); + + } + + UIUtils.showMessage ((PopupsSupported) _this.viewer, + "Your {project} has been sent", + String.format ("Your {project} %s has been sent to %s", + _this.viewer.getProject ().getName (), + _this.editor.getMainName ())); + + UIUtils.closePopupParent (_this); + + }, + // On cancel of login. + () -> + { + + UIUtils.closePopupParent (_this); + + }, + null); + + return false; + + } + + public void handleCancel () + { + + final SendProjectWizard _this = this; + + // Check to see if we are sending to a pending editor. + if (this.editor.isPending ()) + { + + InviteMessage invite = new InviteMessage (EditorsEnvironment.getUserAccount ()); + + invite.setEditor (this.editor); + + // Send an invite. + EditorsEnvironment.sendMessageToEditor (invite, + () -> + { + + /* + TODO + AbstractViewer viewer = Environment.getFocusedViewer (); + + UIUtils.showMessage ((PopupsSupported) viewer, + "Invite sent", + String.format ("An invite has been sent to: %s.", + _this.editor.getEmail ()), + "Ok, got it", + null); + */ + + }, + null, + null); + + } + + } + + @Override + public String getNextButtonLabel (String currStage) + { + + if (currStage.equals ("details")) + { + + return "Send"; + + } + + return super.getNextButtonLabel (currStage); + + } + + public String getNextStage (String currStage) + { + + if (currStage == null) + { + + return "choose"; + + } + + if (currStage.equals ("newversionname")) + { + + if (this.firstSend) + { + + return "first.selectchapters"; + + } + + return "details"; + + } + + if (currStage.equals ("first")) + { + + if (this.createVersion.isSelected ()) + { + + return "newversionname"; + + } + + return "details"; + + } + + if (currStage.equals ("first.selectchapters")) + { + + return "first.notes"; + + } + + if (currStage.equals ("first.notes")) + { + + return "first.create"; + + } + + if (currStage.equals ("first.create")) + { + + return "details"; + + } + + if (currStage.equals ("choose")) + { + + return "details"; + + } + + return null; + + } + + public String getPreviousStage (String currStage) + { + + if (currStage == null) + { + + return null; + + } + + if (currStage.equals ("details")) + { + + if (this.selectDetails.isSelected ()) + { + + if (this.firstSend) + { + + return "first"; + + } + + return "choose"; + + } + + if (this.createVersion.isSelected ()) + { + + return "newversionname"; + + } + + return "choose"; + + } + + if (currStage.equals ("first.selectchapters")) + { + + return "newversionname"; + + } + + if (currStage.equals ("first.notes")) + { + + return "first.selectchapters"; + + } + + if (currStage.equals ("newversionname")) + { + + if (this.firstSend) + { + + return "first"; + + } + + return "choose"; + + } + + if (currStage.equals ("details")) + { + + return "choose"; + + } + + return null; + + } + + public boolean handleStageChange (String oldStage, + String newStage) + { + + if (newStage.equals ("first")) + { + + this.enableButton ("next", + false); + + } + + if (newStage.equals ("newversionname")) + { + + this.newVerName.grabFocus (); + + this.enableButton ("next", + false); + + } + + if (newStage.equals ("first")) + { + + return true; + + } + + if (newStage.equals ("choose")) + { + + return true; + + } + + if (oldStage != null) + { + + if (oldStage.equals ("newversionname")) + { + + this.newVerNameError.setVisible (false); + + if (this.newVerName.getText ().length () == 0) + { + + this.newVerNameError.setText ("Please enter a name for the version."); + + this.newVerNameError.setVisible (true); + + return false; + + } else { + + try + { + + if (this.viewer.getProjectVersion (this.newVerName.getText ().trim ()) != null) + { + + this.newVerNameError.setText ("Already have a version with that name."); + + this.newVerNameError.setVisible (true); + + return false; + + } + + } catch (Exception e) { + + Environment.logError ("Unable to get project version with name: " + + this.newVerName.getText (), + e); + + UIUtils.showErrorMessage (this.viewer, + "Unable to check the version name."); + + return false; + + } + + } + + } + + } + + return true; + + } + + public String getStartStage () + { + + if (this.firstSend) + { + + return "first"; + + } + + //return "choose"; + + return "first"; + + } + + public WizardStep getStage (String stage) + { + + final SendProjectWizard _this = this; + + WizardStep ws = new WizardStep (); + + if (stage.equals ("first.notes")) + { + + ws.title = "Finally, add some notes"; + + FormLayout fl = new FormLayout ("5px, fill:410px:grow, 10px", + "p, 10px, p"); + + PanelBuilder builder = new PanelBuilder (fl); + + CellConstraints cc = new CellConstraints (); + + JTextPane desc = UIUtils.createHelpTextPane ("The final step in creating a version is adding some notes about what you would like the {editor} to do. It's a description of what you would like them to focus on while editing and areas they should pay attention to (or not).

    Leave this bit blank if you want to give individual instructions for each {editor}.", + this.viewer); + desc.setBorder (null); + + int row = 1; + + builder.add (desc, + cc.xy (2, + row)); + + row += 2; + + this.notes = new TextArea (null, + 4, + 5000); + + builder.add (notes, + cc.xy (2, + row)); + + JPanel p = builder.getPanel (); + p.setOpaque (false); + p.setAlignmentX (JComponent.LEFT_ALIGNMENT); + p.setAlignmentY (JComponent.TOP_ALIGNMENT); + + ws.panel = p; + + } + + if (stage.equals ("first.selectchapters")) + { + + ws.title = "Select the {chapters}"; + + FormLayout fl = new FormLayout ("5px, fill:410px:grow, 10px", + "p, 10px, p"); + + PanelBuilder builder = new PanelBuilder (fl); + + CellConstraints cc = new CellConstraints (); + + JTextPane desc = UIUtils.createHelpTextPane ("Select the {chapters} that you would like to be part of the version. But don't worry, the version only acts as a template for what you send. You can always change what you actually send to {an editor} when you send it.", + this.viewer); + desc.setBorder (null); + + int row = 1; + + builder.add (desc, + cc.xy (2, + row)); + + row += 2; + + this.chapterTree = UIUtils.createSelectableTree (); + + Project proj = this.viewer.getProject (); + + final DefaultMutableTreeNode root = UIUtils.createTreeNode (proj, + null, + null, + true); + + if (proj.getBooks ().size () == 1) + { + + Book b = (Book) proj.getBooks ().get (0); + + DefaultMutableTreeNode broot = UIUtils.createTreeNode (b, + null, + null, + true); + + //root.add (broot); + + // Get the chapters. + List chaps = b.getChapters (); + + for (Chapter c : chaps) + { + + DefaultMutableTreeNode node = UIUtils.createTreeNode (c, + null, + null, + true); + + SelectableDataObject s = (SelectableDataObject) node.getUserObject (); + + s.selected = true; + + if (node == null) + { + + continue; + + } + + root.add (node); + + } + + } else + { + + List books = proj.getBooks (); + + for (int i = 0; i < books.size (); i++) + { + + Book b = books.get (i); + + DefaultMutableTreeNode node = UIUtils.createTree (b, + null, + null, + true); + + if (node == null) + { + + continue; + + } + + root.add (node); + + } + + } + + this.chapterTree.setModel (new DefaultTreeModel (root)); + + UIUtils.expandAllNodesWithChildren (this.chapterTree); + + JComponent t = this.chapterTree; + + if (this.chapterTree.getPreferredSize ().height > 300) + { + + JScrollPane sp = UIUtils.createScrollPane (this.chapterTree); + sp.setOpaque (false); + //sp.setBorder (null); + + sp.setPreferredSize (new Dimension (200, + 300)); + + t = sp; + + } + + builder.add (t, + cc.xy (2, + row)); + + JPanel p = builder.getPanel (); + p.setOpaque (false); + p.setAlignmentX (JComponent.LEFT_ALIGNMENT); + p.setAlignmentY (JComponent.TOP_ALIGNMENT); + + ws.panel = p; + + } + + if (stage.equals ("newversionname")) + { + + ws.title = "Select a name for the version"; + + int row = 1; + + FormLayout fl = new FormLayout ("5px, fill:410px:grow, 10px", + "p, 10px, p, p"); + + PanelBuilder builder = new PanelBuilder (fl); + + CellConstraints cc = new CellConstraints (); + + JTextPane desc = UIUtils.createHelpTextPane ("Version names should be meanginful to you, for example 1st Draft, 2nd Draft. You can also create special versions just for your {editor}, for example Jason first edit. The only restriction is that the name must be unique across all versions you create for this {project}.

    Enter the name of the version in the box below.", + this.viewer); + desc.setBorder (null); + + builder.add (desc, + cc.xy (2, + row)); + + row += 2; + + this.newVerNameError.setVisible (false); + this.newVerNameError.setBorder (UIUtils.createPadding (0, 0, 5, 5)); + + UIUtils.addDoActionOnReturnPressed (this.newVerName, + new ActionListener () + { + + public void actionPerformed (ActionEvent ev) + { + + if (_this.firstSend) + { + + _this.showStage ("first.selectchapters"); + + return; + + } + + _this.showStage ("details"); + + } + + }); + + this.newVerName.addKeyListener (new KeyAdapter () + { + + public void keyPressed (KeyEvent ev) + { + + _this.newVerNameError.setVisible (false); + + _this.enableButton ("next", + true); + + } + + }); + + builder.add (this.newVerNameError, + cc.xy (2, + row)); + + row++; + + builder.add (this.newVerName, + cc.xy (2, + row)); + + JPanel p = builder.getPanel (); + p.setOpaque (false); + p.setAlignmentX (JComponent.LEFT_ALIGNMENT); + p.setAlignmentY (JComponent.TOP_ALIGNMENT); + + ws.panel = p; + + this.enableButton ("next", + false); + + } + + if (stage.equals ("first")) + { + + ws.title = "Sending your first project"; + + int row = 1; + + FormLayout fl = new FormLayout ("5px, fill:410px:grow, 10px", + "p, 10px, p, 6px, p"); + + PanelBuilder builder = new PanelBuilder (fl); + + CellConstraints cc = new CellConstraints (); + + JTextPane desc = UIUtils.createHelpTextPane ("It is recommended that you send a version of your {project}. A version is just a snapshot of your {chapters} with a name you provide. It acts as a template or shortcut for what you send to {editors}.

    For example you might have a 1st Draft version or a Ready for edit version and so on. The name is a label that helps you remember what you sent and makes any comments you receive from {editors} more meaningful.

    A version helps ensure you send the same thing to your {editors} (although you can tweak what you send).

    So, pick an option below to continue.", + this.viewer); + desc.setBorder (null); + + builder.add (desc, + cc.xy (2, + row)); + + row += 2; + + this.createVersion = new JRadioButton ("Create a version"); + + this.createVersion.addActionListener (new ActionListener () + { + + public void actionPerformed (ActionEvent ev) + { + + _this.showStage ("newversionname"); + + UIUtils.doLater (new ActionListener () + { + + public void actionPerformed (ActionEvent ev) + { + + _this.newVerName.grabFocus (); + + } + + }); + + } + + }); + + this.createVersion.setOpaque (false); + + this.selectDetails = new JRadioButton (Environment.replaceObjectNames ("I'll select the {chapters} to send")); + + this.selectDetails.addActionListener (new ActionListener () + { + + public void actionPerformed (ActionEvent ev) + { + + _this.showStage ("details"); + + } + + }); + + this.selectDetails.setOpaque (false); + + ButtonGroup bg = new ButtonGroup (); + + bg.add (this.createVersion); + bg.add (this.selectDetails); + + builder.add (this.createVersion, + cc.xy (2, + row)); + + row += 2; + + builder.add (this.selectDetails, + cc.xy (2, + row)); + + JPanel p = builder.getPanel (); + p.setOpaque (false); + p.setAlignmentX (JComponent.LEFT_ALIGNMENT); + p.setAlignmentY (JComponent.TOP_ALIGNMENT); + + ws.panel = p; + + this.enableButton ("next", + false); + + } + + if (stage.equals ("choose")) + { + + ws.title = "Select what you would like to do"; + + FormLayout fl = new FormLayout ("10px, p, 10px", + "p, 6px, p, 6px, p"); + + PanelBuilder builder = new PanelBuilder (fl); + + CellConstraints cc = new CellConstraints (); + + this.createVersion = new JRadioButton ("Create a new version"); + + this.createVersion.setOpaque (false); + + JRadioButton b2 = new JRadioButton (Environment.replaceObjectNames ("Select the {chapters} to send")); + + b2.setOpaque (false); + + ButtonGroup bg = new ButtonGroup (); + + bg.add (this.createVersion); + bg.add (b2); + + int row = 1; + + builder.add (this.createVersion, + cc.xy (2, + row)); + + row += 2; + + builder.add (b2, + cc.xy (2, + row)); + + JPanel p = builder.getPanel (); + p.setOpaque (false); + p.setAlignmentX (JComponent.LEFT_ALIGNMENT); + + ws.panel = p; + + } + + if (stage.equals ("details")) + { + + Box content = new Box (BoxLayout.Y_AXIS); + + ws.title = "Select what you would like to send"; + ws.alwaysRefreshPanel = true; + + JTextPane desc = UIUtils.createHelpTextPane ("You can select a date indicating when you would like the editing to be completed, but be reasonable, {editors} have lives too!", + this.viewer); + desc.setBorder (null); + + desc.setBorder (UIUtils.createPadding (0, 5, 0, 0)); + content.add (desc); + + this.error = UIUtils.createErrorLabel (""); + this.error.setBorder (UIUtils.createPadding (10, 10, 0, 10)); + this.error.setVisible (false); + + content.add (this.error); + + + + String verName = (this.projectVersion != null ? this.projectVersion.getName () : this.newVerName.getText ().trim ()); + + boolean hasVersion = verName.length () > 0; + + String verRow = ""; + + if (this.createVersion.isSelected ()) + { + + verRow = "p, 6px,"; + + } + + FormLayout fl = new FormLayout ("6px, right:p, 6px, fill:200px:grow", + "10px, " + verRow + " top:p, 6px, p, 6px, top:min(150px;p), 0px"); + + fl.setHonorsVisibility (true); + PanelBuilder builder = new PanelBuilder (fl); + + CellConstraints cc = new CellConstraints (); + + int row = 2; + + if (hasVersion) + { + + builder.addLabel (Environment.replaceObjectNames ("Version"), + cc.xy (2, + row)); + + builder.addLabel (verName, + cc.xy (4, + row)); + + row += 2; + + } + + builder.addLabel (Environment.replaceObjectNames ("Notes"), + cc.xy (2, + row)); + + this.notes = new TextArea (Environment.replaceObjectNames ("Tell your {editor} about your {project}/book/story here. Also add instructions/hints on what you are wanting them to do, what to look at specifically and so on."), + 4, + 5000); + + builder.add (notes, + cc.xy (4, + row)); + + row += 2; + + builder.addLabel (Environment.replaceObjectNames ("Due by"), + cc.xy (2, + row)); + + Calendar cal = new GregorianCalendar (); + cal.add (Calendar.DATE, + 7); + + this.date = new JDateChooser (cal.getTime ()); + + this.date.setMinSelectableDate (new Date ()); + this.date.getCalendarButton ().setMargin (new java.awt.Insets (3, 3, 3, 3)); + this.date.setIcon (Environment.getIcon ("date", + 16)); + + Box calBox = new Box (BoxLayout.X_AXIS); + calBox.add (this.date); + this.date.setMaximumSize (this.date.getPreferredSize ()); + builder.add (calBox, + cc.xy (4, + row)); + + row += 2; + + builder.addLabel (Environment.replaceObjectNames ("{Chapters}"), + cc.xy (2, + row)); + + this.chapterTree = UIUtils.createSelectableTree (); + + Project p = this.viewer.getProject (); + + final DefaultMutableTreeNode root = UIUtils.createTreeNode (p, + null, + null, + true); + + if (p.getBooks ().size () == 1) + { + + Book b = (Book) p.getBooks ().get (0); + + DefaultMutableTreeNode broot = UIUtils.createTreeNode (b, + null, + null, + true); + + //root.add (broot); + + // Get the chapters. + List chaps = b.getChapters (); + + for (Chapter c : chaps) + { + + DefaultMutableTreeNode node = UIUtils.createTreeNode (c, + null, + null, + true); + + SelectableDataObject s = (SelectableDataObject) node.getUserObject (); + + s.selected = true; + + if (node == null) + { + + continue; + + } + + root.add (node); + + } + + } else + { + + List books = p.getBooks (); + + for (int i = 0; i < books.size (); i++) + { + + Book b = books.get (i); + + DefaultMutableTreeNode node = UIUtils.createTree (b, + null, + null, + true); + + if (node == null) + { + + continue; + + } + + root.add (node); + + } + + } + + this.chapterTree.setModel (new DefaultTreeModel (root)); + + UIUtils.expandAllNodesWithChildren (this.chapterTree); + + JComponent t = this.chapterTree; + + if (this.chapterTree.getPreferredSize ().height > 200) + { + + JScrollPane sp = UIUtils.createScrollPane (this.chapterTree); + sp.setOpaque (false); + //sp.setBorder (null); + + sp.setPreferredSize (new Dimension (200, + 170)); + + t = sp; + + } + + builder.add (t, + cc.xy (4, + row)); + + row++; + + JLabel sending = UIUtils.createLoadingLabel ("Sending {project}"); + sending.setText (Environment.replaceObjectNames ("Sending {project}...")); + sending.setVisible (true); + + this.sendBox = new Box (BoxLayout.X_AXIS); + this.sendBox.setBorder (UIUtils.createPadding (10, 0, 0, 0)); + this.sendBox.add (sending); + this.sendBox.setVisible (false); + + builder.add (this.sendBox, + cc.xy (4, + row)); + + JPanel panel = builder.getPanel (); + panel.setOpaque (false); + panel.setAlignmentX (JComponent.LEFT_ALIGNMENT); + + content.add (panel); + + ws.panel = content; + + UIUtils.doLater (new ActionListener () + { + + public void actionPerformed (ActionEvent ev) + { + + //_this.notes.getTextArea ().getCaret ().setDot (0); + //_this.notes.grabFocus (); + + UIUtils.resizeParent (_this); + + } + + }); + + } + + return ws; + + } + +} diff --git a/src/main/java/com/quollwriter/editors/ui/UpdateProjectMessageBox.java b/src/main/java/com/quollwriter/editors/ui/UpdateProjectMessageBox.java new file mode 100644 index 00000000..1c29eb0c --- /dev/null +++ b/src/main/java/com/quollwriter/editors/ui/UpdateProjectMessageBox.java @@ -0,0 +1,170 @@ +package com.quollwriter.editors.ui; + +import java.util.*; + +import javafx.beans.property.*; +import javafx.scene.*; +import javafx.scene.control.*; +import javafx.scene.layout.*; + +import com.quollwriter.*; +import com.quollwriter.data.*; +import com.quollwriter.editors.messages.*; +import com.quollwriter.editors.*; + +import com.quollwriter.ui.fx.*; +import com.quollwriter.ui.fx.viewers.*; +import com.quollwriter.ui.fx.components.*; + +import static com.quollwriter.LanguageStrings.*; +import static com.quollwriter.uistrings.UILanguageStringsManager.getUILanguageStringProperty; + +public class UpdateProjectMessageBox extends MessageBox +{ + + private VBox responseBox = null; + private Label previousLabel = null; + + public UpdateProjectMessageBox (UpdateProjectMessage mess, + AbstractViewer viewer) + { + + super (mess, + viewer); + + StringProperty text = getUILanguageStringProperty (editors,messages,updateproject,sent,title); + //"{Project} update sent";//Sent {project} update"; + + if (!this.message.isSentByMe ()) + { + + text = getUILanguageStringProperty (editors,messages,updateproject,received,title); + //"{Project} update received"; //Received {project} update"; + + } + + this.binder.addChangeListener (this.message.dealtWithProperty (), + (pr, oldv, newv) -> + { + + this.update (); + + }); + + this.binder.addChangeListener (this.message.getEditor ().editorStatusProperty (), + (pr, oldv, newv) -> + { + + this.update (); + + }); + + this.getStyleClass ().add (StyleClassNames.UPDATEPROJECTMESSAGE); + + this.getChildren ().add (Header.builder () + .title (text) + .iconClassName (StyleClassNames.PROJECT) + .styleClassName (StyleClassNames.HEADER) + .build ()); + + Node details = EditorsUIUtils.getProjectMessageDetails (this.message, + this.viewer, + this); + + details.getStyleClass ().add (StyleClassNames.MESSAGEDETAILS); + this.getChildren ().add (details); + + this.responseBox = new VBox (); + this.responseBox.getStyleClass ().add (StyleClassNames.RESPONSE); + this.responseBox.managedProperty ().bind (this.responseBox.visibleProperty ()); + this.responseBox.setVisible (false); + this.getChildren ().add (this.responseBox); + + if (!this.message.isSentByMe ()) + { + + // Not sent by me. + if ((!this.message.isDealtWith ()) + && + (!this.message.getEditor ().isPrevious ()) + ) + { + + QuollButtonBar responseButs = QuollButtonBar.builder () + .button (QuollButton.builder () + .label (editors,messages,updateproject,received,undealtwith,buttons,LanguageStrings.update) + .onAction (ev -> + { + + EditorsUIUtils.showProjectUpdate (this.message, + this.viewer, + null); + + }) + .build ()) + .build (); + + this.responseBox.getChildren ().add (responseButs); + this.responseBox.setVisible (true); + + } + + } + + this.previousLabel = QuollLabel.builder () + .styleClassName (StyleClassNames.PREVIOUS) + .build (); + + } + + private void update () + { + + if (this.message.isDealtWith ()) + { + + this.responseBox.setVisible (false); + + } + + if ((!this.message.isDealtWith ()) + && + (this.message.getEditor ().isPrevious ()) + ) + { + + this.previousLabel.textProperty ().unbind (); + this.previousLabel.textProperty ().bind (getUILanguageStringProperty (Arrays.asList (editors,messages,updateproject,received,undealtwith,previouseditor), + //"%s is a previous {contact}. This message can no longer be acted upon.", + this.message.getEditor ().getMainName ())); + this.previousLabel.setVisible (true); + this.responseBox.setVisible (false); + + } + + } + + @Override + public boolean isShowAttentionBorder () + { + + if (this.message.getEditor ().isPrevious ()) + { + + return false; + + } + + return super.isShowAttentionBorder (); + + } + + @Override + public boolean isAutoDealtWith () + { + + return false; + + } + +} diff --git a/src/main/java/com/quollwriter/editors/ui/ViewCommentPopup.java b/src/main/java/com/quollwriter/editors/ui/ViewCommentPopup.java new file mode 100644 index 00000000..e8488616 --- /dev/null +++ b/src/main/java/com/quollwriter/editors/ui/ViewCommentPopup.java @@ -0,0 +1,224 @@ +package com.quollwriter.editors.ui; + +import java.util.*; +import java.util.function.*; + +import javafx.scene.Node; +import javafx.scene.layout.*; +import javafx.scene.control.IndexRange; + +import javafx.beans.property.*; + +import com.quollwriter.*; +import com.quollwriter.data.*; +import com.quollwriter.editors.*; +import com.quollwriter.ui.fx.*; +import com.quollwriter.ui.fx.components.*; +import com.quollwriter.ui.fx.viewers.*; +import com.quollwriter.editors.ui.panels.*; +import com.quollwriter.ui.fx.popups.*; +import com.quollwriter.ui.fx.panels.*; + +import static com.quollwriter.uistrings.UILanguageStringsManager.getUILanguageStringProperty; +import static com.quollwriter.LanguageStrings.*; + +public class ViewCommentPopup extends PopupContent +{ + + private static final String POPUP_ID = "viewcomment"; + private Set items = null; + private TextEditor.Highlight highlight = null; + + public ViewCommentPopup (AbstractProjectViewer viewer, + Set items, + boolean itemEditable) + { + + super (viewer); + + if ((items == null) + || + (items.size () == 0) + ) + { + + throw new IllegalArgumentException ("At least one note must be specified."); + + } + + this.items = items; + + VBox b = new VBox (); + + Node last = null; + Node first = null; + + Runnable r = () -> + { + + this.close (); + + }; + + for (Note i : items) + { + + Supplier> extraControls = null; + + if (!itemEditable) + { + + extraControls = () -> + { + + Set cons = new LinkedHashSet<> (); + + QuollButton d = QuollButton.builder () + .iconName (i.isDealtWith () ? StyleClassNames.UNDEALTWITH : StyleClassNames.DEALTWITH) + .onAction (ev -> + { + + if (i.isDealtWith ()) + { + + i.setDealtWith (null); + + } else { + + i.setDealtWith (new Date ()); + + } + + }) + .build (); + + this.getBinder ().addChangeListener (i.dealtWithProperty (), + (pr, oldv, newv) -> + { + + d.setIconName (i.isDealtWith () ? StyleClassNames.UNDEALTWITH : StyleClassNames.DEALTWITH); + + }); + + cons.add (d); + + return cons; + + }; + + } + + CommentItemFormatter form = new CommentItemFormatter (this.viewer, + this.getBinder (), + i, + r, + itemEditable, + extraControls); + + Node n = form.format (); + n.getStyleClass ().add (StyleClassNames.CHAPTERITEM); + n.getStyleClass ().add (form.getStyleClassName ()); + + if (first == null) + { + + first = n; + n.pseudoClassStateChanged (StyleClassNames.FIRST_PSEUDO_CLASS, true); + + } + + last = n; + + b.getChildren ().add (n); + + } + + last.pseudoClassStateChanged (StyleClassNames.LAST_PSEUDO_CLASS, true); + + if (items.size () == 1) + { + + ChapterItem ci = items.iterator ().next (); + + if (ci instanceof Note) + { + + Note n = (Note) ci; + + if (n.isEditNeeded ()) + { + + if (n.getEndPosition () > n.getStartPosition ()) + { + + this.highlight = this.viewer.getEditorForChapter (n.getChapter ()).getEditor ().addHighlight (new IndexRange (n.getStartPosition (), + n.getEndPosition ()), + UserProperties.getEditNeededNoteChapterHighlightColor ()); + + } + + } + + } + + } + + this.getChildren ().add (b); + + } + + @Override + public QuollPopup createPopup () + { + + Note top = this.items.iterator ().next (); + + QuollPopup p = QuollPopup.builder () + .title (getUILanguageStringProperty (objectnames,singular,StyleClassNames.COMMENT)) + .styleClassName (StyleClassNames.COMMENT) + .headerIconClassName (StyleClassNames.COMMENT) + .styleSheet ("comments") + .hideOnEscape (true) + .withClose (true) + .content (this) + .popupId (ViewCommentPopup.getPopupIdForComment (top)) + .removeOnClose (true) + .withViewer (this.viewer) + .build (); + + p.getStyleClass ().add (StyleClassNames.CHAPTERITEM); + p.getStyleClass ().add (StyleClassNames.VIEW); + + p.toFront (); + + p.addEventHandler (QuollPopup.PopupEvent.CLOSED_EVENT, + ev -> + { + + this.getBinder ().dispose (); + + Note ci = this.items.iterator ().next (); + + ChapterEditorPanelContent ed = this.viewer.getEditorForChapter (ci.getChapter ()); + + if (ed != null) + { + + ed.getEditor ().removeHighlight (this.highlight); + + } + + }); + + return p; + + } + + public static String getPopupIdForComment (Note ci) + { + + return POPUP_ID + ci.getObjectReference ().asString (); + + } + +} diff --git a/src/com/quollwriter/editors/ui/panels/AdvertiseProjectPanel.java b/src/main/java/com/quollwriter/editors/ui/panels/AdvertiseProjectPanel.java similarity index 89% rename from src/com/quollwriter/editors/ui/panels/AdvertiseProjectPanel.java rename to src/main/java/com/quollwriter/editors/ui/panels/AdvertiseProjectPanel.java index 8832e370..a03bad9d 100644 --- a/src/com/quollwriter/editors/ui/panels/AdvertiseProjectPanel.java +++ b/src/main/java/com/quollwriter/editors/ui/panels/AdvertiseProjectPanel.java @@ -24,8 +24,6 @@ import java.util.LinkedHashSet; import java.util.LinkedHashMap; -import javax.activation.*; - import javax.swing.*; import javax.swing.border.*; import javax.swing.event.*; @@ -70,20 +68,20 @@ public class AdvertiseProjectPanel extends QuollPanel private ComboBoxFormItem typesF = null; private TextFormItem titleF = null; private ImageSelectorFormItem avatarF = null; - + private Map formItems = new LinkedHashMap (); - + public AdvertiseProjectPanel (AbstractViewer pv) throws GeneralException { super (pv); - + } - + public void close () { - + } public boolean saveUnsavedChanges () @@ -101,7 +99,7 @@ public String getPanelId () return AdvertiseProjectPanel.PANEL_ID; } - + public void init () throws GeneralException { @@ -113,81 +111,81 @@ public void init () Constants.NOTIFY_ICON_NAME, null); this.add (h); - + EditorsWebServiceHandler wsHandler = EditorsEnvironment.getEditorsWebServiceHandler (); - + EditorAccount acc = EditorsEnvironment.getUserAccount (); - + EditorAuthor auth = null; - + String email = null; String pass = null; - + if (acc != null) { - + email = acc.getEmail (); - + auth = acc.getAuthor (); - + } - + EditorProject proj = null; //this.projectViewer.getProject ().getEditorProject (); - + String title = ""; //this.projectViewer.getProject ().getName (); String desc = null; Set selectedGenres = null; String wcLength = null; String exp = null; - + if (proj != null) { - + title = proj.getName (); desc = (proj.getDescription () != null ? proj.getDescription ().getText () : null); selectedGenres = proj.getGenres (); wcLength = proj.getWordCountLength ().getType (); exp = proj.getExpectations (); - + } - + String yourName = null; File avatarFile = null; String about = null; - + if (auth != null) { - + yourName = auth.getName (); - + DataSource ds = auth.getAvatar (); - + if (ds != null) { - + if (!(ds instanceof FileDataSource)) { - + Environment.logError ("Illegal data source type for author avatar image: " + ds.getClass ().getName ()); - - } else { - + + } else { + avatarFile = ((FileDataSource) ds).getFile (); - + } } - + about = auth.getAbout (); - + } - + final Box box = new ScrollableBox (BoxLayout.Y_AXIS); box.setAlignmentX (Component.LEFT_ALIGNMENT); - + box.add (this.createHeader (Environment.replaceObjectNames ("About your {project}"))); - + this.titleF = new TextFormItem ("Title", false, 1, @@ -196,10 +194,10 @@ public void init () "chars", true, null); - + this.formItems.put ("title", this.titleF); - + box.add (titleF); this.descF = new TextFormItem ("Description", @@ -210,14 +208,14 @@ public void init () "words", true, null); - + this.formItems.put ("desc", this.descF); box.add (this.descF); Vector gitems = new Vector (EditorsEnvironment.getWritingGenres ()); - + this.genresF = new SelectFormItem ("Genres", gitems, 5, @@ -234,7 +232,7 @@ public void init () typeVals.add (EditorProject.WordCountLength.novelette.getDescription ());//"Novellette (7,500 to 17,5000 words"); typeVals.add (EditorProject.WordCountLength.novella.getDescription ());//"Novella (17,500 to 40,000 words"); typeVals.add (EditorProject.WordCountLength.novel.getDescription ());//"Novel (over 40,000 words"); - + this.typesF = new ComboBoxFormItem ("The approximate amount of text you would like to be edited", typeVals, wcLength, @@ -254,7 +252,7 @@ public void init () "words", true, null); - + this.formItems.put ("exp", this.expF); @@ -262,8 +260,8 @@ public void init () box.add (this.createHeader (Environment.replaceObjectNames ("About you"))); Box aboutBox = new Box (BoxLayout.Y_AXIS); - aboutBox.setAlignmentX (Component.LEFT_ALIGNMENT); - + aboutBox.setAlignmentX (Component.LEFT_ALIGNMENT); + this.nameF = new TextFormItem ("Your name", false, 1, @@ -282,7 +280,7 @@ public void init () fileTypes.add ("jpeg"); fileTypes.add ("png"); fileTypes.add ("gif"); - + this.avatarF = new ImageSelectorFormItem ("Your picture/avatar", fileTypes, avatarFile, @@ -292,65 +290,65 @@ public void init () this.avatarF.getImageSelector ().addChangeListener (new ChangeListener () { - + public void stateChanged (ChangeEvent ev) { - + File f = _this.avatarF.getImageSelector ().getFile (); if (f != null) { - + try { // Get the first image, check for animated gif. if (UIUtils.isAnimatedGif (f)) { - + UIUtils.showErrorMessage (_this, "Sorry animated gifs are not supported."); - + _this.avatarF.getImageSelector ().setFile (null); - + return; - + } - + BufferedImage im = UIUtils.getScaledImage (f, 300); - + ByteArrayOutputStream bout = new ByteArrayOutputStream (); - + ImageIO.write (im, Utils.getFileType (f), bout); - + String s = Base64.encodeBytes (bout.toByteArray ()); - + if (s.length () > EditorsWebServiceHandler.MAX_IMAGE_SIZE) { - + UIUtils.showErrorMessage (_this, "Sorry your image/avatar is too large."); - + } } catch (Exception e) { - + Environment.logError ("Unable to check image file: " + f, e); - + } } - + } - + }); - + this.formItems.put ("avatar", this.avatarF); - + aboutBox.add (this.avatarF); this.aboutF = new TextFormItem ("About you", @@ -365,11 +363,11 @@ public void stateChanged (ChangeEvent ev) this.formItems.put ("about", this.aboutF); aboutBox.add (this.aboutF); - + box.add (aboutBox); - + box.add (this.createHeader (Environment.replaceObjectNames ("Login details"))); - + box.add (this.createHelpText ("In order to communicate with your editors you need to create an account with us. Please provide an email address and a password.")); this.emailF = new TextFormItem ("Email", @@ -380,7 +378,7 @@ public void stateChanged (ChangeEvent ev) "chars", true, null); - + this.formItems.put ("email", this.emailF); box.add (this.emailF); @@ -395,39 +393,39 @@ public void stateChanged (ChangeEvent ev) null); this.formItems.put ("pass", this.passF); - + box.add (this.passF); box.add (this.createHeader (Environment.replaceObjectNames ("Ready to go?"))); - + box.add (this.createHelpText ("Ready to go???")); JButton[] buts = new JButton[2]; - + buts[0] = new JButton ("Advertise"); - + buts[0].addActionListener (new ActionAdapter () { - + public void actionPerformed (ActionEvent ev) { - + _this.createAccount (); - + } - + }); - + buts[1] = new JButton ("Cancel"); - + JPanel bp = UIUtils.createButtonBar2 (buts, Component.LEFT_ALIGNMENT); //ButtonBarFactory.buildLeftAlignedBar (buts); bp.setOpaque (false); - + box.add (this.setAsSubItem (bp)); box.add (Box.createVerticalStrut (15)); - + box.setBorder (null); box.add (Box.createVerticalGlue ()); box.setMaximumSize (new Dimension (500, @@ -443,106 +441,106 @@ public void actionPerformed (ActionEvent ev) lscroll.getVerticalScrollBar ().addAdjustmentListener (new AdjustmentListener () { - + public void adjustmentValueChanged (AdjustmentEvent ev) { - + if (lscroll.getVerticalScrollBar ().getValue () > 0) { - + lscroll.setBorder (new MatteBorder (1, 0, 0, 0, UIUtils.getInnerBorderColor ())); } else { - + lscroll.setBorder (new EmptyBorder (1, 0, 0, 0)); - + } - + } - + }); - + box.setBorder (new EmptyBorder (5, 10, 10, 10)); - + this.add (lscroll); - + for (FormItem it : this.formItems.values ()) { - + //it.init (); - + } SwingUtilities.invokeLater (new Runnable () { - + public void run () { - + lscroll.getVerticalScrollBar ().setValue (0); - + } - + }); */ } private void createAccount () { - + FormItem error = null; - + for (FormItem it : this.formItems.values ()) { - + //it.setError (false); - + if (it.hasError ()) { - + //it.updateRequireLabel (); - + //it.setError (true); - + if (error == null) { error = it; - + } } - + } - + if (error != null) { - + //error.scrollIntoView (); return; - + } - + final AdvertiseProjectPanel _this = this; - + new Thread (new Runnable () { - + public void run () { - + try { - + // Wipe out any existing avatar image file. EditorsEnvironment.getEditorsAuthorAvatarImageFile ().delete (); - + EditorsWebServiceHandler h = EditorsEnvironment.getEditorsWebServiceHandler (); - + List projs = h.findProjects ("Monster%"); - + System.out.println ("FOUND: " + projs); /* h.saveAccount (_this.emailF.getValue (), @@ -562,55 +560,55 @@ public void run () _this.expF.getValue (), EditorProject.WordCountLength.getWordCountLengthByDescription (_this.typesF.getValue ()), null); - */ + */ System.out.println ("CREATED/SAVED PROJECT"); - + } catch (Exception e) { UIUtils.showErrorMessage (_this, "Sorry, unable to create/update your information at the moment. Please try again later."); - + Environment.logError ("Unable to create/update editor", e); - + } - + } - + }).start (); - + } - + private JComponent setAsSubItem (JComponent c) { c.setAlignmentX (Component.LEFT_ALIGNMENT); - c.setAlignmentY (Component.TOP_ALIGNMENT); - + c.setAlignmentY (Component.TOP_ALIGNMENT); + c.setBorder (new CompoundBorder (new EmptyBorder (0, 5, 0, 0), c.getBorder ())); - + return c; - + } private Header createHeader (String title) { - + Header h = UIUtils.createHeader (title, Constants.SUB_PANEL_TITLE); - - h.setBorder (new CompoundBorder (new MatteBorder (0, 0, 1, 0, Environment.getBorderColor ()), + + h.setBorder (new CompoundBorder (new MatteBorder (0, 0, 1, 0, UIUtils.getBorderColor ()), new EmptyBorder (0, 0, 3, 0))); h.setBorder (new CompoundBorder (new EmptyBorder (0, 0, 5, 0), h.getBorder ())); return h; - + } - + private JComponent createWrapper (JComponent c) { - + if (c instanceof JComboBox) { @@ -632,17 +630,17 @@ private JComponent createWrapper (JComponent c) _b.setAlignmentY (Component.TOP_ALIGNMENT); c = _b; - + } else { - + c.setBorder (new EmptyBorder (0, 5, 0, 0)); - + } - + return c; - + } - + private JTextPane createHelpText (String text) { @@ -658,7 +656,7 @@ private JTextPane createHelpText (String text) return t; } - + public void fillToolBar (JToolBar acts, final boolean fullScreen) { @@ -672,12 +670,12 @@ public void saveObject () { } - + public void fillPopupMenu (final MouseEvent ev, final JPopupMenu popup) { - + } public void setState (final Map s, @@ -685,7 +683,7 @@ public void setState (final Map s, { this.setReadyForUse (true); - + } public void getState (Map m) @@ -712,11 +710,11 @@ public void refresh (NamedObject n) @Override public String getTitle () { - + return "Advertise your {Project}"; - + } - + @Override public ImageIcon getIcon (int type) { @@ -725,7 +723,7 @@ public ImageIcon getIcon (int type) type); } - + public JScrollPane getScrollPane () { diff --git a/src/main/java/com/quollwriter/editors/ui/panels/ChapterCommentsPanel.java b/src/main/java/com/quollwriter/editors/ui/panels/ChapterCommentsPanel.java new file mode 100644 index 00000000..1982c5df --- /dev/null +++ b/src/main/java/com/quollwriter/editors/ui/panels/ChapterCommentsPanel.java @@ -0,0 +1,457 @@ +package com.quollwriter.editors.ui.panels; + +import java.io.*; + +import java.text.*; + +import java.util.*; +import java.util.stream.*; + +import javafx.geometry.*; +import javafx.scene.control.*; +import javafx.scene.*; +import javafx.scene.input.*; + +//import org.incava.util.diff.*; + +import com.gentlyweb.properties.*; + +import com.quollwriter.*; +import com.quollwriter.ui.fx.*; +import com.quollwriter.editors.ui.*; +import com.quollwriter.ui.fx.panels.*; +import com.quollwriter.ui.fx.components.*; +import com.quollwriter.data.*; +import com.quollwriter.data.comparators.*; + +import com.quollwriter.text.*; +import com.quollwriter.text.rules.*; + +import static com.quollwriter.LanguageStrings.*; +import static com.quollwriter.uistrings.UILanguageStringsManager.getUILanguageStringProperty; + +public class ChapterCommentsPanel extends ChapterEditorWithMarginPanelContent implements ToolBarSupported +{ + + public ChapterCommentsPanel (ProjectSentReceivedViewer pv, + Chapter c) + throws GeneralException + { + + super (pv, + c); + + //this.projectViewer = pv; + + this.editor.setEditable (false); + + UIUtils.addStyleSheet (this, + Constants.PANEL_STYLESHEET_TYPE, + "chapteredit"); + UIUtils.addStyleSheet (this, + Constants.PANEL_STYLESHEET_TYPE, + "editorchapteredit"); + + final ChapterCommentsPanel _this = this; + + } + + @Override + public Boolean canDrag (ChapterItem ci) + { + + return false; + + } + + @Override + public Map getActionMappings () + { + + return new HashMap<> (); + + } + + @Override + public Set getToolBarItems () + { + + Set its = new LinkedHashSet<> (); + + its.add (QuollButton.builder () + .tooltip (editors,projectsent,commentspanel,toolbar,textproperties,tooltip) + .iconName (StyleClassNames.EDITPROPERTIES) + .onAction (ev -> + { + + this.viewer.runCommand (ProjectSentReceivedViewer.CommandId.textproperties); + + }) + .build ()); + + return its; + + } + + /* + public void showDifferences (Chapter c) + { + + BlockPainter newp = new BlockPainter (Color.GREEN); + BlockPainter modp = new BlockPainter (Color.YELLOW); + BlockPainter oldp = new BlockPainter (Color.RED); + + String ot = TextUtilities.stripNonValidXMLCharacters (this.editor.getTextWithMarkup ().getText ()); + + String nt = TextUtilities.stripNonValidXMLCharacters (c.getText ().getText ()); + + this.editor.setTextWithMarkup (c.getText ()); + + String[] oldText = ot.split ("\\n"); + String[] newText = nt.split ("\\n"); +System.out.println ("OT: " + ot); +System.out.println ("NT: " + nt); +//LinkedList +diff_match_patch dmp = new diff_match_patch (); + System.out.println ("DIFF2: " + dmp.patch_make(ot, nt)); + + List diffs = new Diff (oldText, + newText).diff (); +System.out.println ("DIFF: " + diffs); + for (int i = 0; i < diffs.size (); i++) + { + + Difference d = (Difference) diffs.get (i); + + if (d.getDeletedEnd () == Difference.NONE) + { + + // This is an addition. + for (int k = d.getAddedStart (); k < (d.getAddedEnd () + 1); k++) + { + + this.editor.addHighlight (d.getAddedStart (), + d.getAddedEnd (), + newp, + false); + + } + + continue; + + } + + if (d.getAddedEnd () == Difference.NONE) + { + + // This is a deletion. + for (int k = d.getDeletedStart (); k < (d.getDeletedEnd () + 1); k++) + { + + this.editor.addHighlight (d.getDeletedStart (), + d.getDeletedEnd (), + oldp, + false); + + } + + continue; + + } + + // This is a modification. + for (int k = d.getAddedStart (); k < (d.getAddedEnd () + 1); k++) + { + + this.editor.addHighlight (d.getAddedStart (), + d.getAddedEnd (), + modp, + false); + + } + + } + + } + */ + + @Override + public Node getMarginNodeForChapterItem (ChapterItem ci) + { + + if (ci instanceof Note) + { + + Note n = (Note) ci; + + IconBox riv = IconBox.builder () + .iconName (StyleClassNames.COMMENT) + .build (); + + riv.setOnMouseClicked (ev -> + { + + if (ev.getButton () != MouseButton.PRIMARY) + { + + return; + + } + + this.showItem (n, + true); + + ev.consume (); + + }); + + riv.setOnContextMenuRequested (ev -> + { + + Set items = new LinkedHashSet<> (); + + if (n.isDealtWith ()) + { + + items.add (QuollMenuItem.builder () + .label (getUILanguageStringProperty (Arrays.asList ("Set undealt with"))) + .iconName (StyleClassNames.UNDEALTWITH) + .onAction (eev -> + { + + n.setDealtWith (null); + + }) + .build ()); + + } else { + + items.add (QuollMenuItem.builder () + .label (getUILanguageStringProperty (Arrays.asList ("Set dealt with"))) + .iconName (StyleClassNames.DEALTWITH) + .onAction (eev -> + { + + n.setDealtWith (new Date ()); + + }) + .build ()); + + } + + UIUtils.showContextMenu (riv, + items, + ev.getScreenX (), + ev.getScreenY ()); + + }); + + return riv; + + } + + throw new UnsupportedOperationException ("Object not supported: " + ci); + + } + + @Override + public Set getMarginContextMenuItems (int cpos) + { + + return new HashSet<> (); + + } + + @Override + public Set getContextMenuItems (boolean compress) + { + + Set ret = new LinkedHashSet<> (); + + int pos = this.editor.getTextPositionForCurrentMousePosition (); + + if (compress) + { + + List row1 = new ArrayList<> (); + + row1.add (QuollButton.builder () + .iconName (StyleClassNames.EDITPROPERTIES) + .tooltip (getUILanguageStringProperty (editors,projectsent,commentspanel,popupmenu,Chapter.OBJECT_TYPE,items,textproperties,tooltip)) + .onAction (ev -> + { + + this.viewer.runCommand (ProjectSentReceivedViewer.CommandId.textproperties); + + }) + .build ()); + + row1.add (QuollButton.builder () + .iconName (StyleClassNames.FIND) + .tooltip (getUILanguageStringProperty (editors,projectsent,commentspanel,popupmenu,Chapter.OBJECT_TYPE,items,find,tooltip)) + .onAction (ev -> + { + + this.viewer.showFind (); + + }) + .build ()); + + CustomMenuItem n = UIUtils.createCompressedMenuItem (getUILanguageStringProperty (editors,projectsent,commentspanel,popupmenu,Chapter.OBJECT_TYPE,compresstext), + row1); + + ret.add (n); + + } else { + + ret.add (QuollMenuItem.builder () + .iconName (StyleClassNames.EDITPROPERTIES) + .label (getUILanguageStringProperty (editors,projectsent,commentspanel,popupmenu,Chapter.OBJECT_TYPE,items,textproperties,text)) + .onAction (ev -> + { + + this.viewer.runCommand (ProjectSentReceivedViewer.CommandId.textproperties); + + }) + .build ()); + + ret.add (QuollMenuItem.builder () + .iconName (StyleClassNames.FIND) + .label (getUILanguageStringProperty (editors,projectsent,commentspanel,popupmenu,Chapter.OBJECT_TYPE,items,find,text)) + .onAction (ev -> + { + + this.viewer.showFind (); + + }) + .build ()); + + } + + return ret; + + } + + @Override + public void showItem (ChapterItem item, + boolean showAllForLine) + { + + Note n = (Note) item; + + Note top = n; + Set items = null; + + if (showAllForLine) + { + + items = this.getNotesForPosition (item.getPosition ()); + + if (items.size () == 0) + { + + return; + + } + + top = items.iterator ().next (); + + } else { + + items = new LinkedHashSet<> (); + items.add (n); + + } + + QuollPopup qp = this.viewer.getPopupById (ViewCommentPopup.getPopupIdForComment (top)); + + if (qp != null) + { + + qp.toFront (); + return; + + } + + qp = new ViewCommentPopup (this.viewer, + items, + false).getPopup (); + + this.showPopupForItem (top, + qp); + + } + + public Set getNotesForPosition (int p) + { + + Bounds cb = this.editor.getBoundsForPosition (p); + + if (cb == null) + { + + return new HashSet<> (); + + } + + int paraNo = this.editor.getParagraphForOffset (p); + + double y = cb.getMinY (); + + Set ret = new TreeSet<> (new ChapterItemSorter ()); + + ret.addAll (this.object.getNotes ().stream () + // Only interested in those that have the same y value. i.e. on the same line. + .filter (i -> + { + + // See if we are in the same paragraph. + if (this.editor.getParagraphForOffset (i.getPosition ()) != paraNo) + { + + return false; + + } + + Bounds b = this.editor.getBoundsForPosition (i.getPosition ()); + + return (b != null) && b.getMinY () == y; + + }) + .collect (Collectors.toSet ())); + + return ret; + + } + +/* + public void showNote (Note n) + throws GeneralException + { + + this.scrollToNote (n); + + this.iconColumn.showItem (n); + + } +*/ +/* + public void removeItemHighlightTextFromEditor (ChapterItem it) + { + + this.editor.removeAllHighlights (this.highlight); + + } + + public void highlightItemTextInEditor (ChapterItem it) + { + + this.editor.removeAllHighlights (this.highlight); + this.editor.addHighlight (it.getStartPosition (), + it.getEndPosition (), + this.highlight, + false); + + } +*/ +} diff --git a/src/main/java/com/quollwriter/editors/ui/panels/EditorChapterPanel.java b/src/main/java/com/quollwriter/editors/ui/panels/EditorChapterPanel.java new file mode 100644 index 00000000..83a7f575 --- /dev/null +++ b/src/main/java/com/quollwriter/editors/ui/panels/EditorChapterPanel.java @@ -0,0 +1,1073 @@ +package com.quollwriter.editors.ui.panels; + +import java.io.*; + +import java.text.*; + +import java.util.*; +import java.util.stream.*; + +import javafx.scene.*; +import javafx.scene.control.*; +import javafx.scene.layout.*; +import javafx.scene.input.*; +import javafx.geometry.*; + +import com.gentlyweb.properties.*; + +import org.reactfx.*; +import org.fxmisc.flowless.*; +import org.fxmisc.wellbehaved.event.*; + +import com.quollwriter.*; +import com.quollwriter.ui.fx.*; +import com.quollwriter.ui.fx.panels.*; +import com.quollwriter.ui.fx.components.*; +import com.quollwriter.editors.ui.*; +import com.quollwriter.data.*; +import com.quollwriter.data.comparators.*; +import com.quollwriter.events.*; + +import com.quollwriter.text.*; +import com.quollwriter.text.rules.*; + +import com.swabunga.spell.engine.*; +import com.swabunga.spell.event.*; + +import static com.quollwriter.LanguageStrings.*; +import static com.quollwriter.uistrings.UILanguageStringsManager.getUILanguageStringProperty; + +public class EditorChapterPanel extends ChapterEditorWithMarginPanelContent implements ToolBarSupported +{ + + public static final String CHAPTER_INFO_ACTION_NAME = "chapter-info"; + public static final String SET_EDIT_COMPLETE_ACTION_NAME = "set-edit-complete"; + public static final String REMOVE_EDIT_POINT_ACTION_NAME = "remove-edit-point"; + + public static final String NEW_COMMENT_ACTION_NAME = "newcomment"; + + //private IconColumn iconColumn = null; + private int lastCaret = -1; + //private ChapterItemTransferHandler chItemTransferHandler = null; + //private BlockPainter highlight = null; + private boolean chapterItemEditVisible = false; + private TextEditor.Highlight highlight = null; + + public EditorChapterPanel (EditorProjectViewer pv, + Chapter c) + throws GeneralException + { + + super (pv, + c); + + final EditorChapterPanel _this = this; + + this.editor.setEditable (false); + // TODO this.editor.setCanCopy (false); + + UIUtils.addStyleSheet (this, + Constants.PANEL_STYLESHEET_TYPE, + "chapteredit"); + UIUtils.addStyleSheet (this, + Constants.PANEL_STYLESHEET_TYPE, + "editorchapteredit"); + + this.editor.readyForUseProperty ().addListener ((pr, oldv, newv) -> + { + + if (!newv) + { + + return; + + } + + UIUtils.forceRunLater (() -> + { + + this.object.getNotes ().stream () + .forEach (n -> this.createTextPosition (n)); + + }); + + }); + + Nodes.addInputMap (this.editor, + InputMap.process (EventPattern.mouseClicked (), + ev -> + { + + if (ev.getClickCount () == 2) + { + + this.showAddNewComment (this.editor.getSelection ().getStart ()); + + } + return InputHandler.Result.PROCEED; + + })); + + Nodes.addInputMap (this.editor, + InputMap.consume (EventPattern.keyPressed (KeyCode.C, KeyCombination.SHIFT_DOWN, KeyCombination.SHORTCUT_DOWN), + ev -> + { + + this.showAddNewComment (this.editor.getSelection ().getStart ()); + + })); + + Nodes.addInputMap (this.editor, + InputMap.consume (EventPattern.mouseReleased (), + ev -> + { + + if ((_this.editor.getSelection ().getEnd () > _this.editor.getSelection ().getStart ()) + && + (!_this.isChapterItemEditVisible ()) + && + (_this.isReadyForUse ()) + ) + { + + this.showAddNewComment (this.editor.getSelection ().getStart ()); + + } + + })); + +/* + this.iconColumn = new IconColumn (this, + c, + this.projectViewer.getIconProvider (), + this.projectViewer.getChapterItemViewPopupProvider ()); + + this.iconColumn.addMouseListener (new MouseEventHandler () + { + + public void handleDoublePress (MouseEvent ev) + { + + _this.getActionListenerForTextPosition (NEW_COMMENT_ACTION_NAME, + ev.getPoint ()).actionPerformed (new ActionEvent (_this, 1, "show")); + + } + + }); +*/ + + //this.chItemTransferHandler = new ChapterItemTransferHandler (this.getIconColumn ()); + + //this.setTransferHandler (this.chItemTransferHandler); +/* + this.actions.put (REMOVE_EDIT_POINT_ACTION_NAME, + new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + _this.removeEditPosition (); + + } + + }); + + this.actions.put (SET_EDIT_COMPLETE_ACTION_NAME, + new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + _this.setEditComplete (true); + + } + + }); + + this.actions.put (NEW_COMMENT_ACTION_NAME, + new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + _this.performAction (ev, + NEW_COMMENT_ACTION_NAME, + -1); + + } + + }); + + this.actions.put (CHAPTER_INFO_ACTION_NAME, + new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + try + { + + _this.projectViewer.viewEditorChapterInformation (_this.obj); + + } catch (Exception e) + { + + Environment.logError ("Unable to show chapter information for: " + + _this.obj, + e); + + UIUtils.showErrorMessage (_this, + getUIString (editors,project,LanguageStrings.actions,showchapterinfo,actionerror)); + //Environment.replaceObjectNames ("Unable to show {chapter}.")); + + } + + } + + }); +*/ +/* + InputMap im = this.editor.getInputMap (JComponent.WHEN_IN_FOCUSED_WINDOW); + + // Remove ctrl+shift+O from the when_focused set since it conflicts. + this.editor.getInputMap (JComponent.WHEN_FOCUSED).put (KeyStroke.getKeyStroke ("ctrl shift O"), + "none"); + + im.put (KeyStroke.getKeyStroke ("ctrl shift C"), + NEW_COMMENT_ACTION_NAME); + + this.highlight = new BlockPainter (UIUtils.getHighlightColor ()); +*/ + } + + public void recreateVisibleParagraphs () + { + + int s = this.editor.getVisibleParagraphs ().size (); + + IntStream.range (0, + s) + .forEach (i -> + { + + if (i < s) + { + + this.editor.recreateParagraphGraphic (this.editor.visibleParToAllParIndex (i)); + + } + + }); + + } + + public void setChapterItemEditVisible (boolean v) + { + + this.chapterItemEditVisible = v; + + } + + public boolean isChapterItemEditVisible () + { + + return this.chapterItemEditVisible; + + } +/* + public int getTextPositionForMousePosition (Point p) + { + + Point pp = p; + + if (this.iconColumn.getMousePosition () != null) + { + + pp = new Point (0, + p.y); + + } + + return this.editor.viewToModel (pp); + + } +*/ +/* + public ActionListener getActionListenerForTextPosition (final String actionName, + final Point p) + { + + final EditorChapterPanel _this = this; + + final int pos = this.getTextPositionForMousePosition (p); + + return new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + _this.performAction (ev, + actionName, + pos); + + } + + }; + + } +*/ +/* + public ChapterItemTransferHandler getChapterItemTransferHandler () + { + + return this.chItemTransferHandler; + + } +*/ +/* + public int getIconColumnXOffset (ChapterItem i) + { + + int xOffset = 22; + + if (i instanceof OutlineItem) + { + + xOffset = 22; + + } + + return xOffset; + + } +*/ +/* + public JComponent getEditorWrapper (QTextEditor q) + { + + Box b = new Box (BoxLayout.X_AXIS); + b.add (this.iconColumn); + b.add (q); + q.setMaximumSize (new Dimension (Integer.MAX_VALUE, Integer.MAX_VALUE)); + + q.setMinimumSize (new Dimension (200, 200)); + q.setAlignmentY (Component.TOP_ALIGNMENT); + q.setAlignmentX (Component.LEFT_ALIGNMENT); + + this.iconColumn.setAlignmentY (Component.TOP_ALIGNMENT); + this.iconColumn.setAlignmentX (Component.LEFT_ALIGNMENT); + this.iconColumn.setMinimumSize (new Dimension (32, 200)); + this.iconColumn.setPreferredSize (new Dimension (32, 200)); + this.iconColumn.setMaximumSize (new Dimension (32, Integer.MAX_VALUE)); + + JPanel p = new ScrollablePanel (new BorderLayout ()); + p.add (b); + + return p; + + } +*/ + @Override + public Set getToolBarItems () + { + + Set its = new LinkedHashSet<> (); + + its.add (QuollButton.builder () + .tooltip (editors,project,commentspanel,toolbar,newcomment,tooltip) + .iconName (StyleClassNames.COMMENT) + /* + TODO + .accelerator (new KeyCodeCombination (KeyCode.C, + KeyCombination.SHORTCUT_DOWN, + KeyCombination.SHIFT_DOWN)) + */ + .onAction (ev -> + { + + int s = 0; + + if (this.editor.getSelection () != null) + { + + s = this.editor.getSelection ().getStart (); + + } + + this.showAddNewComment (s); + + }) + .build ()); + + its.add (QuollButton.builder () + .tooltip (editors,project,commentspanel,toolbar,textproperties,tooltip) + .iconName (StyleClassNames.EDITPROPERTIES) + .onAction (ev -> + { + + this.viewer.runCommand (EditorProjectViewer.CommandId.textproperties); + + }) + .build ()); + + return its; + + } +/* + public void removeItem (ChapterItem c) + { + + this.iconColumn.removeItem (c); + + } + + public void addItem (ChapterItem c) + throws GeneralException + { + + this.iconColumn.addItem (c); + + } + + public void scrollToItem (ChapterItem i) + throws GeneralException + { + + this.scrollToPosition (i.getPosition ()); + + } +*/ +/* + public void editNote (Note n) + throws GeneralException + { + + this.scrollToNote (n); + + new CommentActionHandler (n, + this).actionPerformed (new ActionEvent (this, + 0, + "edit")); + + } +*/ + @Override + public void showItem (ChapterItem item, + boolean showAllForLine) + { + + Note n = (Note) item; + + Note top = n; + Set items = null; + + if (showAllForLine) + { + + items = this.getNotesForPosition (item.getPosition ()); + + if (items.size () == 0) + { + + return; + + } + + top = items.iterator ().next (); + + } else { + + items = new LinkedHashSet<> (); + items.add (n); + + } + + QuollPopup qp = this.viewer.getPopupById (ViewCommentPopup.getPopupIdForComment (top)); + + if (qp != null) + { + + qp.toFront (); + return; + + } + + qp = new ViewCommentPopup (this.viewer, + items, + true).getPopup (); + + this.showPopupForItem (top, + qp); + + } + + public void removeItemHighlightTextFromEditor (ChapterItem it) + { + + this.editor.removeHighlight (this.highlight); + + } + + public void highlightItemTextInEditor (ChapterItem it) + { + + this.editor.removeHighlight (this.highlight); + + this.highlight = this.editor.addHighlight (new IndexRange (it.getStartPosition (), + it.getEndPosition ()), + UserProperties.getEditorCommentChapterHighlightColor ()); + + } + +/* + public void scrollToNote (Note n) + throws GeneralException + { + + this.scrollToPosition (n.getPosition ()); + + } +*/ + @Override + public void init (State s) + throws GeneralException + { + + super.init (s); + + this.editor.getCaretSelectionBind ().moveTo (0); + + this.setReadyForUse (); + + } +/* + public void restoreBackgroundColor () + { + + super.restoreBackgroundColor (); + + //this.iconColumn.setBackground (IconColumn.defaultBGColor); + + } +*/ + //public void setBackgroundColor (Color c) + //{ + + // super.setBackgroundColor (c); +/* + if (c.equals (Color.white)) + { + + this.iconColumn.setBackground (IconColumn.defaultBGColor); + + } else + { + + this.iconColumn.setBackground (c); + + } +*/ + //} +/* + private void setContextMenu () + { + + Set items = new LinkedHashSet<> (); + + if (this.editor.getProperties ().get ("context-menu") != null) + { + + ((ContextMenu) this.editor.getProperties ().get ("context-menu")).hide (); + + } + + ContextMenu cm = new ContextMenu (); + cm.getItems ().addAll (items); + + boolean compress = UserProperties.getAsBoolean (Constants.COMPRESS_CHAPTER_CONTEXT_MENU_PROPERTY_NAME); + + cm.getItems ().addAll (this.getContextMenuItems (compress)); + + this.editor.setContextMenu (cm); + + this.editor.getProperties ().put ("context-menu", cm); + cm.setAutoFix (true); + cm.setAutoHide (true); + cm.setHideOnEscape (true); + + } +*/ + + @Override + public Boolean canDrag (ChapterItem ci) + { + + return false; + + } + + @Override + public Set getContextMenuItems (boolean compress) + { + + Set ret = new LinkedHashSet<> (); + + int pos = this.editor.getTextPositionForCurrentMousePosition (); + + // This is needed to move to the correct character, the call above seems to get the character + // before what was clicked on. + // pos++; + List prefix = Arrays.asList (editors,project,commentspanel,popupmenu,Chapter.OBJECT_TYPE); + + if (compress) + { + + List row1 = new ArrayList<> (); + + row1.add (QuollButton.builder () + .iconName (StyleClassNames.EDITPROPERTIES) + .tooltip (getUILanguageStringProperty (Utils.newList (prefix,items,textproperties,tooltip))) + .onAction (ev -> + { + + this.viewer.runCommand (EditorProjectViewer.CommandId.textproperties); + + }) + .build ()); + + row1.add (QuollButton.builder () + .iconName (StyleClassNames.FIND) + .tooltip (getUILanguageStringProperty (Utils.newList (prefix,items,find,tooltip))) + .onAction (ev -> + { + + this.viewer.runCommand (EditorProjectViewer.CommandId.find); + + }) + .build ()); + + List row2 = new ArrayList<> (); + + row2.add (QuollButton.builder () + .iconName (StyleClassNames.SETEDITPOSITION) + .tooltip (getUILanguageStringProperty (Utils.newList (prefix,items,seteditposition,tooltip))) + .onAction (ev -> + { + + this.viewer.setChapterEditPosition (this.object, + pos); + + this.recreateVisibleParagraphs (); + + }) + .build ()); + + if (this.object.getEditPosition () > 0) + { + + row2.add (QuollButton.builder () + .iconName (StyleClassNames.GOTOEDITPOSITION) + .tooltip (getUILanguageStringProperty (Utils.newList (prefix,items,gotoeditposition,tooltip))) + .onAction (ev -> + { + + this.editor.moveTo (this.object.getEditPosition ()); + this.editor.requestFollowCaret (); + + }) + .build ()); + + row2.add (QuollButton.builder () + .iconName (StyleClassNames.REMOVEEDITPOSITION) + .tooltip (getUILanguageStringProperty (Utils.newList (prefix,items,removeeditposition,tooltip))) + .onAction (ev -> + { + + this.viewer.removeChapterEditPosition (this.object); + + this.recreateVisibleParagraphs (); + + }) + .build ()); + + } + + if (!this.object.isEditComplete ()) + { + + row2.add (QuollButton.builder () + .iconName (StyleClassNames.EDITCOMPLETE) + .tooltip (getUILanguageStringProperty (Utils.newList (prefix,items,seteditcomplete,tooltip))) + .onAction (ev -> + { + + this.viewer.setChapterEditComplete (this.object, + true); + + IntStream.range (0, + this.editor.getVisibleParagraphs ().size ()) + .forEach (i -> + { + + this.editor.recreateParagraphGraphic (this.editor.visibleParToAllParIndex (i)); + + }); + + }) + .build ()); + + } + + CustomMenuItem n = UIUtils.createCompressedMenuItem (getUILanguageStringProperty (editors,project,commentspanel,popupmenu,Chapter.OBJECT_TYPE,compresstext), + row1, + row2); + + ret.add (n); + + } else { + + ret.add (QuollMenuItem.builder () + .iconName (StyleClassNames.SETEDITPOSITION) + .label (getUILanguageStringProperty (Utils.newList (prefix,items,seteditposition,text))) + .onAction (ev -> + { + + this.viewer.setChapterEditPosition (this.object, + pos); + + IntStream.range (0, + this.editor.getVisibleParagraphs ().size ()) + .forEach (i -> + { + + this.editor.recreateParagraphGraphic (this.editor.visibleParToAllParIndex (i)); + + }); + + }) + .build ()); + + if (this.object.getEditPosition () > 0) + { + + ret.add (QuollMenuItem.builder () + .iconName (StyleClassNames.GOTOEDITPOSITION) + .label (getUILanguageStringProperty (Utils.newList (prefix,items,gotoeditposition,text))) + .onAction (ev -> + { + + this.editor.moveTo (this.object.getEditPosition ()); + this.editor.requestFollowCaret (); + + }) + .build ()); + + ret.add (QuollMenuItem.builder () + .iconName (StyleClassNames.REMOVEEDITPOSITION) + .label (getUILanguageStringProperty (Utils.newList (prefix,items,removeeditposition,text))) + .onAction (ev -> + { + + this.viewer.removeChapterEditPosition (this.object); + + IntStream.range (0, + this.editor.getVisibleParagraphs ().size ()) + .forEach (i -> + { + + this.editor.recreateParagraphGraphic (this.editor.visibleParToAllParIndex (i)); + + }); + + }) + .build ()); + + } + + if (!this.object.isEditComplete ()) + { + + ret.add (QuollMenuItem.builder () + .iconName (StyleClassNames.EDITCOMPLETE) + .label (getUILanguageStringProperty (Utils.newList (prefix,items,seteditcomplete,text))) + .onAction (ev -> + { + + this.viewer.setChapterEditComplete (this.object, + true); + + }) + .build ()); + + } else { + + ret.add (QuollMenuItem.builder () + .iconName (StyleClassNames.EDITNEEDED) + .label (getUILanguageStringProperty (Utils.newList (prefix,items,seteditneeded,text))) + .onAction (ev -> + { + + this.viewer.setChapterEditComplete (this.object, + false); + + }) + .build ()); + + } + + } + + return ret; + + } + + public void editComment (Note n) + { + + QuollPopup qp = this.viewer.getPopupById (AddEditCommentPopup.getPopupIdForComment (n)); + + if (qp != null) + { + + qp.toFront (); + return; + + } + + qp = new AddEditCommentPopup (this.viewer, + this.object, + n).getPopup (); + + this.showPopupForItem (n, + qp); + + } + + public void showDeleteCommentPopup (Note n, + Node showAt) + { + + QuollPopup.questionBuilder () + .title (comments,delete,popup,title) + .inViewer (this.viewer) + .styleClassName (StyleClassNames.DELETE) + .message (getUILanguageStringProperty (Arrays.asList (comments,delete,popup,text), + n.getSummary ())) + .confirmButtonLabel (comments,delete,popup,buttons,confirm) + .cancelButtonLabel (comments,delete,popup,buttons,cancel) + .onConfirm (ev -> + { + + try + { + + this.viewer.deleteObject (n, + false); + + } catch (Exception e) + { + + Environment.logError ("Unable to delete comment: " + + n, + e); + + ComponentUtils.showErrorMessage (this.viewer, + getUILanguageStringProperty (comments,delete,actionerror)); + //"Unable to delete."); + + } + + + }) + .showAt (showAt, Side.BOTTOM) + .build (); + + } + + public void showAddNewComment (int pos) + { + + Note item = new Note (); + item.setPosition (pos); + item.setType (Note.EDIT_NEEDED_NOTE_TYPE); + + // Here we generate a bogus negative key so that the hashCode/equals still works. + item.setKey (-1 * System.currentTimeMillis ()); + + this.addNewItem (item); + + AddEditCommentPopup p = new AddEditCommentPopup (this.viewer, + this.object, + item); + p.setOnCancel (ev -> + { + + //this.getParagraphIconMargin (item).removeItem (item); + this.newItems.remove (item); + + this.editor.recreateParagraphGraphic (this.editor.getParagraphForOffset (item.getPosition ())); + + }); + + p.setOnClose (() -> + { + + //this.getParagraphIconMargin (item).removeItem (item); + this.newItems.remove (item); + + int ind = this.editor.getParagraphForOffset (item.getPosition ()); + + if (ind > -1) + { + + this.editor.recreateParagraphGraphic (ind); + + } + + }); + + UIUtils.forceRunLater (() -> + { + + this.editor.recreateParagraphGraphic (this.editor.getParagraphForOffset (item.getPosition ())); + + }); + + QuollPopup qp = p.getPopup (); + + UIUtils.forceRunLater (() -> + { + + this.showPopupForItem (item, + qp); + + }); + + } + + @Override + public Map getActionMappings () + { + + return new HashMap<> (); + + } + + public Set getNotesForPosition (int p) + { + + Bounds cb = this.editor.getBoundsForPosition (p); + + if (cb == null) + { + + return new HashSet<> (); + + } + + int paraNo = this.editor.getParagraphForOffset (p); + + double y = cb.getMinY (); + + Set ret = new TreeSet<> (new ChapterItemSorter ()); + + ret.addAll (this.object.getNotes ().stream () + // Only interested in those that have the same y value. i.e. on the same line. + .filter (i -> + { + + // See if we are in the same paragraph. + if (this.editor.getParagraphForOffset (i.getPosition ()) != paraNo) + { + + return false; + + } + + Bounds b = this.editor.getBoundsForPosition (i.getPosition ()); + + return (b != null) && b.getMinY () == y; + + }) + .collect (Collectors.toSet ())); + + return ret; + + } + + @Override + public Node getMarginNodeForChapterItem (ChapterItem ci) + { + + if (ci instanceof Note) + { + + Note n = (Note) ci; + + IconBox riv = IconBox.builder () + .iconName (StyleClassNames.COMMENT) + .build (); + + riv.setOnMouseDragged (ev -> + { + + riv.requestFocus (); + + }); + riv.setOnMouseClicked (ev -> + { + + if (ev.getButton () != MouseButton.PRIMARY) + { + + return; + + } + + this.showItem (n, + true); + + ev.consume (); + + }); + + return riv; + + } + + throw new UnsupportedOperationException ("Object not supported: " + ci); + + } + + @Override + public Set getMarginContextMenuItems (int cpos) + { + + List prefix = Arrays.asList (iconcolumn,doubleclickmenu,items); + + Set items = new LinkedHashSet<> (); + + items.add (QuollMenuItem.builder () + .label (getUILanguageStringProperty (Utils.newList (prefix,comment))) + .iconName (StyleClassNames.COMMENT) + .accelerator (new KeyCharacterCombination ("C", + KeyCombination.SHORTCUT_DOWN, + KeyCombination.SHIFT_DOWN)) + .onAction (eev -> + { + + this.showAddNewComment (this.editor.getSelection ().getStart ()); + + }) + .build ()); + + return items; + + } + +} diff --git a/src/com/quollwriter/editors/ui/panels/RegisterAsAnEditorPanel.java b/src/main/java/com/quollwriter/editors/ui/panels/RegisterAsAnEditorPanel.java similarity index 88% rename from src/com/quollwriter/editors/ui/panels/RegisterAsAnEditorPanel.java rename to src/main/java/com/quollwriter/editors/ui/panels/RegisterAsAnEditorPanel.java index 43f8ac5d..3c9809f2 100644 --- a/src/com/quollwriter/editors/ui/panels/RegisterAsAnEditorPanel.java +++ b/src/main/java/com/quollwriter/editors/ui/panels/RegisterAsAnEditorPanel.java @@ -30,7 +30,6 @@ import javax.swing.text.*; import javax.swing.undo.*; import javax.imageio.*; -import javax.activation.*; import com.gentlyweb.properties.*; @@ -66,20 +65,20 @@ public class RegisterAsAnEditorPanel extends QuollPanel private SelectFormItem genresF = null; private CheckboxFormItem typesF = null; private ImageSelectorFormItem avatarF = null; - + private Map formItems = new LinkedHashMap (); - + public RegisterAsAnEditorPanel (AbstractViewer pv) throws GeneralException { super (pv); - + } - + public void close () { - + } public boolean saveUnsavedChanges () @@ -97,7 +96,7 @@ public String getPanelId () return RegisterAsAnEditorPanel.PANEL_ID; } - + public void init () throws GeneralException { @@ -109,71 +108,71 @@ public void init () Constants.EDIT_ICON_NAME, null); this.add (h); - + EditorsWebServiceHandler wsHandler = EditorsEnvironment.getEditorsWebServiceHandler (); - + EditorAccount acc = EditorsEnvironment.getUserAccount (); - + EditorEditor ed = null; - + String email = null; String pass = null; - + if (acc != null) { - + email = acc.getEmail (); - + ed= acc.getEditor (); - + } - + String yourName = null; File avatarFile = null; String about = null; Set selectedGenres = null; Set selectedTypes = null; - + if (ed != null) { - + yourName = ed.getName (); - + DataSource ds = null; //ed.getAvatar (); - + if (ds != null) { - + if (!(ds instanceof FileDataSource)) { - + Environment.logError ("Illegal data source type for editor avatar image: " + ds.getClass ().getName ()); - + } else { - + avatarFile = ((FileDataSource) ds).getFile (); - + } } - + about = ed.getAbout (); selectedGenres = ed.getGenres (); selectedTypes = EditorProject.WordCountLength.getDescriptions (ed.getWordCountLengths ()); - + } - + final Box box = new ScrollableBox (BoxLayout.Y_AXIS); box.setAlignmentX (Component.LEFT_ALIGNMENT); - + box.add (this.createHeader (Environment.replaceObjectNames ("Types of things you are interested in editing"))); - + Vector gitems = new Vector (EditorsEnvironment.getWritingGenres ()); - + gitems.add (0, "Any"); - + this.genresF = new SelectFormItem ("Genres", gitems, 5, @@ -191,13 +190,13 @@ public void init () typeVals.add (EditorProject.WordCountLength.novelette.getDescription ());//"Novellette (7,500 to 17,5000 words"); typeVals.add (EditorProject.WordCountLength.novella.getDescription ());//"Novella (17,500 to 40,000 words"); typeVals.add (EditorProject.WordCountLength.novel.getDescription ());//"Novel (over 40,000 words"); - + this.typesF = new CheckboxFormItem ("{Project} lengths", typeVals, selectedTypes, false, "Select the lengths of project you are prepared to edit."); - + this.formItems.put ("types", this.typesF); @@ -205,8 +204,8 @@ public void init () box.add (this.createHeader (Environment.replaceObjectNames ("About you"))); Box aboutBox = new Box (BoxLayout.Y_AXIS); - aboutBox.setAlignmentX (Component.LEFT_ALIGNMENT); - + aboutBox.setAlignmentX (Component.LEFT_ALIGNMENT); + this.nameF = new TextFormItem ("Your name", false, 1, @@ -225,7 +224,7 @@ public void init () fileTypes.add ("jpeg"); fileTypes.add ("png"); fileTypes.add ("gif"); - + this.avatarF = new ImageSelectorFormItem ("Your picture/avatar", fileTypes, avatarFile, @@ -235,65 +234,65 @@ public void init () this.avatarF.getImageSelector ().addChangeListener (new ChangeListener () { - + public void stateChanged (ChangeEvent ev) { - + File f = _this.avatarF.getImageSelector ().getFile (); if (f != null) { - + try { - + // Get the first image, check for animated gif. if (UIUtils.isAnimatedGif (f)) { - + UIUtils.showErrorMessage (_this, "Sorry animated gifs are not supported."); - + _this.avatarF.getImageSelector ().setFile (null); - + return; - + } - + BufferedImage im = UIUtils.getScaledImage (f, 300); - + ByteArrayOutputStream bout = new ByteArrayOutputStream (); - + ImageIO.write (im, Utils.getFileType (f), bout); - + String s = Base64.encodeBytes (bout.toByteArray ()); - + if (s.length () > EditorsWebServiceHandler.MAX_IMAGE_SIZE) { - + UIUtils.showErrorMessage (_this, "Sorry your image/avatar is too large."); - + } } catch (Exception e) { - + Environment.logError ("Unable to check image file: " + f, e); - + } } - + } - + }); - + this.formItems.put ("avatar", this.avatarF); - + aboutBox.add (this.avatarF); this.aboutF = new TextFormItem ("About you", @@ -308,11 +307,11 @@ public void stateChanged (ChangeEvent ev) this.formItems.put ("about", this.aboutF); aboutBox.add (this.aboutF); - + box.add (aboutBox); - + box.add (this.createHeader (Environment.replaceObjectNames ("Login details"))); - + box.add (this.createHelpText ("In order to communicate with authors you need to create an account with us. Please provide an email address and a password.")); this.emailF = new TextFormItem ("Email", @@ -323,7 +322,7 @@ public void stateChanged (ChangeEvent ev) "chars", true, null); - + this.formItems.put ("email", this.emailF); box.add (this.emailF); @@ -338,39 +337,39 @@ public void stateChanged (ChangeEvent ev) null); this.formItems.put ("pass", this.passF); - + box.add (this.passF); box.add (this.createHeader (Environment.replaceObjectNames ("Ready to go?"))); - + box.add (this.createHelpText ("Ready to go???")); JButton[] buts = new JButton[2]; - + buts[0] = new JButton ("Advertise"); - + buts[0].addActionListener (new ActionAdapter () { - + public void actionPerformed (ActionEvent ev) { - + _this.createAccount (); - + } - + }); - + buts[1] = new JButton ("Cancel"); - + JPanel bp = UIUtils.createButtonBar2 (buts, Component.LEFT_ALIGNMENT); //ButtonBarFactory.buildLeftAlignedBar (buts); bp.setOpaque (false); - + box.add (this.setAsSubItem (bp)); box.add (Box.createVerticalStrut (15)); - + box.setBorder (null); box.add (Box.createVerticalGlue ()); box.setMaximumSize (new Dimension (500, @@ -386,105 +385,105 @@ public void actionPerformed (ActionEvent ev) lscroll.getVerticalScrollBar ().addAdjustmentListener (new AdjustmentListener () { - + public void adjustmentValueChanged (AdjustmentEvent ev) { - + if (lscroll.getVerticalScrollBar ().getValue () > 0) { - + lscroll.setBorder (new MatteBorder (1, 0, 0, 0, UIUtils.getInnerBorderColor ())); } else { - + lscroll.setBorder (new EmptyBorder (1, 0, 0, 0)); - + } - + } - + }); - + box.setBorder (new EmptyBorder (5, 10, 10, 10)); - + this.add (lscroll); - + for (FormItem it : this.formItems.values ()) { - + it.init (); - + } SwingUtilities.invokeLater (new Runnable () { - + public void run () { - + lscroll.getVerticalScrollBar ().setValue (0); - + } - + }); */ } private void createAccount () { - + FormItem error = null; - + for (FormItem it : this.formItems.values ()) { - + //it.setError (false); - + if (it.hasError ()) { - + //it.updateRequireLabel (); - + //it.setError (true); - + if (error == null) { error = it; - + } } - + } - + if (error != null) { - + //error.scrollIntoView (); return; - + } - + final RegisterAsAnEditorPanel _this = this; - + new Thread (new Runnable () { - + public void run () { /* try { - + // Wipe out any existing image file. EditorsEnvironment.getEditorsEditorAvatarImageFile ().delete (); - -System.out.println ("SAVING ACCOUNT"); + +System.out.println ("SAVING ACCOUNT"); EditorsWebServiceHandler h = EditorsEnvironment.getEditorsWebServiceHandler (); - + //h.saveAccount (_this.emailF.getValue (), // _this.passF.getValue ()); @@ -498,51 +497,51 @@ public void run () System.out.println ("CREATED/SAVED EDITOR"); } catch (Exception e) { - + UIUtils.showErrorMessage (_this, "Sorry, unable to create/update your information at the moment. Please try again later."); - + Environment.logError ("Unable to create/update editor", e); - + } - */ + */ } - + }).start (); - + } - + private JComponent setAsSubItem (JComponent c) { c.setAlignmentX (Component.LEFT_ALIGNMENT); - c.setAlignmentY (Component.TOP_ALIGNMENT); - + c.setAlignmentY (Component.TOP_ALIGNMENT); + c.setBorder (new CompoundBorder (new EmptyBorder (0, 5, 0, 0), c.getBorder ())); - + return c; - + } private Header createHeader (String title) { - + Header h = UIUtils.createHeader (title, Constants.SUB_PANEL_TITLE); - - h.setBorder (new CompoundBorder (new MatteBorder (0, 0, 1, 0, Environment.getBorderColor ()), + + h.setBorder (new CompoundBorder (new MatteBorder (0, 0, 1, 0, UIUtils.getBorderColor ()), new EmptyBorder (0, 0, 3, 0))); h.setBorder (new CompoundBorder (new EmptyBorder (0, 0, 5, 0), h.getBorder ())); return h; - + } - + private JComponent createWrapper (JComponent c) { - + if (c instanceof JComboBox) { @@ -564,17 +563,17 @@ private JComponent createWrapper (JComponent c) _b.setAlignmentY (Component.TOP_ALIGNMENT); c = _b; - + } else { - + c.setBorder (new EmptyBorder (0, 5, 0, 0)); - + } - + return c; - + } - + private JTextPane createHelpText (String text) { @@ -590,7 +589,7 @@ private JTextPane createHelpText (String text) return t; } - + public void fillToolBar (JToolBar acts, final boolean fullScreen) { @@ -602,12 +601,12 @@ public void saveObject () { } - + public void fillPopupMenu (final MouseEvent ev, final JPopupMenu popup) { - + } public void setState (final Map s, @@ -642,11 +641,11 @@ public void refresh (NamedObject n) @Override public String getTitle () { - + return "Register as an Editor"; - + } - + @Override public ImageIcon getIcon (int type) { @@ -655,7 +654,7 @@ public ImageIcon getIcon (int type) type); } - + public JScrollPane getScrollPane () { diff --git a/src/com/quollwriter/editors/ui/sidebars/EditorFindInfoBox.java b/src/main/java/com/quollwriter/editors/ui/sidebars/EditorFindInfoBox.java similarity index 85% rename from src/com/quollwriter/editors/ui/sidebars/EditorFindInfoBox.java rename to src/main/java/com/quollwriter/editors/ui/sidebars/EditorFindInfoBox.java index 0272b3cb..126e4e35 100644 --- a/src/com/quollwriter/editors/ui/sidebars/EditorFindInfoBox.java +++ b/src/main/java/com/quollwriter/editors/ui/sidebars/EditorFindInfoBox.java @@ -18,61 +18,62 @@ public class EditorFindInfoBox extends Box { - + private EditorEditor editor = null; - + public EditorFindInfoBox (EditorEditor ed) { - + super (BoxLayout.X_AXIS); - + this.editor = ed; - - if (ed.getAvatar () != null) + + if (ed.getMainAvatar () != null) { - +/* +TODO Remove BufferedImage bi = UIUtils.getScaledImage (ed.getAvatar (), 50, 50); - + JLabel il = new JLabel (new ImageIcon (bi)); il.setAlignmentY (Component.TOP_ALIGNMENT); - + this.add (il); il.setOpaque (false); - + il.setBorder (new MatteBorder (1, 1, 1, 1, - Environment.getBorderColor ())); + UIUtils.getBorderColor ())); this.add (Box.createHorizontalStrut (5)); - +*/ } - + Box details = new Box (BoxLayout.Y_AXIS); details.setAlignmentY (Component.TOP_ALIGNMENT); - + Box nameBox = new Box (BoxLayout.X_AXIS); details.add (nameBox); nameBox.setAlignmentX (Component.LEFT_ALIGNMENT); nameBox.add (this.getNameLabel (ed.getName ())); - + //details.add (Box.createVerticalStrut (3)); - + this.add (details); final EditorFindInfoBox _this = this; - + this.addMouseListener (new MouseEventHandler () { - + public void handlePress (MouseEvent ev) { - + if (ev.isPopupTrigger ()) { - + // Show the menu. JPopupMenu m = new JPopupMenu (); @@ -84,7 +85,7 @@ public void handlePress (MouseEvent ev) null); m.add (mi); - + m.add (mi); mi = UIUtils.createMenuItem ("Send invite", @@ -94,40 +95,40 @@ public void handlePress (MouseEvent ev) null); m.add (mi); - + Component c = (Component) ev.getSource (); - + m.show (c, ev.getX (), ev.getY ()); - + return; - + } - + } - + }); - + } - + private JLabel getNameLabel (String name) { - + JLabel l = new JLabel (name); l.setFont (l.getFont ().deriveFont (16f)); l.setAlignmentY (Component.TOP_ALIGNMENT); l.setVerticalAlignment (SwingConstants.TOP); - + return l; - + } - + public void init () { - - - + + + } - -} \ No newline at end of file + +} diff --git a/src/com/quollwriter/editors/ui/sidebars/EditorFindPanel.java b/src/main/java/com/quollwriter/editors/ui/sidebars/EditorFindPanel.java similarity index 78% rename from src/com/quollwriter/editors/ui/sidebars/EditorFindPanel.java rename to src/main/java/com/quollwriter/editors/ui/sidebars/EditorFindPanel.java index 5435a238..39c66260 100644 --- a/src/com/quollwriter/editors/ui/sidebars/EditorFindPanel.java +++ b/src/main/java/com/quollwriter/editors/ui/sidebars/EditorFindPanel.java @@ -1,53 +1,44 @@ package com.quollwriter.editors.ui.sidebars; -import java.awt.Component; -import java.awt.event.*; -import javax.swing.event.*; +import java.util.*; -import java.util.Set; -import java.util.Vector; - -import javax.swing.*; -import javax.swing.border.*; +import javafx.scene.layout.*; import com.quollwriter.*; -import com.quollwriter.ui.*; -import com.quollwriter.ui.forms.*; -import com.quollwriter.ui.components.ScrollableBox; -import com.quollwriter.ui.components.ActionAdapter; import com.quollwriter.data.editors.*; -import com.quollwriter.ui.sidebars.*; +import com.quollwriter.ui.fx.sidebars.*; +import com.quollwriter.ui.fx.components.*; import com.quollwriter.editors.*; -public class EditorFindPanel extends Box +public class EditorFindPanel extends VBox { - + private EditorsSideBar sideBar = null; private AccordionItem matchesBox = null; - private JLabel loading = null; - + //private JLabel loading = null; + public EditorFindPanel (EditorsSideBar sb) { - - super (BoxLayout.Y_AXIS); - + + //super (BoxLayout.Y_AXIS); + this.sideBar = sb; - - Box b = new ScrollableBox (BoxLayout.Y_AXIS); + + //Box b = new ScrollableBox (BoxLayout.Y_AXIS); EditorProject proj = null;//this.sideBar.getProjectViewer ().getProject ().getEditorProject (); -/* +/* Set selectedGenres = null; - + if (proj != null) { - + selectedGenres = proj.getGenres (); } - + Box crit = new Box (BoxLayout.Y_AXIS); - + TextFormItem nameF = new TextFormItem ("Name", false, 1, @@ -60,7 +51,7 @@ public EditorFindPanel (EditorsSideBar sb) crit.add (nameF); Vector gitems = new Vector (EditorsEnvironment.getWritingGenres ()); - + SelectFormItem genreF = new SelectFormItem ("Genre", gitems, 5, @@ -74,37 +65,37 @@ public EditorFindPanel (EditorsSideBar sb) AccordionItem ai = new AccordionItem ("Find Editors by", null, crit); - + b.add (ai); ai.init (); ai.setAlignmentX (Component.LEFT_ALIGNMENT); //this.add (ai); - + b.add (Box.createVerticalStrut (5)); - + final EditorFindPanel _this = this; - + JButton find = UIUtils.createButton (Constants.FIND_ICON_NAME, Constants.ICON_MENU, "Click to find editors", new ActionAdapter () { - + public void actionPerformed (ActionEvent ev) { - + _this.doSearch (); - + } - + }); - + find.setText ("Find Editors"); - + b.add (find); - + b.add (Box.createVerticalStrut (10)); - + Box matches = new Box (BoxLayout.Y_AXIS); this.loading = new JLabel (Environment.getLoadingIcon ()); @@ -114,17 +105,17 @@ public void actionPerformed (ActionEvent ev) this.matchesBox = new AccordionItem ("Matches", null, matches); - + b.add (this.matchesBox); this.matchesBox.init (); this.matchesBox.setAlignmentX (Component.LEFT_ALIGNMENT); - + this.matchesBox.setVisible (false); - + b.add (UIUtils.createOpaqueGlue (BoxLayout.Y_AXIS)); JScrollPane sp = new JScrollPane (b); - + sp.setOpaque (false); sp.setAlignmentX (Component.LEFT_ALIGNMENT); sp.setBorder (new EmptyBorder (0, 0, 0, 0)); @@ -132,35 +123,35 @@ public void actionPerformed (ActionEvent ev) sp.getVerticalScrollBar ().setUnitIncrement (20); this.add (sp); - */ + */ } - + private void doSearch () { - + try { - + java.util.List eds = EditorsEnvironment.getEditorsWebServiceHandler ().findEditors (); - + //this.matchesBox.setContent (this.sideBar.createEditorsFindList (eds)); - this.matchesBox.setVisible (true); - - this.loading.setVisible (false); - + //this.matchesBox.setVisible (true); + + //this.loading.setVisible (false); + } catch (Exception e) { - + e.printStackTrace (); - + } - + } - + public void init () { - - + + } - + } diff --git a/src/com/quollwriter/editors/ui/sidebars/EditorList.java.old b/src/main/java/com/quollwriter/editors/ui/sidebars/EditorList.java.old similarity index 100% rename from src/com/quollwriter/editors/ui/sidebars/EditorList.java.old rename to src/main/java/com/quollwriter/editors/ui/sidebars/EditorList.java.old diff --git a/src/main/java/com/quollwriter/editors/ui/sidebars/EditorPanel.java b/src/main/java/com/quollwriter/editors/ui/sidebars/EditorPanel.java new file mode 100644 index 00000000..0ae31b56 --- /dev/null +++ b/src/main/java/com/quollwriter/editors/ui/sidebars/EditorPanel.java @@ -0,0 +1,629 @@ +package com.quollwriter.editors.ui.sidebars; + +import java.io.*; + +import java.util.*; +import java.util.concurrent.*; + +import javafx.scene.control.*; +import javafx.scene.layout.*; +import javafx.scene.*; + +import org.josql.*; + +import com.quollwriter.*; +import com.quollwriter.data.*; +import com.quollwriter.data.editors.*; +import com.quollwriter.editors.*; +import com.quollwriter.editors.ui.*; +import com.quollwriter.editors.messages.*; +import com.quollwriter.ui.fx.*; +import com.quollwriter.ui.fx.viewers.*; +import com.quollwriter.ui.fx.components.*; + +import static com.quollwriter.LanguageStrings.*; +import static com.quollwriter.uistrings.UILanguageStringsManager.getUILanguageStringProperty; + +public class EditorPanel extends VBox +{ + + private AbstractViewer viewer = null; + private EditorChatBox chatBox = null; + //private JTextArea message = null; + private boolean typed = false; + private EditorEditor editor = null; + private Map chatHistory = new TreeMap<> (); + private VBox chatHistoryBox = null; + /* + private JTextField find = null; + private Box findBox = null; + private Box findResults = null; + */ + private ScrollPane chatHistoryScrollPane = null; + + private ScheduledFuture dateLabelsUpdate = null; + private Project project = null; + private ProjectEditor projectEditor = null; + + //private boolean showChatBox = true; + + public EditorPanel (AbstractViewer viewer, + EditorEditor ed, + IPropertyBinder binder) + throws GeneralException + { + + if (!ed.messagesLoaded ()) + { + + EditorsEnvironment.loadMessagesForEditor (ed); + + } + + binder.addSetChangeListener (ed.getMessages (), + ev -> + { + + if (ev.wasRemoved ()) + { + + UIUtils.runLater (() -> + { + + this.removeMessage (ev.getElementRemoved ()); + + }); + + } + + if (ev.wasAdded ()) + { + + if (!EditorsUIUtils.getDefaultViewableMessageFilter ().accept (ev.getElementAdded ())) + { + + return; + + } + + UIUtils.runLater (() -> + { + + this.addMessage (ev.getElementAdded ()); + + }); + + return; + + } + + }); + + this.dateLabelsUpdate = Environment.schedule (() -> + { + + UIUtils.runLater (() -> + { + + for (Date d : this.chatHistory.keySet ()) + { + + this.chatHistory.get (d).updateHeaderTitle (); + + } + + }); + + }, + 60 * Constants.MIN_IN_MILLIS, + 60 * Constants.MIN_IN_MILLIS); + + this.viewer = viewer; + this.editor = ed; + + if (viewer instanceof AbstractProjectViewer) + { + + AbstractProjectViewer pv = (AbstractProjectViewer) viewer; + this.project = pv.getProject (); + this.projectEditor = this.project.getProjectEditor (this.editor); + + } + + Project np = null; + + EditorInfoBox infBox = new EditorInfoBox (this.editor, + this.viewer, + false, + binder); + + UIUtils.setTooltip (infBox, + getUILanguageStringProperty (editors,LanguageStrings.editor,view,info,tooltip,general)); + infBox.addFullPopupListener (); + + this.chatBox = new EditorChatBox (this.editor, + this.viewer); + + this.chatBox.managedProperty ().bind (this.chatBox.visibleProperty ()); + this.chatBox.setVisible (!this.editor.isPrevious ()); + + VBox chatBoxWrapper = new VBox (); + chatBoxWrapper.getStyleClass ().add ("chatbox-wrapper"); + chatBoxWrapper.getChildren ().add (this.chatBox); + + this.getChildren ().addAll (infBox, + this.createChatHistory (), + chatBoxWrapper); + + UIUtils.forceRunLater (() -> + { + + this.chatHistoryScrollPane.setVvalue (this.chatHistoryScrollPane.getVmax ()); + + }); + + } + + public void showChatBox () + { + + this.chatBox.requestFocus (); + + } + + public void removeMessage (EditorMessage mess) + { + + // Needed? + + } + + public void addMessage (EditorMessage mess) + { + + if (mess instanceof EditorChatMessage) + { + + EditorChatMessage cmess = (EditorChatMessage) mess; +/* +TODO? + if (this.isShowing ()) + { + + cmess.setDealtWith (true); + + try + { + + EditorsEnvironment.updateMessage (cmess); + + } catch (Exception e) { + + Environment.logError ("Unable to update message: " + + cmess, + e); + + } + + } +*/ + Date w = Utils.zeroTimeFields (cmess.getWhen ()); + + // See if we have a "today" history box. + ChatMessageAccordionItem it = this.chatHistory.get (w); + + Set messages = null; + + if (it == null) + { + + messages = new LinkedHashSet<> (); + messages.add (cmess); + + it = new ChatMessageAccordionItem (this.viewer, + w, + messages); + + this.chatHistoryBox.getChildren ().add (it.getAccordionItem ()); + + this.chatHistory.put (w, + it); + + } else { + + it.addMessage (cmess); + + } + + UIUtils.forceRunLater (() -> + { + + this.chatHistoryScrollPane.setVvalue (this.chatHistoryScrollPane.getVmax ()); + + }); + + } + + } + + public EditorEditor getEditor () + { + + return this.editor; + + } + + private Map> sortChatMessages (Set messages) + { + + Map> ret = new TreeMap<> (); + + if (messages == null) + { + + return ret; + + } + + for (EditorChatMessage m : messages) + { + + Date w = Utils.zeroTimeFields (m.getWhen ()); + + Set mess = ret.get (w); + + if (mess == null) + { + + mess = new LinkedHashSet<> (); + ret.put (w, + mess); + + } + + mess.add (m); + + } + + return ret; + + } +/* + private ChatMessageAccordionItem createChatMessages (Date d, + Set messages) + { + + ChatMessageAccordionItem it = new ChatMessageAccordionItem (this.viewer, + d, + messages); + + this.chatHistory.put (d, + it); + + return it; + + } +*/ +/* + public void showSearch () + { + + // TODO: Not sure about the best way for this since each message is a container around the actual text. + + if (true) + { + + return; + + } + + this.findBox.setVisible (true); + + this.find.selectAll (); + + this.find.grabFocus (); + + } +*/ +/* + private void search () + { + + String f = this.find.getText ().trim (); + + // Ask all messages. + Set matches = this.editor.getMessages (new EditorMessageFilter () + { + + public boolean accept (EditorMessage m) + { + + return true; + + } + + }); + + + } +*/ + private Node createChatHistory () + { + + this.chatHistoryBox = new VBox (); +/* + this.find = UIUtils.createSearchBox (750, + new ActionListener () + { + + public void actionPerformed (ActionEvent ev) + { + + _this.search (); + + } + + }); + + this.find.setMaximumSize (new Dimension (Short.MAX_VALUE, + this.find.getPreferredSize ().height)); + + this.findBox = new Box (BoxLayout.Y_AXIS); + this.findBox.add (this.find); + + this.findResults = new ScrollableBox (BoxLayout.Y_AXIS); + + this.findBox.add (this.findResults); + + this.findBox.setVisible (false); + + //card.add (this.findBox); +*/ + + ChatMessageAccordionItem hist = null; + + // Waaaay too much type information here... + // Sort the messages, if present, into date buckets. + + Set fmessages = new LinkedHashSet<> (); + + int undealtWithCount = 0; + + Project np = null; + + EditorMessageFilter filter = new DefaultEditorMessageFilter (np, + EditorChatMessage.MESSAGE_TYPE); + + for (EditorMessage m : this.editor.getMessages ()) + { + + if (filter.accept (m)) + { + + fmessages.add ((EditorChatMessage) m); + + } + + } + + Map> messages = this.sortChatMessages (fmessages); + + Set>> entries = messages.entrySet (); + + long dontShowBefore = System.currentTimeMillis () - (7 * 24 * 60 * 60 *1000); + + for (Map.Entry> en : entries) + { + + hist = new ChatMessageAccordionItem (this.viewer, + en.getKey (), + en.getValue ()); + + this.chatHistory.put (en.getKey (), + hist); + + this.chatHistoryBox.getChildren ().add (hist.getAccordionItem ()); + + if (en.getKey ().getTime () < (dontShowBefore)) + { + + hist.getAccordionItem ().setContentVisible (false); + + } + + } + + // Last one should always be visible regardless of age. + if (hist != null) + { + + hist.getAccordionItem ().setContentVisible (true); + + } + + this.chatHistoryScrollPane = new QScrollPane (this.chatHistoryBox); + VBox.setVgrow (this.chatHistoryScrollPane, + Priority.ALWAYS); + + return this.chatHistoryScrollPane; + + } + +/* +REMOVE + private void showMessagesInCard (String cardId, + String title, + String iconType, + String help, + Set messages, + boolean showAttentionBorder) + { + + final EditorPanel _this = this; + + try + { + + // Sort the messages in descending when order or newest first. + Query q = new Query (); + q.parse (String.format ("SELECT * FROM %s ORDER BY when DESC", + EditorMessage.class.getName ())); + + QueryResults qr = q.execute (messages); + + messages = new LinkedHashSet (qr.getResults ()); + + } catch (Exception e) { + + Environment.logError ("Unable to sort messages", + e); + + } + + Box b = new ScrollableBox (BoxLayout.Y_AXIS); + b.setAlignmentX (Component.LEFT_ALIGNMENT); + + for (EditorMessage m : messages) + { + + MessageBox mb = null; + + try + { + + mb = MessageBoxFactory.getMessageBoxInstance (m, + this.viewer); + //mb.setShowAttentionBorder (showAttentionBorder); + + mb.init (); + + } catch (Exception e) { + + Environment.logError ("Unable to get message box for message: " + + m, + e); + + } + + mb.setAlignmentX (Component.LEFT_ALIGNMENT); + + Box wb = new Box (BoxLayout.Y_AXIS); + wb.setAlignmentX (Component.LEFT_ALIGNMENT); + wb.setBorder (UIUtils.createPadding (0, 0, 10, 0)); + wb.add (mb); + + b.add (wb); + + } + + final JScrollPane sp = UIUtils.createScrollPane (b); + + sp.setBorder (null); + sp.setAlignmentX (Component.LEFT_ALIGNMENT); + sp.setBorder (new EmptyBorder (1, 0, 0, 0)); + + Box wrapper = new Box (BoxLayout.Y_AXIS); + wrapper.setAlignmentX (Component.LEFT_ALIGNMENT); + + Header h = new Header (title, + Environment.getIcon (iconType, + Constants.ICON_SIDEBAR), + null); + + JButton close = UIUtils.createButton (Constants.CLOSE_ICON_NAME, + Constants.ICON_MENU, + getUIString (actions,clicktoclose), + //"Click to close", + new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + _this.showChatHistory (); + + } + + }); + + List buts = new ArrayList (); + buts.add (close); + + h.setControls (UIUtils.createButtonBar (buts)); + + h.setFont (h.getFont ().deriveFont ((float) UIUtils.getScaledFontSize (14)).deriveFont (java.awt.Font.PLAIN)); + h.setAlignmentX (Component.LEFT_ALIGNMENT); + + wrapper.add (h); + + if (help != null) + { + + JLabel info = UIUtils.createInformationLabel (help); + info.setBorder (UIUtils.createPadding (0, 5, 5, 5)); + + wrapper.add (info); + + } + + wrapper.add (sp); + + sp.getVerticalScrollBar ().addAdjustmentListener (new AdjustmentListener () + { + + public void adjustmentValueChanged (AdjustmentEvent ev) + { + + if (sp.getVerticalScrollBar ().getValue () > 0) + { + + sp.setBorder (new MatteBorder (1, 0, 0, 0, + UIUtils.getInnerBorderColor ())); + + } else { + + sp.setBorder (new EmptyBorder (1, 0, 0, 0)); + + } + + } + + }); + + this.cards.add (wrapper, + cardId); + + ((CardLayout) this.cards.getLayout ()).show (this.cards, + cardId); + + UIUtils.doLater (new ActionListener () + { + + public void actionPerformed (ActionEvent ev) + { + + sp.getVerticalScrollBar ().setValue (0); + + } + + }); + + } + */ +/* + public boolean isShowChatBox () + { + + return this.showChatBox; + + } + + public void setShowChatBox (boolean v) + { + + this.showChatBox = v; + + } +*/ + +} diff --git a/src/main/java/com/quollwriter/editors/ui/sidebars/EditorProjectSideBar.java b/src/main/java/com/quollwriter/editors/ui/sidebars/EditorProjectSideBar.java new file mode 100644 index 00000000..c5d8cdd8 --- /dev/null +++ b/src/main/java/com/quollwriter/editors/ui/sidebars/EditorProjectSideBar.java @@ -0,0 +1,581 @@ +package com.quollwriter.editors.ui.sidebars; + +import java.util.*; +import javafx.beans.property.*; +import javafx.scene.layout.*; +import javafx.scene.*; +import javafx.geometry.*; +import javafx.scene.input.*; +import javafx.scene.control.*; +import javafx.collections.*; + +import org.josql.*; + +import com.quollwriter.*; +import com.quollwriter.ui.fx.*; +import com.quollwriter.data.*; +import com.quollwriter.data.editors.*; +import com.quollwriter.events.*; +import com.quollwriter.editors.ui.*; +import com.quollwriter.editors.*; +import com.quollwriter.ui.fx.components.*; +import com.quollwriter.ui.fx.sidebars.*; +import com.quollwriter.ui.fx.popups.*; + +import static com.quollwriter.LanguageStrings.*; +import static com.quollwriter.uistrings.UILanguageStringsManager.getUILanguageStringProperty; + +public class EditorProjectSideBar extends BaseSideBar +{ + + public static final String SIDEBAR_ID = "editorproject"; + + private EditorChaptersSidebarItem chapters = null; + private EditorInfoBox editorInfoBox = null; + private EditorEditor editor = null; + private VBox content = null; + private QuollHyperlink unsentLabel = null; + private QuollHyperlink otherVersionsLabel = null; + private ScrollPane sp = null; + + public EditorProjectSideBar (EditorProjectViewer v) + //throws GeneralException + { + + super (v); + + this.content = new VBox (); + VBox.setVgrow (this.content, + Priority.ALWAYS); + this.setContent (this.content); + + } +/* + @Override + public String getSideBarId () + { + + return SIDEBAR_ID; + + } +*/ + + @Override + public void init (State s) + { + + super.init (s); + + this.editor = this.viewer.getProject ().getForEditor (); + + this.editorInfoBox = new EditorInfoBox (this.editor, + this.viewer, + true, + this.getBinder ()); + this.editorInfoBox.addFullPopupListener (); + + this.content.getChildren ().add (this.editorInfoBox); + + VBox b = new VBox (); + this.content.getChildren ().add (b); + + ProjectVersion projVer = this.viewer.getProject ().getProjectVersion (); + + if (projVer != null) + { + + Node pvp = EditorsUIUtils.getProjectVersionPanel (projVer, + this.viewer); + b.getChildren ().add (pvp); + + } + + this.getBinder ().addChangeListener (this.viewer.getProject ().projectVersionProperty (), + (pr, oldv, newv) -> + { + + b.getChildren ().clear (); + + if (newv != null) + { + + Node pvp = EditorsUIUtils.getProjectVersionPanel (newv, + this.viewer); + b.getChildren ().add (pvp); + + } + + }); + + //Get the due by/response message (properties from the project) + //Get the project description (sent by editor) + + // Create a box to indicate when there are comments to send. + this.unsentLabel = QuollHyperlink.builder () + .styleClassName (StyleClassNames.COMMENT) + .onAction (ev -> + { + + EditorsUIUtils.showSendUnsentComments (this.viewer, + () -> + { + + this.showUnsentNotification (); + + }); + + }) + .build (); + + this.showUnsentNotification (); + + this.getBinder ().addListChangeListener (this.viewer.getProject ().getBooks ().get (0).getChapters (), + ev -> + { + + this.showUnsentNotification (); + + while (ev.next ()) + { + + for (Chapter c : ev.getAddedSubList ()) + { + + c.chapterItemsEvents ().subscribe (eev -> + { + + this.showUnsentNotification (); + + }); + + } + + } + + }); + + this.viewer.getProject ().getBooks ().get (0).getChapters ().stream () + .forEach (c -> + { + + // TODO Do we need to record and manage these? + c.chapterItemsEvents ().subscribe (ev -> + { + + this.showUnsentNotification (); + + }); + + }); + + this.getBinder ().addChangeListener (this.viewer.getProject ().projectVersionProperty (), + (pr, oldv, newv) -> + { + + this.showUnsentNotification (); + + }); + + this.content.getChildren ().add (this.unsentLabel); + + this.otherVersionsLabel = QuollHyperlink.builder () + .styleClassName (StyleClassNames.VIEW) + .onAction (ev -> + { + + this.showOtherVersionsSelector (); + + }) + .build (); + + this.showOtherVersionsLabel (); + + this.content.getChildren ().add (this.otherVersionsLabel); + + final EditorProjectSideBar _this = this; + + this.chapters = new EditorChaptersSidebarItem (this.viewer, + this.getBinder ()); + + this.sp = new QScrollPane (this.chapters.getAccordionItem ()); + + VBox.setVgrow (sp, + Priority.ALWAYS); + this.content.getChildren ().add (sp); + + this.getBinder ().addChangeListener (this.viewer.getProject ().projectVersionProperty (), + (pr, oldv, newv) -> + { + + this.chapters = new EditorChaptersSidebarItem (this.viewer, + this.getBinder ()); + + this.sp.setContent (this.chapters.getAccordionItem ()); + + }); + + } + + private void showUnsentNotification () + { + + if (this.editor.isPrevious ()) + { + + this.unsentLabel.setVisible (false); + + return; + + } + + // Get the unsent note count for the project (for this version). + Set notes = null; + + try + { + + notes = this.viewer.getUnsentComments (); + + } catch (Exception e) { + + Environment.logError ("Unable to show unsent comments notification", + e); + + return; + + } + + int count = notes.size (); + + if (count > 0) + { +/* + String l = ""; + + if (count == 1) + { + + l = "1 {comment} hasn't been sent, click to review/send it now"; + + } else { + + l = count + " {comments} haven't been sent, click to review/send them now"; + + } +*/ + this.unsentLabel.textProperty ().unbind (); + this.unsentLabel.textProperty ().bind (getUILanguageStringProperty (Arrays.asList (editors,project,LanguageStrings.sidebar,comments,unsent), + Environment.formatNumber (count))); + //l); + + } + + this.unsentLabel.setVisible (count > 0); + + } + + private void showOtherVersionsSelector () + { + + final EditorProjectSideBar _this = this; + + List pvs = null; + + try + { + + // TODO: Encapsulate this better. + pvs = (List) this.viewer.getObjectManager ().getObjects (ProjectVersion.class, + this.viewer.getProject (), + null, + false); + + } catch (Exception e) { + + Environment.logError ("Unable to get project versions for project: " + + this.viewer.getProject (), + e); + + return; + + } + + int c = 0; + + // Order in descending order. + try + { + + Query q = new Query (); + q.parse (String.format ("SELECT * FROM %s ORDER BY dateCreated DESC", + ProjectVersion.class.getName ())); + + QueryResults qr = q.execute (pvs); + + pvs = new ArrayList (qr.getResults ()); + + } catch (Exception e) { + + Environment.logError ("Unable to sort project versions: " + + pvs, + e); + + } + + ProjectVersion currPv = this.viewer.getProject ().getProjectVersion (); + + List others = new ArrayList<> (); + + for (ProjectVersion pv : pvs) + { + + if ((currPv != null) + && + (pv.equals (currPv)) + ) + { + + continue; + + } + + others.add (pv); + + c++; + + } + + if (c == 0) + { + + return; + + } + + if (c == 1) + { + + this.viewer.switchToProjectVersion (others.iterator ().next ()); + + } else { + + String popupId = "other-versions"; + + ShowObjectSelectPopup.builder () + .withViewer (viewer) + .title (editors,project,LanguageStrings.sidebar,comments,otherversions,popup,title) + .headerIconClassName (StyleClassNames.VIEW) + .styleClassName ("versionselect") + .styleSheet ("versionselect") + .popupId (popupId) + .objects (FXCollections.observableList (others)) + .cellProvider ((obj, popupContent) -> + { + + List prefix = Arrays.asList (editors,project,LanguageStrings.sidebar,comments,otherversions,popup,labels); + + VBox b = new VBox (); + b.getStyleClass ().add (StyleClassNames.ITEM); + + UIUtils.setTooltip (b, + getUILanguageStringProperty (Utils.newList (prefix,clicktoview), + //"Click to view version %s.", + (obj.getName () != null ? obj.getName () : getUILanguageStringProperty (Utils.newList (prefix,noversion))))); + + b.setOnMouseClicked (ev -> + { + + if (ev.getButton () != MouseButton.PRIMARY) + { + + return; + + } + + this.viewer.switchToProjectVersion (obj); + + popupContent.close (); + + }); + + QuollLabel l = QuollLabel.builder () + .label (obj.getName () != null ? obj.nameProperty () : getUILanguageStringProperty (Utils.newList (prefix,noversion))) + .styleClassName (StyleClassNames.TITLE) + .build (); + + b.getChildren ().add (l); + + StringBuilder s = new StringBuilder (); + + if (obj.getDueDate () != null) + { + + s.append (getUILanguageStringProperty (Utils.newList (prefix,dueby), + //"Due by: %s. ", + Environment.formatDate (obj.getDueDate ())).getValue ()); + + } + + try + { + + Set comms = this.viewer.getNotesForVersion (obj); + + int unsent = 0; + + for (Note n : comms) + { + + if (!n.isDealtWith ()) + { + + unsent++; + + } + + } + + String t = getUILanguageStringProperty (Utils.newList (prefix,comments), + //"%s {comment%s}", + Environment.formatNumber (comms.size ())).getValue (); + //(comms.size () == 1 ? "" : "s")); + + if (unsent > 0) + { + + t += getUILanguageStringProperty (Utils.newList (prefix,LanguageStrings.unsent), + //", %s unsent", + Environment.formatNumber (unsent)).getValue (); + + } else { + + t += getUILanguageStringProperty (Utils.newList (prefix,sent)).getValue (); + //", all sent"; + + } + + s.append (t); + + b.getChildren ().add (QuollTextView.builder () + .text (new SimpleStringProperty (s.toString ())) + .styleClassName (StyleClassNames.INFO) + .build ()); + + } catch (Exception e) { + + Environment.logError ("Unable to get unsent comments for project version: " + + obj, + e); + + } + + return b; + + }) + .showAt (this.otherVersionsLabel, + Side.BOTTOM) + .build () + .show (); + + } + + } + + private void showOtherVersionsLabel () + { + + List pvs = null; + + try + { + + // TODO: Encapsulate this better. + pvs = (java.util.List) this.viewer.getObjectManager ().getObjects (ProjectVersion.class, + this.viewer.getProject (), + null, + false); + + } catch (Exception e) { + + Environment.logError ("Unable to get project versions for project: " + + this.viewer.getProject (), + e); + + return; + + } + + int c = 0; + + ProjectVersion currPv = this.viewer.getProject ().getProjectVersion (); + + ProjectVersion otherPv = null; + + for (ProjectVersion pv : pvs) + { + + if ((currPv != null) + && + (pv.equals (currPv)) + ) + { + + continue; + + } + + otherPv = pv; + + c++; + + } + + if (c > 0) + { +/* + String l = ""; + + if (c == 1) + { + + l = String.format ("1 other version%s is available, click to view it", + (otherPv.getName () != null ? String.format (" (%s)", otherPv.getName ()) : "")); + + } else { + + l = c + " other versions are available, click to select one"; + + } +*/ + this.otherVersionsLabel.textProperty ().unbind (); + this.otherVersionsLabel.textProperty ().bind (getUILanguageStringProperty (Arrays.asList (editors,project,LanguageStrings.sidebar,comments,labels,otherversions), + Environment.formatNumber (c))); + //l); + + } + + this.otherVersionsLabel.setVisible (c > 0); + + } + + @Override + public SideBar createSideBar () + { + + return SideBar.builder () + .title (editors,project,LanguageStrings.sidebar,comments,title) + .activeTitle (editors,project,LanguageStrings.sidebar,comments,title) + //.contextMenu ()? + .styleClassName (StyleClassNames.PROJECT) + .headerIconClassName (StyleClassNames.PROJECT) + .styleSheet (StyleClassNames.PROJECT, StyleClassNames.EDITORPROJECT) + .withScrollPane (false) + .canClose (true) + .withViewer (this.viewer) + .content (this) + .sideBarId (SIDEBAR_ID) + .build (); + + } + +} diff --git a/src/main/java/com/quollwriter/editors/ui/sidebars/ProjectCommentsSideBar.java b/src/main/java/com/quollwriter/editors/ui/sidebars/ProjectCommentsSideBar.java new file mode 100644 index 00000000..d7b2db00 --- /dev/null +++ b/src/main/java/com/quollwriter/editors/ui/sidebars/ProjectCommentsSideBar.java @@ -0,0 +1,341 @@ +package com.quollwriter.editors.ui.sidebars; + +import java.util.*; + +import javafx.beans.property.*; +import javafx.scene.layout.*; +import javafx.scene.input.*; +import javafx.scene.*; +import javafx.collections.*; + +import com.quollwriter.*; +import com.quollwriter.data.*; +import com.quollwriter.text.*; +import com.quollwriter.editors.*; +import com.quollwriter.editors.ui.*; +import com.quollwriter.editors.messages.*; +import com.quollwriter.ui.fx.components.*; +import com.quollwriter.ui.fx.*; +import com.quollwriter.ui.fx.popups.*; +import com.quollwriter.uistrings.UILanguageStringsManager; + +import static com.quollwriter.LanguageStrings.*; +import static com.quollwriter.uistrings.UILanguageStringsManager.getUILanguageStringProperty; + +public class ProjectCommentsSideBar extends ProjectSentReceivedSideBar +{ + + private QuollHyperlink otherCommentsLabel = null; + + public ProjectCommentsSideBar (ProjectCommentsViewer viewer, + ProjectCommentsMessage message) + { + + super (viewer, + message); + + } + + @Override + public StringProperty getTitle () + { + + return getUILanguageStringProperty (editors,projectcomments,LanguageStrings.sidebar,comments,(this.message.isSentByMe () ? sent : received),title); + + //return String.format ("{Comments} %s", + // (this.message.isSentByMe () ? "to" : "from")); + + } + + @Override + public String getStyleClassName () + { + + return StyleClassNames.COMMENTS; + + } + + @Override + public StringProperty getItemsTitle () + { + + return getUILanguageStringProperty (objectnames,plural,comment); + + } + + @Override + public String getStyleSheet () + { + + return "projectcomments"; + + } + + @Override + public Node getMessageDetails (ProjectCommentsMessage message) + { + + List prefix = Arrays.asList (editors,projectcomments,LanguageStrings.sidebar,comments,labels); + + ProjectVersion projVer = message.getProjectVersion (); + + String verName = projVer.getName (); + + final String notes = (projVer.getDescription () != null ? projVer.getDescription ().getText () : null); + + Form.Builder fb = Form.builder () + .layoutType (Form.LayoutType.column) + .item (getUILanguageStringProperty (Utils.newList (prefix,(this.message.isSentByMe () ? sent : received))), + UILanguageStringsManager.createStringPropertyWithBinding (() -> + { + + return Environment.formatDateTime (message.getWhen ()); + + })); + + if (verName != null) + { + + fb.item (getUILanguageStringProperty (Utils.newList (prefix,version)), + new SimpleStringProperty (verName)); + + } + + final String genComments = message.getGeneralComment (); + + if (genComments != null) + { + + String commText = genComments; + + TextIterator ti = new TextIterator (commText); + + if (ti.getSentenceCount () > 1) + { + + commText = ti.getFirstSentence ().getText (); + + commText += getUILanguageStringProperty (prefix,more).getValue (); + //"
    More, click to view all."; + + } + + QuollTextView notesT = QuollTextView.builder () + .inViewer (this.viewer) + .text (new SimpleStringProperty (commText)) + .build (); + + notesT.setOnMouseClicked (ev -> + { + + QuollPopup.messageBuilder () + .title (editors,projectcomments,LanguageStrings.sidebar,comments,notes,popup,title) + .message (genComments) + .inViewer (this.viewer) + .build (); + + }); + + fb.item (getUILanguageStringProperty (Utils.newList (prefix,LanguageStrings.notes)), + notesT); + + } + + Node n = fb.build (); + + VBox content = new VBox (); + + Set messages = this.getMessage ().getEditor ().getMessages (this.getMessage ().getForProjectId (), + ProjectCommentsMessage.MESSAGE_TYPE); + + int otherC = 0; + + for (EditorMessage m : messages) + { + + ProjectCommentsMessage pcm = (ProjectCommentsMessage) m; + + if (!pcm.equals (this.getMessage ())) + { + + otherC += pcm.getComments ().size (); + + } + + } + + this.otherCommentsLabel = QuollHyperlink.builder () + .styleClassName (StyleClassNames.VIEW) + .label (getUILanguageStringProperty (Arrays.asList (editors,projectcomments,LanguageStrings.sidebar,comments,labels,othercomments), + Environment.formatNumber (otherC))) + .onAction (ev -> + { + + this.showOtherCommentsSelector (); + + }) + .build (); + + this.otherCommentsLabel.setVisible (otherC > 0); + + content.getChildren ().addAll (n, this.otherCommentsLabel); + + return content; + + } + + private void showOtherCommentsSelector () + { + + String popupId = this.message.getProjectVersion ().getId () + "othercomments"; + + QuollPopup qp = viewer.getPopupById (popupId); + + if (qp != null) + { + + qp.toFront (); + return; + + } + + final List pcms = new ArrayList<> (); + + Set messages = this.getMessage ().getEditor ().getMessages (this.getMessage ().getForProjectId (), + ProjectCommentsMessage.MESSAGE_TYPE); + + for (EditorMessage m : messages) + { + + ProjectCommentsMessage pcm = (ProjectCommentsMessage) m; + + if (pcm.equals (this.getMessage ())) + { + + continue; + + } + + pcms.add (pcm); + + } + + if (pcms.size () == 0) + { + + return; + + } + + if (pcms.size () == 1) + { + + EditorsUIUtils.showProjectComments (pcms.iterator ().next (), + this.viewer, + null); + + } else { + + ShowObjectSelectPopup.builder () + .withViewer (this.viewer) + .title (getUILanguageStringProperty (editors,projectcomments,LanguageStrings.sidebar,comments,othercomments,popup,title)) + .styleClassName (StyleClassNames.OTHERCOMMENTS) + .styleSheet (StyleClassNames.OTHERCOMMENTS) + .popupId (popupId) + .objects (FXCollections.observableList (pcms)) + .cellProvider ((obj, popupContent) -> + { + + int c = obj.getComments ().size (); + + VBox b = new VBox (); + b.getStyleClass ().add ("commentset"); + + b.setOnMouseClicked (ev -> + { + + if (ev.getButton () != MouseButton.PRIMARY) + { + + return; + + } + + EditorsUIUtils.showProjectComments (obj, + this.viewer, + null); + + popupContent.close (); + + }); + + UIUtils.setTooltip (b, + getUILanguageStringProperty (editors,projectcomments,LanguageStrings.sidebar,comments,othercomments,item,tooltip)); + + + QuollLabel h = QuollLabel.builder () + .styleClassName (StyleClassNames.TITLE) + .label (getUILanguageStringProperty (Arrays.asList (editors,projectcomments,LanguageStrings.sidebar,comments,othercomments,item,title), + Environment.formatNumber (c))) + .build (); + + b.getChildren ().add (h); + + if (obj.getProjectVersion ().getName () != null) + { + + QuollLabel l = QuollLabel.builder () + .styleClassName (StyleClassNames.VERSION) + .label (getUILanguageStringProperty (Arrays.asList (editors,projectcomments,LanguageStrings.sidebar,comments,othercomments,item,version), + obj.getProjectVersion ().getName ())) + .build (); + + b.getChildren ().add (l); + + } + + QuollLabel info = QuollLabel.builder () + .styleClassName (StyleClassNames.WHEN) + .label (getUILanguageStringProperty (Arrays.asList (editors,projectcomments,LanguageStrings.sidebar,comments,othercomments,item,(this.getMessage ().isSentByMe () ? sent : received)), + //"Received: %s", + Environment.formatDate (obj.getWhen ()))) + .build (); + + b.getChildren ().add (info); + + // Get the first line of the notes, if provided. + String genComm = obj.getGeneralComment (); + + if (genComm != null) + { + + TextIterator ti = new TextIterator (genComm); + + if (ti.getSentenceCount () > 1) + { + + genComm = ti.getFirstSentence ().getText (); + + } + + QuollTextView notesT = QuollTextView.builder () + .inViewer (this.viewer) + .styleClassName (StyleClassNames.COMMENTS) + .text (genComm) + .build (); + + b.getChildren ().add (notesT); + + } + + return b; + + }) + .build () + .show (); + + } + + } + +} diff --git a/src/main/java/com/quollwriter/editors/ui/sidebars/ProjectSentReceivedSideBar.java b/src/main/java/com/quollwriter/editors/ui/sidebars/ProjectSentReceivedSideBar.java new file mode 100644 index 00000000..642c339d --- /dev/null +++ b/src/main/java/com/quollwriter/editors/ui/sidebars/ProjectSentReceivedSideBar.java @@ -0,0 +1,118 @@ +package com.quollwriter.editors.ui.sidebars; + +import java.util.*; + +import javafx.beans.property.*; +import javafx.scene.*; +import javafx.scene.layout.*; + +import com.quollwriter.*; +import com.quollwriter.data.*; +import com.quollwriter.data.editors.*; +import com.quollwriter.events.*; +import com.quollwriter.editors.ui.*; +import com.quollwriter.editors.*; +import com.quollwriter.editors.messages.*; +import com.quollwriter.text.*; +import com.quollwriter.ui.fx.components.*; +import com.quollwriter.ui.fx.sidebars.*; +import com.quollwriter.ui.fx.*; + +import static com.quollwriter.uistrings.UILanguageStringsManager.getUILanguageStringProperty; + +public abstract class ProjectSentReceivedSideBar extends SideBarContent +{ + + public static final String SIDEBAR_ID = "projectsentreceived"; + + private ProjectCommentsChaptersSidebarItem chapters = null; + private EditorInfoBox editorInfoBox = null; + private EditorEditor editor = null; + private VBox content = null; + protected E message = null; + + public ProjectSentReceivedSideBar (ProjectSentReceivedViewer v, + E message) + { + + super (v); + + this.editor = message.getEditor (); + this.message = message; + + this.content = new VBox (); + this.getChildren ().add (this.content); + + this.editorInfoBox = new EditorInfoBox (this.editor, + this.viewer, + true, + this.getBinder ()); + VBox.setVgrow (this.editorInfoBox, + Priority.NEVER); + + Node messageC = this.getMessageDetails (this.message); + + VBox.setVgrow (messageC, + Priority.NEVER); + + this.chapters = new ProjectCommentsChaptersSidebarItem (this.viewer, + this.getItemsTitle (), + this.getBinder ()); + + QScrollPane sp = new QScrollPane (this.chapters.getAccordionItem ()); + VBox.setVgrow (sp, + Priority.ALWAYS); + + this.content.getChildren ().addAll (this.editorInfoBox, messageC, sp); + + } + + public E getMessage () + { + + return this.message; + + } + + public abstract Node getMessageDetails (E message); + + public abstract StringProperty getItemsTitle (); + + public abstract StringProperty getTitle (); + + public abstract String getStyleClassName (); + + public abstract String getStyleSheet (); + + @Override + public SideBar createSideBar () + { + + + SideBar sb = SideBar.builder () + .title (this.getTitle ()) + .activeTitle (this.getTitle ()) + .styleClassName (this.getStyleClassName ()) + //.styleSheet (this.getStyleSheet ()) + .headerIconClassName (StyleClassNames.COMMENTS) + .styleSheet (StyleClassNames.PROJECT, StyleClassNames.EDITORPROJECT, this.getStyleSheet ()) + .withScrollPane (false) + .canClose (false) + .withViewer (this.viewer) + .content (this) + .sideBarId (SIDEBAR_ID) + .build (); + + sb.addEventHandler (SideBar.SideBarEvent.CLOSE_EVENT, + ev -> + { + + this.dispose (); + + }); + + return sb; + + } + +} diff --git a/src/com/quollwriter/events/FullScreenEvent.java b/src/main/java/com/quollwriter/events/FullScreenEvent.java similarity index 100% rename from src/com/quollwriter/events/FullScreenEvent.java rename to src/main/java/com/quollwriter/events/FullScreenEvent.java diff --git a/src/com/quollwriter/events/FullScreenListener.java b/src/main/java/com/quollwriter/events/FullScreenListener.java similarity index 100% rename from src/com/quollwriter/events/FullScreenListener.java rename to src/main/java/com/quollwriter/events/FullScreenListener.java diff --git a/src/com/quollwriter/events/MainPanelEvent.java b/src/main/java/com/quollwriter/events/MainPanelEvent.java similarity index 100% rename from src/com/quollwriter/events/MainPanelEvent.java rename to src/main/java/com/quollwriter/events/MainPanelEvent.java diff --git a/src/com/quollwriter/events/MainPanelListener.java b/src/main/java/com/quollwriter/events/MainPanelListener.java similarity index 100% rename from src/com/quollwriter/events/MainPanelListener.java rename to src/main/java/com/quollwriter/events/MainPanelListener.java diff --git a/src/com/quollwriter/events/MouseEventHandler.java b/src/main/java/com/quollwriter/events/MouseEventHandler.java similarity index 100% rename from src/com/quollwriter/events/MouseEventHandler.java rename to src/main/java/com/quollwriter/events/MouseEventHandler.java diff --git a/src/com/quollwriter/events/ProjectInfoChangedEvent.java b/src/main/java/com/quollwriter/events/ProjectInfoChangedEvent.java similarity index 100% rename from src/com/quollwriter/events/ProjectInfoChangedEvent.java rename to src/main/java/com/quollwriter/events/ProjectInfoChangedEvent.java diff --git a/src/com/quollwriter/events/ProjectInfoChangedListener.java b/src/main/java/com/quollwriter/events/ProjectInfoChangedListener.java similarity index 100% rename from src/com/quollwriter/events/ProjectInfoChangedListener.java rename to src/main/java/com/quollwriter/events/ProjectInfoChangedListener.java diff --git a/src/com/quollwriter/events/PropertyChangeAdapter.java b/src/main/java/com/quollwriter/events/PropertyChangeAdapter.java similarity index 100% rename from src/com/quollwriter/events/PropertyChangeAdapter.java rename to src/main/java/com/quollwriter/events/PropertyChangeAdapter.java diff --git a/src/com/quollwriter/events/PropertyChangedAdapter.java b/src/main/java/com/quollwriter/events/PropertyChangedAdapter.java similarity index 100% rename from src/com/quollwriter/events/PropertyChangedAdapter.java rename to src/main/java/com/quollwriter/events/PropertyChangedAdapter.java diff --git a/src/com/quollwriter/events/PropertyChangedEvent.java b/src/main/java/com/quollwriter/events/PropertyChangedEvent.java similarity index 90% rename from src/com/quollwriter/events/PropertyChangedEvent.java rename to src/main/java/com/quollwriter/events/PropertyChangedEvent.java index 7e0f8d81..7fcbb37b 100644 --- a/src/com/quollwriter/events/PropertyChangedEvent.java +++ b/src/main/java/com/quollwriter/events/PropertyChangedEvent.java @@ -10,6 +10,7 @@ public class PropertyChangedEvent extends EventObject private Object newValue = null; private String changeType = null; + // TODO Change to take a JavaFX Property, have the property set a bean name. public PropertyChangedEvent(Object source, String changeType, Object oldValue, diff --git a/src/com/quollwriter/events/PropertyChangedListener.java b/src/main/java/com/quollwriter/events/PropertyChangedListener.java similarity index 100% rename from src/com/quollwriter/events/PropertyChangedListener.java rename to src/main/java/com/quollwriter/events/PropertyChangedListener.java diff --git a/src/com/quollwriter/events/SideBarEvent.java b/src/main/java/com/quollwriter/events/SideBarEvent.java similarity index 100% rename from src/com/quollwriter/events/SideBarEvent.java rename to src/main/java/com/quollwriter/events/SideBarEvent.java diff --git a/src/com/quollwriter/events/SideBarListener.java b/src/main/java/com/quollwriter/events/SideBarListener.java similarity index 100% rename from src/com/quollwriter/events/SideBarListener.java rename to src/main/java/com/quollwriter/events/SideBarListener.java diff --git a/src/main/java/com/quollwriter/events/UpdateEvent.java b/src/main/java/com/quollwriter/events/UpdateEvent.java new file mode 100644 index 00000000..dd68d1ea --- /dev/null +++ b/src/main/java/com/quollwriter/events/UpdateEvent.java @@ -0,0 +1,15 @@ +package com.quollwriter.events; + +import java.util.EventObject; + +public abstract class UpdateEvent extends EventObject +{ + + public UpdateEvent (Object source) + { + + super (source); + + } + +} diff --git a/src/main/java/com/quollwriter/events/UpdateEventListener.java b/src/main/java/com/quollwriter/events/UpdateEventListener.java new file mode 100644 index 00000000..5fa0cfdd --- /dev/null +++ b/src/main/java/com/quollwriter/events/UpdateEventListener.java @@ -0,0 +1,11 @@ +package com.quollwriter.events; + +import java.util.EventListener; + +@FunctionalInterface +public interface UpdateEventListener extends EventListener +{ + + public void valueUpdated (E ev); + +} diff --git a/src/main/java/com/quollwriter/events/UploadProgressEvent.java b/src/main/java/com/quollwriter/events/UploadProgressEvent.java new file mode 100644 index 00000000..4efae8b2 --- /dev/null +++ b/src/main/java/com/quollwriter/events/UploadProgressEvent.java @@ -0,0 +1,45 @@ +package com.quollwriter.events; + +import java.util.EventObject; + +public class UploadProgressEvent extends UpdateEvent +{ + + private int percent = 0; + private long sent = 0; + private long total = 0; + + public UploadProgressEvent (Object source, + long sent, + long total) + { + + super (source); + + this.sent = sent; + this.total = total; + + } + + public int getPercent () + { + + return (int) (this.sent * 100.0 / this.total + 0.5); + + } + + public long getSent () + { + + return this.sent; + + } + + public long getTotal () + { + + return this.total; + + } + +} diff --git a/src/com/quollwriter/events/UserPropertyEvent.java b/src/main/java/com/quollwriter/events/UserPropertyEvent.java similarity index 100% rename from src/com/quollwriter/events/UserPropertyEvent.java rename to src/main/java/com/quollwriter/events/UserPropertyEvent.java diff --git a/src/com/quollwriter/events/UserPropertyListener.java b/src/main/java/com/quollwriter/events/UserPropertyListener.java similarity index 100% rename from src/com/quollwriter/events/UserPropertyListener.java rename to src/main/java/com/quollwriter/events/UserPropertyListener.java diff --git a/src/com/quollwriter/events/UserPropertySetter.java b/src/main/java/com/quollwriter/events/UserPropertySetter.java similarity index 100% rename from src/com/quollwriter/events/UserPropertySetter.java rename to src/main/java/com/quollwriter/events/UserPropertySetter.java diff --git a/src/com/quollwriter/exporter/AbstractDocumentExporter.java b/src/main/java/com/quollwriter/exporter/AbstractDocumentExporter.java similarity index 94% rename from src/com/quollwriter/exporter/AbstractDocumentExporter.java rename to src/main/java/com/quollwriter/exporter/AbstractDocumentExporter.java index 9314f121..64193e6d 100644 --- a/src/com/quollwriter/exporter/AbstractDocumentExporter.java +++ b/src/main/java/com/quollwriter/exporter/AbstractDocumentExporter.java @@ -8,6 +8,10 @@ import javax.swing.border.*; import javax.swing.tree.*; +import javafx.scene.*; +import javafx.scene.image.*; +import javafx.scene.control.*; + import com.quollwriter.*; import com.quollwriter.data.*; @@ -16,6 +20,7 @@ import com.quollwriter.ui.*; import com.quollwriter.ui.renderers.*; +import com.quollwriter.ui.fx.components.*; public abstract class AbstractDocumentExporter implements DocumentExporter { @@ -24,6 +29,11 @@ public abstract class AbstractDocumentExporter implements DocumentExporter protected JTree itemsTree = null; + public AbstractDocumentExporter () + { + + } + public void setProject (Project p) { @@ -54,12 +64,12 @@ private void selectAllChildren (DefaultTreeModel model, boolean v) { - Enumeration en = n.children (); + Enumeration en = n.children (); while (en.hasMoreElements ()) { - DefaultMutableTreeNode c = en.nextElement (); + DefaultMutableTreeNode c = (DefaultMutableTreeNode) en.nextElement (); Object uo = c.getUserObject (); @@ -155,7 +165,7 @@ private DefaultMutableTreeNode createTree (Project p, { TreeParentNode c = new TreeParentNode (Chapter.OBJECT_TYPE, - Environment.getObjectTypeNamePlural (Chapter.OBJECT_TYPE)); + Environment.getObjectTypeNamePlural (Chapter.OBJECT_TYPE).getValue ()); SelectableDataObject sd = new SelectableDataObject (c); @@ -191,27 +201,27 @@ private DefaultMutableTreeNode createTree (Project p, for (UserConfigurableObjectType t : assetTypes) { - + Set as = p.getAssets (t); - + if (excludeTypes.contains (t.getObjectTypeId ())) { - + continue; - + } - + if (as == null) { - + continue; - + } - + this.addAssetsToTree (root, t, as); - + } /* if (!excludeTypes.contains (QCharacter.OBJECT_TYPE)) @@ -270,7 +280,7 @@ private void addAssetsToTree (DefaultMutableTreeNode root, root.add (tn); java.util.List lassets = new ArrayList (assets); - + Collections.sort (lassets, NamedObjectSorter.getInstance ()); diff --git a/src/main/java/com/quollwriter/exporter/DocumentExporter.java b/src/main/java/com/quollwriter/exporter/DocumentExporter.java new file mode 100644 index 00000000..55c30e3f --- /dev/null +++ b/src/main/java/com/quollwriter/exporter/DocumentExporter.java @@ -0,0 +1,33 @@ +package com.quollwriter.exporter; + +import java.io.*; +import java.nio.file.*; + +import com.quollwriter.*; + +import com.quollwriter.data.*; + +import com.quollwriter.ui.*; + +import com.quollwriter.ui.fx.components.*; + +public interface DocumentExporter +{ + + public void exportProject (Path dir, + Project itemsToExport) + throws GeneralException; + + public String getStartStage (); + + public WizardStep getStage (String stage); + + com.quollwriter.ui.fx.components.Wizard.Step getStage2 (String stage); + + public String getNextStage (String currStage); + + public String getPreviousStage (String currStage); + + public void setProject (Project p); + +} diff --git a/src/com/quollwriter/exporter/EPUBDocumentExporter.java b/src/main/java/com/quollwriter/exporter/EPUBDocumentExporter.java similarity index 78% rename from src/com/quollwriter/exporter/EPUBDocumentExporter.java rename to src/main/java/com/quollwriter/exporter/EPUBDocumentExporter.java index 23ef5f3a..ef423e6d 100644 --- a/src/com/quollwriter/exporter/EPUBDocumentExporter.java +++ b/src/main/java/com/quollwriter/exporter/EPUBDocumentExporter.java @@ -4,6 +4,7 @@ import java.awt.event.*; import java.io.*; +import java.nio.file.*; import java.text.*; @@ -14,8 +15,6 @@ import javax.swing.border.*; import javax.swing.tree.*; -import com.gentlyweb.utils.*; - import com.jgoodies.forms.builder.*; import com.jgoodies.forms.factories.*; import com.jgoodies.forms.layout.*; @@ -31,22 +30,29 @@ import com.quollwriter.ui.*; import com.quollwriter.ui.userobjects.*; -import com.quollwriter.ui.components.Markup; import com.quollwriter.ui.renderers.*; import com.quollwriter.text.*; +import com.quollwriter.ui.fx.components.*; + import static com.quollwriter.LanguageStrings.*; import static com.quollwriter.Environment.getUIString; +import static com.quollwriter.uistrings.UILanguageStringsManager.getUILanguageStringProperty; public class EPUBDocumentExporter extends AbstractDocumentExporter { + public static final String DETAILS_STAGE = "details"; + // private ExportSettings settings = null; private ZipOutputStream zout = null; private JTextField author = null; private JTextField id = null; + private QuollTextField author2 = null; + private QuollTextField id2 = null; + public EPUBDocumentExporter() { @@ -55,7 +61,7 @@ public EPUBDocumentExporter() public String getStartStage () { - return "select-items"; + return DETAILS_STAGE; } @@ -94,7 +100,7 @@ public WizardStep getStage (String stage) } - if (stage.equals ("details")) + if (DETAILS_STAGE.equals (stage)) { ws.title = getUIString (exportproject,stages,bookdetails,title); @@ -142,9 +148,58 @@ public WizardStep getStage (String stage) } + @Override + public com.quollwriter.ui.fx.components.Wizard.Step getStage2 (String stage) + { + + final EPUBDocumentExporter _this = this; + + com.quollwriter.ui.fx.components.Wizard.Step ws = new com.quollwriter.ui.fx.components.Wizard.Step (); + + if (DETAILS_STAGE.equals (stage)) + { + + ws.title = getUILanguageStringProperty (exportproject,stages,bookdetails,title); + + this.author2 = QuollTextField.builder () + .build (); + + this.author2.setText (this.proj.getProperty (Constants.AUTHOR_NAME_PROPERTY_NAME)); + + this.id2 = QuollTextField.builder () + .build (); + + this.id2.setText (this.proj.getProperty (Constants.BOOK_ID_PROPERTY_NAME)); + + Form f = Form.builder () + .description (exportproject,stages,bookdetails,text) + .item (getUILanguageStringProperty (exportproject,stages,bookdetails,labels,authorname), + this.author2) + .item (getUILanguageStringProperty (exportproject,stages,bookdetails,labels,LanguageStrings.id), + this.id2) + .build (); + + ws.content = f; + ws.content.getStyleClass ().add (DETAILS_STAGE); + + } + + return ws; + + } + public String getNextStage (String currStage) { + if (DETAILS_STAGE.equals (currStage)) + { + + return null; + + } + + return DETAILS_STAGE; +/* if (currStage == null) { @@ -160,12 +215,14 @@ public String getNextStage (String currStage) } return null; - +*/ } public String getPreviousStage (String currStage) { + return null; +/* if (currStage == null) { @@ -181,7 +238,7 @@ public String getPreviousStage (String currStage) } return null; - +*/ } private void addEntry (String name, @@ -222,15 +279,29 @@ private String sanitizeName (String name) } - public void exportProject (File dir) + public void exportProject (Path dir, + Project itemsToExport) throws GeneralException { try { - Project p = ExportUtils.getSelectedItems (this.itemsTree, - this.proj); + if (this.author2.getText () != null) + { + + this.proj.setProperty (Constants.AUTHOR_NAME_PROPERTY_NAME, + this.author2.getText ().trim ()); + + } + + if (this.id2.getText () != null) + { + + this.proj.setProperty (Constants.BOOK_ID_PROPERTY_NAME, + this.id2.getText ().trim ()); + + } // Create new Book nl.siegmann.epublib.domain.Book book = new nl.siegmann.epublib.domain.Book (); @@ -239,24 +310,24 @@ public void exportProject (File dir) book.getMetadata ().addTitle (this.proj.getName ()); // Add an Author - book.getMetadata ().addAuthor (new Author (this.author.getText ())); + book.getMetadata ().addAuthor (new Author (this.author2.getText ())); book.getMetadata ().setLanguage (this.getLanguageCode (this.proj)); // Set cover image //book.getMetadata().setCoverImage(new Resource(Simple1.class.getResourceAsStream("/book1/test_cover.png"), "cover.png")); - String css = Environment.getResourceFileAsString ("/data/export/epub/css-template.xml"); + String css = Utils.getResourceFileAsString ("/data/export/epub/css-template.xml"); - css = StringUtils.replaceString (css, + css = Utils.replaceString (css, "[[FONT_NAME]]", UserProperties.get (Constants.EDITOR_FONT_PROPERTY_NAME)); - css = StringUtils.replaceString (css, + css = Utils.replaceString (css, "[[FONT_SIZE]]", UserProperties.getAsInt (Constants.EDITOR_FONT_SIZE_PROPERTY_NAME) + "pt"); - css = StringUtils.replaceString (css, + css = Utils.replaceString (css, "[[LINE_SPACING]]", (100 * UserProperties.getAsFloat (Constants.EDITOR_LINE_SPACING_PROPERTY_NAME)) + "%"); - css = StringUtils.replaceString (css, + css = Utils.replaceString (css, "[[ALIGN]]", UserProperties.get (Constants.EDITOR_ALIGNMENT_PROPERTY_NAME).toLowerCase ()); @@ -269,59 +340,65 @@ public void exportProject (File dir) } - css = StringUtils.replaceString (css, + css = Utils.replaceString (css, "[[INDENT]]", indent); book.getResources ().add (new Resource (new ByteArrayInputStream (css.getBytes ("utf-8")), "main.css")); - Book b = p.getBook (0); + if (itemsToExport.getBooks ().size () > 0) + { - String cTemp = Environment.getResourceFileAsString ("/data/export/epub/chapter-template.xml"); + Book b = itemsToExport.getBook (0); - List chapters = b.getChapters (); + String cTemp = Utils.getResourceFileAsString ("/data/export/epub/chapter-template.xml"); - int count = 0; + List chapters = b.getChapters (); - for (Chapter c : chapters) - { + int count = 0; - count++; + for (Chapter c : chapters) + { - String chapterText = StringUtils.replaceString (cTemp, - "[[TITLE]]", - c.getName ()); + count++; - StringWithMarkup v = c.getText (); + String chapterText = Utils.replaceString (cTemp, + "[[TITLE]]", + c.getName ()); - String t = (v != null ? v.getText () : null); + StringWithMarkup v = c.getText (); - TextIterator iter = new TextIterator (t); + String t = (v != null ? v.getText () : null); - Markup m = (c != null ? v.getMarkup () : null); + TextIterator iter = new TextIterator (t); - StringBuilder ct = new StringBuilder (); + Markup m = (c != null ? v.getMarkup () : null); - for (Paragraph para : iter.getParagraphs ()) - { + StringBuilder ct = new StringBuilder (); - ct.append (String.format ("

    %s

    ", - para.markupAsHTML (m))); + for (Paragraph para : iter.getParagraphs ()) + { - } + ct.append (String.format ("

    %s

    ", + para.markupAsHTML (m))); + + } + + chapterText = Utils.replaceString (chapterText, + "[[CONTENT]]", + ct.toString ()); - chapterText = StringUtils.replaceString (chapterText, - "[[CONTENT]]", - ct.toString ()); + book.addSection (c.getName (), + new Resource (new ByteArrayInputStream (chapterText.getBytes ("utf-8")), + "chapter" + count + ".html")); - book.addSection (c.getName (), - new Resource (new ByteArrayInputStream (chapterText.getBytes ("utf-8")), - "chapter" + count + ".html")); + } } - String appendixTemp = Environment.getResourceFileAsString ("/data/export/epub/appendix-template.xml"); + // TODO Make a constant/property... + String appendixTemp = Utils.getResourceFileAsString ("/data/export/epub/appendix-template.xml"); Set assetTypes = Environment.getAssetUserConfigurableObjectTypes (true); @@ -333,7 +410,7 @@ public void exportProject (File dir) for (UserConfigurableObjectType type : assetTypes) { - Set as = p.getAssets (type); + Set as = itemsToExport.getAssets (type); if ((as == null) || @@ -358,10 +435,10 @@ public void exportProject (File dir) apxC, type.getObjectTypeNamePlural ()); - String t = StringUtils.replaceString (appendixTemp, + String t = Utils.replaceString (appendixTemp, "[[TITLE]]", title); - t = StringUtils.replaceString (t, + t = Utils.replaceString (t, "[[CONTENT]]", this.getAssetsPage (as, book)); @@ -445,7 +522,7 @@ public void exportProject (File dir) EpubWriter epubWriter = new EpubWriter (); // Write the Book as Epub - epubWriter.write (book, new FileOutputStream (new File (dir.getPath () + "/" + this.sanitizeName (this.proj.getName ()) + Constants.EPUB_FILE_EXTENSION))); + epubWriter.write (book, Files.newOutputStream (dir.resolve (this.sanitizeName (this.proj.getName ()) + Constants.EPUB_FILE_EXTENSION))); } catch (Exception e) { @@ -486,7 +563,10 @@ private String getAssetsPage (Set assets, Object val = h.getFieldValue (); - if (val == null) + if ((val == null) + || + ((val instanceof StringWithMarkup) && (!((StringWithMarkup) val).hasText ())) + ) { continue; @@ -527,7 +607,7 @@ private String getAssetsPage (Set assets, buf.append ("

    "); + buf.append ("\" />

    "); continue; diff --git a/src/com/quollwriter/exporter/ExportSettings.java b/src/main/java/com/quollwriter/exporter/ExportSettings.java similarity index 100% rename from src/com/quollwriter/exporter/ExportSettings.java rename to src/main/java/com/quollwriter/exporter/ExportSettings.java diff --git a/src/com/quollwriter/exporter/ExportUtils.java b/src/main/java/com/quollwriter/exporter/ExportUtils.java similarity index 100% rename from src/com/quollwriter/exporter/ExportUtils.java rename to src/main/java/com/quollwriter/exporter/ExportUtils.java diff --git a/src/com/quollwriter/exporter/HTMLDocumentExporter.java b/src/main/java/com/quollwriter/exporter/HTMLDocumentExporter.java similarity index 100% rename from src/com/quollwriter/exporter/HTMLDocumentExporter.java rename to src/main/java/com/quollwriter/exporter/HTMLDocumentExporter.java diff --git a/src/com/quollwriter/exporter/MSWordDocXDocumentExporter.java b/src/main/java/com/quollwriter/exporter/MSWordDocXDocumentExporter.java similarity index 87% rename from src/com/quollwriter/exporter/MSWordDocXDocumentExporter.java rename to src/main/java/com/quollwriter/exporter/MSWordDocXDocumentExporter.java index 5ac97e4d..902e5494 100644 --- a/src/com/quollwriter/exporter/MSWordDocXDocumentExporter.java +++ b/src/main/java/com/quollwriter/exporter/MSWordDocXDocumentExporter.java @@ -4,6 +4,7 @@ import java.awt.event.*; import java.io.*; +import java.nio.file.*; import java.text.*; @@ -13,8 +14,6 @@ import javax.swing.border.*; import javax.swing.tree.*; -import com.gentlyweb.utils.*; - import com.jgoodies.forms.builder.*; import com.jgoodies.forms.factories.*; import com.jgoodies.forms.layout.*; @@ -26,10 +25,14 @@ import com.quollwriter.ui.*; import com.quollwriter.ui.userobjects.*; -import com.quollwriter.ui.components.Markup; import com.quollwriter.ui.renderers.*; import com.quollwriter.text.*; +import javafx.beans.property.*; +import javafx.scene.control.*; +import javafx.scene.layout.*; +import com.quollwriter.ui.fx.components.*; + import org.docx4j.jaxb.*; import org.docx4j.openpackaging.packages.WordprocessingMLPackage; @@ -39,9 +42,11 @@ import static com.quollwriter.LanguageStrings.*; import static com.quollwriter.Environment.getUIString; +import static com.quollwriter.uistrings.UILanguageStringsManager.getUILanguageStringProperty; public class MSWordDocXDocumentExporter extends AbstractDocumentExporter { + public static final String HOW_TO_SAVE_STAGE = "how-to-save"; public static final String HEADING1 = "Heading1"; public static final String HEADING2 = "Heading2"; @@ -52,13 +57,16 @@ public class MSWordDocXDocumentExporter extends AbstractDocumentExporter protected ExportSettings settings = null; private JComboBox exportOthersType = null; private JComboBox exportChaptersType = null; - private JScrollPane itemsTreeScroll = null; + + private QuollChoiceBox exportChaptersType2 = null; + private QuollChoiceBox exportOthersType2 = null; + private CTLanguage lang = null; public String getStartStage () { - return "select-items"; + return HOW_TO_SAVE_STAGE; } @@ -151,9 +159,65 @@ public WizardStep getStage (String stage) } + @Override + public com.quollwriter.ui.fx.components.Wizard.Step getStage2 (String stage) + { + + final MSWordDocXDocumentExporter _this = this; + + com.quollwriter.ui.fx.components.Wizard.Step ws = new com.quollwriter.ui.fx.components.Wizard.Step (); + + if (HOW_TO_SAVE_STAGE.equals (stage)) + { + + ws.title = getUILanguageStringProperty (exportproject,stages,howtosave,title); + //"How should the selected items be saved"; + + Set exportChaptersTypes = new LinkedHashSet<> (); + exportChaptersTypes.add (getUILanguageStringProperty (exportproject,stages,howtosave,types,singlefile)); + exportChaptersTypes.add (getUILanguageStringProperty (exportproject,stages,howtosave,types,onefileperchapter)); + + this.exportChaptersType2 = QuollChoiceBox.builder () + .items (exportChaptersTypes) + .build (); + + Set exportOthersTypes = new LinkedHashSet<> (); + exportOthersTypes.add (getUILanguageStringProperty (exportproject,stages,howtosave,types,singlefile)); + exportOthersTypes.add (getUILanguageStringProperty (exportproject,stages,howtosave,types,onefileperitemtype)); + + this.exportOthersType2 = QuollChoiceBox.builder () + .items (exportOthersTypes) + .build (); + + Form f = Form.builder () + .description (exportproject,stages,howtosave,text) + .item (getUILanguageStringProperty (exportproject,stages,howtosave,labels,chapters), + this.exportChaptersType2) + .item (getUILanguageStringProperty (exportproject,stages,howtosave,labels,otheritems), + this.exportOthersType2) + .build (); + + ws.content = f; + ws.content.getStyleClass ().add (HOW_TO_SAVE_STAGE); + + } + + return ws; + + } + public String getNextStage (String currStage) { + if (HOW_TO_SAVE_STAGE.equals (currStage)) + { + + return null; + + } + + return HOW_TO_SAVE_STAGE; +/* if (currStage == null) { @@ -169,12 +233,14 @@ public String getNextStage (String currStage) } return null; - +*/ } public String getPreviousStage (String currStage) { + return null; +/* if (currStage == null) { @@ -190,7 +256,7 @@ public String getPreviousStage (String currStage) } return null; - +*/ } private void addParagraph (Paragraph para, @@ -604,7 +670,10 @@ private void addTo (MainDocumentPart mp, Object val = h.getFieldValue (); - if (val == null) + if ((val == null) + || + ((val instanceof StringWithMarkup) && (!((StringWithMarkup) val).hasText ())) + ) { continue; @@ -915,7 +984,7 @@ protected void save (WordprocessingMLPackage wordMLPackage, name = name.replace ('\\', '_'); - name = Utils.sanitizeForFilename (name); + name = Utils.sanitizeForFilenameKeepCase (name); File f = new File (this.settings.outputDirectory.getPath () + "/" + name + Constants.DOCX_FILE_EXTENSION); @@ -924,14 +993,15 @@ protected void save (WordprocessingMLPackage wordMLPackage, } @Override - public void exportProject (File dir) + public void exportProject (Path dir, + Project itemsToExport) throws GeneralException { ExportSettings es = new ExportSettings (); - es.outputDirectory = dir; - es.chapterExportType = ((this.exportChaptersType.getSelectedIndex () == 0) ? ExportSettings.SINGLE_FILE : ExportSettings.INDIVIDUAL_FILE); - es.otherExportType = ((this.exportOthersType.getSelectedIndex () == 0) ? ExportSettings.SINGLE_FILE : ExportSettings.INDIVIDUAL_FILE); + es.outputDirectory = dir.toFile (); + es.chapterExportType = ((this.exportChaptersType2.getSelectionModel ().getSelectedIndex () == 0) ? ExportSettings.SINGLE_FILE : ExportSettings.INDIVIDUAL_FILE); + es.otherExportType = ((this.exportOthersType2.getSelectionModel ().getSelectedIndex () == 0) ? ExportSettings.SINGLE_FILE : ExportSettings.INDIVIDUAL_FILE); this.settings = es; @@ -941,8 +1011,7 @@ public void exportProject (File dir) this.lang.setVal (this.getLanguageCode (this.proj)); - Project p = ExportUtils.getSelectedItems (this.itemsTree, - this.proj); + Project p = itemsToExport; try { @@ -1005,86 +1074,91 @@ public void exportProject (File dir) boolean hasChapInf = false; - List chapters = p.getBooks ().get (0).getChapters (); - - for (Chapter c : chapters) + if (p.getBooks ().size () > 0) { - this.addTo (mp, - wordMLPackage, - c); + List chapters = p.getBooks ().get (0).getChapters (); - notesmp.addStyledParagraphOfText (HEADING1, - c.getName ()); - outlinemp.addStyledParagraphOfText (HEADING1, - c.getName ()); - chapinfmp.addStyledParagraphOfText (HEADING1, - c.getName ()); + for (Chapter c : chapters) + { - this.addChapterItems (c, - notesmp, - outlinemp, - chapinfmp); + this.addTo (mp, + wordMLPackage, + c); + + notesmp.addStyledParagraphOfText (HEADING1, + c.getName ()); + outlinemp.addStyledParagraphOfText (HEADING1, + c.getName ()); + chapinfmp.addStyledParagraphOfText (HEADING1, + c.getName ()); + + this.addChapterItems (c, + notesmp, + outlinemp, + chapinfmp); + + if ((c.getGoals () != null) + || + (c.getPlan () != null) + ) + { - if ((c.getGoals () != null) - || - (c.getPlan () != null) - ) - { + hasChapInf = true; - hasChapInf = true; + } - } + if (c.getNotes ().size () > 0) + { - if (c.getNotes ().size () > 0) - { + hasNotes = true; - hasNotes = true; + } - } + if ((c.getOutlineItems ().size () > 0) + || + (c.getScenes ().size () > 0) + ) + { - if ((c.getOutlineItems ().size () > 0) - || - (c.getScenes ().size () > 0) - ) - { + hasOutline = true; - hasOutline = true; + } } - } + this.save (wordMLPackage, + p.getName ()); - this.save (wordMLPackage, - p.getName ()); + if (hasNotes) + { - if (hasNotes) - { + this.save (notesWordMLPackage, + String.format (getUIString (exportproject,sectiontitles,notes), + p.getName ())); + //p.getName () + " - Notes"); - this.save (notesWordMLPackage, - String.format (getUIString (exportproject,sectiontitles,notes), - p.getName ())); - //p.getName () + " - Notes"); + } - } + if (hasOutline) + { - if (hasOutline) - { + this.save (outlineWordMLPackage, + String.format (getUIString (exportproject,sectiontitles,scenesoutlineitems), + p.getName ())); + //p.getName () + " - Scenes and Plot Outline"); - this.save (outlineWordMLPackage, - String.format (getUIString (exportproject,sectiontitles,scenesoutlineitems), - p.getName ())); - //p.getName () + " - Scenes and Plot Outline"); + } - } + if (hasChapInf) + { - if (hasChapInf) - { + this.save (chapterInfoWordMLPackage, + String.format (getUIString (exportproject,sectiontitles,chapterinfo), + p.getName ())); + //p.getName () + " - Chapter Information"); - this.save (chapterInfoWordMLPackage, - String.format (getUIString (exportproject,sectiontitles,chapterinfo), - p.getName ())); - //p.getName () + " - Chapter Information"); + } } diff --git a/src/com/quollwriter/exporter/PDFDocumentExporter.java b/src/main/java/com/quollwriter/exporter/PDFDocumentExporter.java similarity index 94% rename from src/com/quollwriter/exporter/PDFDocumentExporter.java rename to src/main/java/com/quollwriter/exporter/PDFDocumentExporter.java index 29150ba0..038b57ee 100644 --- a/src/com/quollwriter/exporter/PDFDocumentExporter.java +++ b/src/main/java/com/quollwriter/exporter/PDFDocumentExporter.java @@ -12,8 +12,6 @@ import javax.swing.border.*; import javax.swing.tree.*; -import com.gentlyweb.utils.*; - import com.jgoodies.forms.builder.*; import com.jgoodies.forms.factories.*; import com.jgoodies.forms.layout.*; @@ -47,14 +45,14 @@ protected void save (WordprocessingMLPackage wordMLPackage, name = name.replace ('\\', '_'); name = Utils.sanitizeForFilename (name); - + FileOutputStream out = new FileOutputStream (new File (this.settings.outputDirectory.getPath () + "/" + name + Constants.PDF_FILE_EXTENSION)); wordMLPackage.setFontMapper (new IdentityPlusMapper (), true); - + Docx4J.toPDF (wordMLPackage, out); - + } } diff --git a/src/com/quollwriter/importer/DocumentImporter.java b/src/main/java/com/quollwriter/importer/DocumentImporter.java similarity index 100% rename from src/com/quollwriter/importer/DocumentImporter.java rename to src/main/java/com/quollwriter/importer/DocumentImporter.java diff --git a/src/com/quollwriter/importer/HTMLDocumentImporter.java b/src/main/java/com/quollwriter/importer/HTMLDocumentImporter.java similarity index 87% rename from src/com/quollwriter/importer/HTMLDocumentImporter.java rename to src/main/java/com/quollwriter/importer/HTMLDocumentImporter.java index 8f32df57..b9f2ebca 100644 --- a/src/com/quollwriter/importer/HTMLDocumentImporter.java +++ b/src/main/java/com/quollwriter/importer/HTMLDocumentImporter.java @@ -7,12 +7,12 @@ import com.quollwriter.*; import com.quollwriter.data.*; - +/* import org.apache.poi.hwpf.*; import org.apache.poi.hwpf.extractor.*; import org.apache.poi.hwpf.model.*; import org.apache.poi.hwpf.usermodel.*; - +*/ import org.docx4j.openpackaging.parts.WordprocessingML.*; @@ -137,40 +137,40 @@ private void addItem (String style, } // Work out what to create. - if (text.toLowerCase ().startsWith (Environment.getObjectTypeName (QCharacter.OBJECT_TYPE).toLowerCase () + ":")) + if (text.toLowerCase ().startsWith (Environment.getObjectTypeName (QCharacter.OBJECT_TYPE).getValue ().toLowerCase () + ":")) { // Create a character. this.n = new QCharacter (); - name = text.substring (Environment.getObjectTypeName (QCharacter.OBJECT_TYPE).toLowerCase ().length () + 1).trim (); + name = text.substring (Environment.getObjectTypeName (QCharacter.OBJECT_TYPE).getValue ().toLowerCase ().length () + 1).trim (); } - if (text.toLowerCase ().startsWith (Environment.getObjectTypeName (Location.OBJECT_TYPE).toLowerCase () + ":")) + if (text.toLowerCase ().startsWith (Environment.getObjectTypeName (Location.OBJECT_TYPE).getValue ().toLowerCase () + ":")) { // Create a character. this.n = new Location (); - name = text.substring (Environment.getObjectTypeName (Location.OBJECT_TYPE).toLowerCase ().length () + 1).trim (); + name = text.substring (Environment.getObjectTypeName (Location.OBJECT_TYPE).getValue ().toLowerCase ().length () + 1).trim (); } - if (text.toLowerCase ().startsWith (Environment.getObjectTypeName (ResearchItem.OBJECT_TYPE).toLowerCase () + ":")) + if (text.toLowerCase ().startsWith (Environment.getObjectTypeName (ResearchItem.OBJECT_TYPE).getValue ().toLowerCase () + ":")) { // Create a character. this.n = new ResearchItem (); - name = text.substring (Environment.getObjectTypeName (ResearchItem.OBJECT_TYPE).toLowerCase ().length () + 1).trim (); + name = text.substring (Environment.getObjectTypeName (ResearchItem.OBJECT_TYPE).getValue ().toLowerCase ().length () + 1).trim (); } - if (text.toLowerCase ().startsWith (Environment.getObjectTypeName (QObject.OBJECT_TYPE).toLowerCase () + ":")) + if (text.toLowerCase ().startsWith (Environment.getObjectTypeName (QObject.OBJECT_TYPE).getValue ().toLowerCase () + ":")) { // Create a character. this.n = new QObject (); - name = text.substring (Environment.getObjectTypeName (QObject.OBJECT_TYPE).toLowerCase ().length () + 1).trim (); + name = text.substring (Environment.getObjectTypeName (QObject.OBJECT_TYPE).getValue ().toLowerCase ().length () + 1).trim (); } diff --git a/src/com/quollwriter/importer/ImportCallback.java b/src/main/java/com/quollwriter/importer/ImportCallback.java similarity index 100% rename from src/com/quollwriter/importer/ImportCallback.java rename to src/main/java/com/quollwriter/importer/ImportCallback.java diff --git a/src/com/quollwriter/importer/Importer.java b/src/main/java/com/quollwriter/importer/Importer.java similarity index 91% rename from src/com/quollwriter/importer/Importer.java rename to src/main/java/com/quollwriter/importer/Importer.java index 888ef4f8..9ecef358 100644 --- a/src/com/quollwriter/importer/Importer.java +++ b/src/main/java/com/quollwriter/importer/Importer.java @@ -23,9 +23,10 @@ public class Importer { Map m = Importer.handlers; - +/* m.put (Constants.DOC_FILE_EXTENSION, MSWordDocumentImporter.class); +*/ m.put (Constants.DOCX_FILE_EXTENSION, MSWordDocumentImporter.class); @@ -36,9 +37,10 @@ public class Importer HTMLDocumentImporter.class); */ m = Importer.initDocs; - +/* m.put (Constants.DOC_FILE_EXTENSION, Constants.DATA_DIR + "doc-import-init.doc"); +*/ m.put (Constants.DOCX_FILE_EXTENSION, Constants.DATA_DIR + "docx-import-init.docx"); @@ -60,9 +62,9 @@ public static void init () try { - DocumentImporter di = (DocumentImporter) c.newInstance (); + DocumentImporter di = (DocumentImporter) c.getDeclaredConstructor ().newInstance (); - di.convert (Environment.getResourceStream (Importer.initDocs.get (t)), + di.convert (Utils.getResourceStream (Importer.initDocs.get (t)), t); } catch (Exception e) @@ -120,7 +122,7 @@ public static void importProject (final URI u, try { - final DocumentImporter di = (DocumentImporter) c.newInstance (); + final DocumentImporter di = (DocumentImporter) c.getDeclaredConstructor ().newInstance (); Thread t = new Thread (new Runner () { @@ -140,9 +142,11 @@ public void run () { // Use the file name. - String fn = url.getFile ().substring (0, + String fn = url.getFile ().substring (url.getPath ().lastIndexOf ("/") + 1, url.getFile ().length () - Constants.DOCX_FILE_EXTENSION.length ()); + fn = URLDecoder.decode (fn); + p.setName (fn); p.getBooks ().get (0).setName (fn); diff --git a/src/com/quollwriter/importer/MSWordDocumentImporter.java b/src/main/java/com/quollwriter/importer/MSWordDocumentImporter.java similarity index 83% rename from src/com/quollwriter/importer/MSWordDocumentImporter.java rename to src/main/java/com/quollwriter/importer/MSWordDocumentImporter.java index a346a5b8..74bede96 100644 --- a/src/com/quollwriter/importer/MSWordDocumentImporter.java +++ b/src/main/java/com/quollwriter/importer/MSWordDocumentImporter.java @@ -8,10 +8,11 @@ import com.quollwriter.text.TextUtilities; import com.quollwriter.data.*; -import org.apache.poi.hwpf.*; -import org.apache.poi.hwpf.extractor.*; -import org.apache.poi.hwpf.model.*; -import org.apache.poi.hwpf.usermodel.*; +// TODO Removed support for .doc files. +//import org.apache.poi.hwpf.*; +//import org.apache.poi.hwpf.extractor.*; +//import org.apache.poi.hwpf.model.*; +//import org.apache.poi.hwpf.usermodel.*; import org.docx4j.openpackaging.packages.WordprocessingMLPackage; import org.docx4j.openpackaging.parts.WordprocessingML.*; @@ -44,6 +45,13 @@ public Project convert (InputStream in, if (fileExt.equals (Constants.DOC_FILE_EXTENSION)) { + if (true) + { + + throw new UnsupportedOperationException (".doc files no longer supported."); + + } + this.importFromDOC (in); } @@ -62,14 +70,29 @@ public Project convert (InputStream in, private void importFromDOC (InputStream in) throws Exception { - +/* +TODO Remove HWPFDocument doc = new HWPFDocument (in); PAPBinTable parasT = doc.getParagraphTable (); Range r = doc.getRange (); - List paras = parasT.getParagraphs (); + for (int i = 0; i < r.numParagraphs (); i++) + { + + Paragraph p = r.getParagraph (i); + + String style = doc.getStyleSheet ().getStyleDescription (p.getStyleIndex ()).getName (); + + this.addItem (style, + p.text ()); + + } + */ +/* + List paras = parasT.getParagraphs (); + int pi = 0; for (int i = 0; i < paras.size (); i++) { @@ -93,8 +116,8 @@ private void importFromDOC (InputStream in) } } - - this.addLastItem (); +*/ + //this.addLastItem (); } @@ -102,7 +125,7 @@ private void importFromDOCX (InputStream in) throws Exception { - File f = Environment.writeStreamToTempFile (in); + File f = Utils.writeStreamToTempFile (in); f.deleteOnExit (); WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage.load (f); @@ -146,6 +169,18 @@ private void importFromDOCX (InputStream in) this.addItem (s, text); + } else { + + StringWriter sw = new StringWriter (); + + org.docx4j.TextUtils.extractText (o, + sw); + + String text = sw.toString (); + + this.addItem (null, + text); + } } @@ -356,38 +391,38 @@ private void addItem (String style, } // Work out what to create. - if (text.toLowerCase ().startsWith (Environment.getObjectTypeName (QCharacter.OBJECT_TYPE).toLowerCase () + ":")) + if (text.toLowerCase ().startsWith (Environment.getObjectTypeName (QCharacter.OBJECT_TYPE).getValue ().toLowerCase () + ":")) { // Create a character. this.n = new QCharacter (); - name = text.substring (Environment.getObjectTypeName (QCharacter.OBJECT_TYPE).toLowerCase ().length () + 1).trim (); + name = text.substring (Environment.getObjectTypeName (QCharacter.OBJECT_TYPE).getValue ().toLowerCase ().length () + 1).trim (); } - if (text.toLowerCase ().startsWith (Environment.getObjectTypeName (Location.OBJECT_TYPE).toLowerCase () + ":")) + if (text.toLowerCase ().startsWith (Environment.getObjectTypeName (Location.OBJECT_TYPE).getValue ().toLowerCase () + ":")) { this.n = new Location (); - name = text.substring (Environment.getObjectTypeName (Location.OBJECT_TYPE).toLowerCase ().length () + 1).trim (); + name = text.substring (Environment.getObjectTypeName (Location.OBJECT_TYPE).getValue ().toLowerCase ().length () + 1).trim (); } - if (text.toLowerCase ().startsWith (Environment.getObjectTypeName (ResearchItem.OBJECT_TYPE).toLowerCase () + ":")) + if (text.toLowerCase ().startsWith (Environment.getObjectTypeName (ResearchItem.OBJECT_TYPE).getValue ().toLowerCase () + ":")) { this.n = new ResearchItem (); - name = text.substring (Environment.getObjectTypeName (ResearchItem.OBJECT_TYPE).toLowerCase ().length () + 1).trim (); + name = text.substring (Environment.getObjectTypeName (ResearchItem.OBJECT_TYPE).getValue ().toLowerCase ().length () + 1).trim (); } - if (text.toLowerCase ().startsWith (Environment.getObjectTypeName (QObject.OBJECT_TYPE).toLowerCase () + ":")) + if (text.toLowerCase ().startsWith (Environment.getObjectTypeName (QObject.OBJECT_TYPE).getValue ().toLowerCase () + ":")) { this.n = new QObject (); - name = text.substring (Environment.getObjectTypeName (QObject.OBJECT_TYPE).toLowerCase ().length () + 1).trim (); + name = text.substring (Environment.getObjectTypeName (QObject.OBJECT_TYPE).getValue ().toLowerCase ().length () + 1).trim (); } @@ -413,7 +448,7 @@ private void addItem (String style, if (chapterText.length () > 0) { - chapterText.append ("\n\n"); + chapterText.append ("\n"); } diff --git a/src/com/quollwriter/synonyms/SynonymProvider.java b/src/main/java/com/quollwriter/synonyms/SynonymProvider.java similarity index 100% rename from src/com/quollwriter/synonyms/SynonymProvider.java rename to src/main/java/com/quollwriter/synonyms/SynonymProvider.java diff --git a/src/com/quollwriter/synonyms/Synonyms.java b/src/main/java/com/quollwriter/synonyms/Synonyms.java similarity index 84% rename from src/com/quollwriter/synonyms/Synonyms.java rename to src/main/java/com/quollwriter/synonyms/Synonyms.java index 141f45eb..4fd9f479 100644 --- a/src/com/quollwriter/synonyms/Synonyms.java +++ b/src/main/java/com/quollwriter/synonyms/Synonyms.java @@ -33,12 +33,12 @@ public Part(char type, } - public List verbs = new ArrayList (); - public List nouns = new ArrayList (); - public List other = new ArrayList (); - public List adjectives = new ArrayList (); - public List adverbs = new ArrayList (); - public List words = new ArrayList (); + public List verbs = new ArrayList<> (); + public List nouns = new ArrayList<> (); + public List other = new ArrayList<> (); + public List adjectives = new ArrayList<> (); + public List adverbs = new ArrayList<> (); + public List words = new ArrayList<> (); public String word = null; private String parts = null; @@ -119,7 +119,7 @@ public void addToWords (char type) public Part newPart (char type) { - List words = this.other; + List words = this.other; if ((type == VERB) || (type == VERB_I) || @@ -178,7 +178,7 @@ public Part newPart (char type) } - public void addNouns (List nouns) + public void addNouns (List nouns) { if (nouns != null) @@ -190,7 +190,7 @@ public void addNouns (List nouns) } - public void addAdverbs (List advs) + public void addAdverbs (List advs) { if (advs != null) @@ -202,7 +202,7 @@ public void addAdverbs (List advs) } - public void addAdjectives (List adjs) + public void addAdjectives (List adjs) { if (adjs != null) @@ -214,7 +214,7 @@ public void addAdjectives (List adjs) } - public void addVerbs (List verbs) + public void addVerbs (List verbs) { if (verbs != null) diff --git a/src/com/quollwriter/synonyms/providers/BigHugeLabsSynonymProvider.java b/src/main/java/com/quollwriter/synonyms/providers/BigHugeLabsSynonymProvider.java similarity index 96% rename from src/com/quollwriter/synonyms/providers/BigHugeLabsSynonymProvider.java rename to src/main/java/com/quollwriter/synonyms/providers/BigHugeLabsSynonymProvider.java index 5f8f7549..1d5ec35e 100644 --- a/src/com/quollwriter/synonyms/providers/BigHugeLabsSynonymProvider.java +++ b/src/main/java/com/quollwriter/synonyms/providers/BigHugeLabsSynonymProvider.java @@ -6,8 +6,6 @@ import java.util.*; -import com.gentlyweb.utils.*; - import com.quollwriter.*; import com.quollwriter.synonyms.*; @@ -21,7 +19,7 @@ public class BigHugeLabsSynonymProvider implements SynonymProvider public static final String WORD_TAG = "[[WORD]]"; private String language = null; - + public BigHugeLabsSynonymProvider() { @@ -29,18 +27,18 @@ public BigHugeLabsSynonymProvider() public boolean isLanguageSupported (String language) { - + return true; - + } - + public void init (String language) { - + this.language = language; - + } - + public void setUseCache (boolean v) { @@ -59,11 +57,11 @@ public String getWordTypes (String word) public boolean hasSynonym (String word) throws GeneralException { - + return this.getSynonyms (word) != null; - + } - + public Synonyms getSynonyms (String word) throws GeneralException { @@ -92,9 +90,9 @@ public Synonyms getSynonyms (String word) } - String url = Environment.getProperty (BigHugeLabsSynonymProvider.URL_PROPERTY_NAME); + String url = UserProperties.get (BigHugeLabsSynonymProvider.URL_PROPERTY_NAME); - url = StringUtils.replaceString (url, + url = Utils.replaceString (url, BigHugeLabsSynonymProvider.WORD_TAG, word); diff --git a/src/com/quollwriter/synonyms/providers/BuiltInSynonymProvider.java b/src/main/java/com/quollwriter/synonyms/providers/BuiltInSynonymProvider.java similarity index 87% rename from src/com/quollwriter/synonyms/providers/BuiltInSynonymProvider.java rename to src/main/java/com/quollwriter/synonyms/providers/BuiltInSynonymProvider.java index 2d98d642..9377ed04 100644 --- a/src/com/quollwriter/synonyms/providers/BuiltInSynonymProvider.java +++ b/src/main/java/com/quollwriter/synonyms/providers/BuiltInSynonymProvider.java @@ -1,15 +1,14 @@ package com.quollwriter.synonyms.providers; import java.io.*; +import java.nio.file.*; import java.net.*; import java.util.*; -import com.gentlyweb.utils.*; - import com.quollwriter.*; - +import com.quollwriter.uistrings.*; import com.quollwriter.synonyms.*; public class BuiltInSynonymProvider implements SynonymProvider @@ -19,10 +18,10 @@ public class BuiltInSynonymProvider implements SynonymProvider public static final String THESAURUS_FILE_INDEX_NAME_PROPERTY_NAME = "thesaurusIndexFileName"; - private List synInd = new ArrayList (); + private List synInd = new ArrayList<> (); private RandomAccessFile thesaurusFile = null; private File tFile = null; - private Map synCache = new HashMap (); + private Map synCache = new HashMap<> (); private boolean useCache = false; public BuiltInSynonymProvider() @@ -30,69 +29,78 @@ public BuiltInSynonymProvider() } + private Path getThesaurusDirPath (String lang) + { + + return Environment.getUserPath (Constants.THESAURUS_DIR).resolve (lang); + + } + private File getIndexFile (String lang) { - - String thesaurusDir = Environment.getUserQuollWriterDir ().getPath () + "/thesaurus/" + lang; - return new File (thesaurusDir + "/index.txt"); - + return this.getThesaurusDirPath (lang).resolve ("index.txt").toFile (); + + // TODO Check return new File (thesaurusDir + "/index.txt"); + } - + private File getWordsFile (String lang) { - - String thesaurusDir = Environment.getUserQuollWriterDir ().getPath () + "/thesaurus/" + lang; - - return new File (thesaurusDir + "/words.txt"); - + + return this.getThesaurusDirPath (lang).resolve ("words.txt").toFile (); + + // REMOVE String thesaurusDir = Environment.getUserQuollWriterDir ().getPath () + "/thesaurus/" + lang; + + // REMOVE return new File (thesaurusDir + "/words.txt"); + } - + public boolean isLanguageSupported (String lang) { - + if (this.hasThesaurusJarResourceFile ()) { - + return true; - + } - + // Look in the thesaurus directory. - if (Environment.isEnglish (lang)) + if (UILanguageStrings.isEnglish (lang)) { - + lang = Constants.ENGLISH; //"English"; - + } - + File wordsFile = this.getWordsFile (lang); - + if (!wordsFile.exists ()) { - + return false; - + } - + File indexFile = this.getIndexFile (lang); - + if (!indexFile.exists ()) { - + return false; - + } - + return true; - + } - + private boolean hasThesaurusJarResourceFile () { - - String thesaurusIndexFileName = Environment.getProperty (BuiltInSynonymProvider.THESAURUS_FILE_INDEX_NAME_PROPERTY_NAME); + + String thesaurusIndexFileName = UserProperties.get (BuiltInSynonymProvider.THESAURUS_FILE_INDEX_NAME_PROPERTY_NAME); if (thesaurusIndexFileName == null) { @@ -104,127 +112,128 @@ private boolean hasThesaurusJarResourceFile () String thesaurusIndexFileResourceName = Constants.DICTIONARIES_DIR + thesaurusIndexFileName; // Read the index file. - return Environment.getResourceStream (thesaurusIndexFileResourceName) != null; - + return Utils.getResourceStream (thesaurusIndexFileResourceName) != null; + } - + public void init (String language) throws GeneralException { - + BufferedReader indexReader = null; File wordsFile = null; - + // Check for legacy, pre v2.2 or if the user still has the dictionaries jar. if (this.hasThesaurusJarResourceFile ()) { - - String thesaurusFileName = Environment.getProperty (BuiltInSynonymProvider.THESAURUS_FILE_NAME_PROPERTY_NAME); - + + String thesaurusFileName = UserProperties.get (BuiltInSynonymProvider.THESAURUS_FILE_NAME_PROPERTY_NAME); + if (thesaurusFileName == null) { - + throw new GeneralException ("No: " + BuiltInSynonymProvider.THESAURUS_FILE_NAME_PROPERTY_NAME + " property found."); - + } - - String thesaurusIndexFileName = Environment.getProperty (BuiltInSynonymProvider.THESAURUS_FILE_INDEX_NAME_PROPERTY_NAME); - + + String thesaurusIndexFileName = UserProperties.get (BuiltInSynonymProvider.THESAURUS_FILE_INDEX_NAME_PROPERTY_NAME); + if (thesaurusIndexFileName == null) { - + throw new GeneralException ("No: " + BuiltInSynonymProvider.THESAURUS_FILE_INDEX_NAME_PROPERTY_NAME + " property found."); - + } - + String thesaurusFileResourceName = Constants.DICTIONARIES_DIR + thesaurusFileName; - - File thesaurusFile = new File (Environment.getUserQuollWriterDir ().getPath () + "/" + thesaurusFileName); - + + // TODO Improve... + File thesaurusFile = Environment.getUserPath (Constants.DICTIONARIES_DIR).resolve (thesaurusFileName).toFile (); + if (!thesaurusFile.exists ()) { - + // Extract the thesaurus file to the Quoll Writer directory. - Environment.extractResourceToFile (thesaurusFileResourceName, - thesaurusFile); - + Utils.extractResourceToFile (thesaurusFileResourceName, + thesaurusFile); + } - + this.tFile = thesaurusFile; - + String thesaurusIndexFileResourceName = Constants.DICTIONARIES_DIR + thesaurusIndexFileName; - + // Read the index file. - indexReader = new BufferedReader (new InputStreamReader (Environment.getResourceStream (thesaurusIndexFileResourceName))); + indexReader = new BufferedReader (new InputStreamReader (Utils.getResourceStream (thesaurusIndexFileResourceName))); } else { - + String lang = language; - + // Look in the thesaurus directory. - if (Environment.isEnglish (language)) + if (UILanguageStrings.isEnglish (language)) { - + lang = Constants.ENGLISH; //"English"; - + } - + File thesaurusFile = this.getWordsFile (lang); - + if (!thesaurusFile.exists ()) { - + throw new GeneralException ("Unable to find thesaurus words file for language: " + lang + " at: " + thesaurusFile); - + } - + this.tFile = thesaurusFile; - + File indexFile = this.getIndexFile (lang); - + if (!indexFile.exists ()) { - + throw new GeneralException ("Unable to find thesaurus index file for language: " + lang + " at: " + indexFile); - + } - + try { - + indexReader = new BufferedReader (new FileReader (indexFile)); - + } catch (Exception e) { - + throw new GeneralException ("Unable to read thesaurus index file for language: " + lang + " at: " + indexFile); - + } - + } - + if (indexReader == null) { - + throw new GeneralException ("Unable to find thesaurus index file for language: " + language); - + } - + String l = null; try diff --git a/src/com/quollwriter/synonyms/providers/SynonymIndex.java b/src/main/java/com/quollwriter/synonyms/providers/SynonymIndex.java similarity index 100% rename from src/com/quollwriter/synonyms/providers/SynonymIndex.java rename to src/main/java/com/quollwriter/synonyms/providers/SynonymIndex.java diff --git a/src/com/quollwriter/text/DialogueConstraints.java b/src/main/java/com/quollwriter/text/DialogueConstraints.java similarity index 100% rename from src/com/quollwriter/text/DialogueConstraints.java rename to src/main/java/com/quollwriter/text/DialogueConstraints.java diff --git a/src/com/quollwriter/text/DialogueInd.java b/src/main/java/com/quollwriter/text/DialogueInd.java similarity index 100% rename from src/com/quollwriter/text/DialogueInd.java rename to src/main/java/com/quollwriter/text/DialogueInd.java diff --git a/src/com/quollwriter/text/IgnoreCheckbox.java b/src/main/java/com/quollwriter/text/IgnoreCheckbox.java similarity index 100% rename from src/com/quollwriter/text/IgnoreCheckbox.java rename to src/main/java/com/quollwriter/text/IgnoreCheckbox.java diff --git a/src/com/quollwriter/text/Issue.java b/src/main/java/com/quollwriter/text/Issue.java similarity index 87% rename from src/com/quollwriter/text/Issue.java rename to src/main/java/com/quollwriter/text/Issue.java index bfa3d4bc..b0e0956d 100644 --- a/src/com/quollwriter/text/Issue.java +++ b/src/main/java/com/quollwriter/text/Issue.java @@ -12,6 +12,8 @@ public class Issue private String desc = null; private Position startPos = null; private Position endPos = null; + private com.quollwriter.ui.fx.components.TextEditor.Position startPos2 = null; + private com.quollwriter.ui.fx.components.TextEditor.Position endPos2 = null; private int startIssuePosition = -1; private int length = -1; private String ruleId = null; @@ -249,4 +251,34 @@ public void setEndPosition (Position p) } + + + public com.quollwriter.ui.fx.components.TextEditor.Position getStartPosition2 () + { + + return this.startPos2; + + } + + public com.quollwriter.ui.fx.components.TextEditor.Position getEndPosition2 () + { + + return this.endPos2; + + } + + public void setStartPosition2 (com.quollwriter.ui.fx.components.TextEditor.Position p) + { + + this.startPos2 = p; + + } + + public void setEndPosition2 (com.quollwriter.ui.fx.components.TextEditor.Position p) + { + + this.endPos2 = p; + + } + } diff --git a/src/com/quollwriter/text/IssueSorter.java b/src/main/java/com/quollwriter/text/IssueSorter.java similarity index 100% rename from src/com/quollwriter/text/IssueSorter.java rename to src/main/java/com/quollwriter/text/IssueSorter.java diff --git a/src/com/quollwriter/text/NoTextBlock.java b/src/main/java/com/quollwriter/text/NoTextBlock.java similarity index 100% rename from src/com/quollwriter/text/NoTextBlock.java rename to src/main/java/com/quollwriter/text/NoTextBlock.java diff --git a/src/com/quollwriter/text/Paragraph.java b/src/main/java/com/quollwriter/text/Paragraph.java similarity index 82% rename from src/com/quollwriter/text/Paragraph.java rename to src/main/java/com/quollwriter/text/Paragraph.java index 9baacd01..9f7d8c3e 100644 --- a/src/com/quollwriter/text/Paragraph.java +++ b/src/main/java/com/quollwriter/text/Paragraph.java @@ -8,7 +8,7 @@ public class Paragraph implements TextBlock { - + private List sentences = new ArrayList (); private int start = -1; private String paragraph = null; @@ -17,89 +17,89 @@ public class Paragraph implements TextBlock private int wordCount = -1; private List words = null; private DialogueInd inDialogue = null; - + public Paragraph (String paragraph, int start) { - + this.start = start; - + if (paragraph == null) { - + return; - + } - + // Split up the sentences. BreakIterator bi = BreakIterator.getSentenceInstance (); - + bi.setText (paragraph); - + Sentence last = null; - + int st = bi.first (); int en = -1; - + int openQuoteCount = 0; - + this.inDialogue = new DialogueInd (); - + while (st != BreakIterator.DONE) { - + en = bi.next (); - + if (en == BreakIterator.DONE) { - + break; - + } - + String t = paragraph.substring (st, en); - + if (t.length () == 0) { - + st = en; - + continue; - + } - + Sentence s = new Sentence (this, t, st, this.inDialogue); - + this.sentences.add (s); - + if (last != null) { - + s.setPrevious (last); last.setNext (s); - + } - + last = s; - + st = en; - + } - + this.paragraph = paragraph;//.trim (); - + } - + @Override public String toString () { - + Map data = new LinkedHashMap (); - + data.put ("type", "paragraph"); data.put ("wordCount", @@ -118,112 +118,112 @@ public String toString () this.getSyllableCount ()); data.put ("threeSyllableWordCount", this.getThreeSyllableWordCount ()); - - return Environment.formatObjectToStringProperties (data); - - } - + + return Environment.formatObjectToStringProperties (data); + + } + public List getWords () { - + List ret = null; - + if (this.words == null) { - + ret = new ArrayList (); - + for (Sentence s : this.sentences) { - + ret.addAll (s.getWords ()); - + } this.words = ret; - + } - + return ret; - + } public int getThreeSyllableWordCount () { int c = 0; - + for (Sentence s : this.sentences) { - + c += s.getThreeSyllableWordCount (); - + } - + return c; - + } - + public int getSyllableCount () { int c = 0; - + for (Sentence s : this.sentences) { - + c += s.getSyllableCount (); - + } - + return c; - + } - + public int getSentenceCount () { - + return this.sentences.size (); - + } - + public int getWordCount () { - + if (this.wordCount > -1) { - + return this.wordCount; - + } - + int wc = 0; - + for (Sentence s : this.sentences) { - + wc += s.getWordCount (); - + } - + this.wordCount = wc; - + return wc; - + } - + public List getChildren () { - + return this.sentences; - + } - + public List getSentences () { - + return this.getChildren (); - + } /** @@ -237,37 +237,37 @@ public List getSentences () */ public Sentence getNextClosestSentenceTo (int i) { - + Sentence f = this.getSentenceAt (i); - + return f; - + /* - *Since all text is now represented by sentences there is no need to + *Since all text is now represented by sentences there is no need to if (f != null) { - + return f; - + } - + for (Sentence s : this.sentences) { - + if (s.getStart () >= i) { - + f = s; break; - + } - + } - + return f; */ } - + /** * For index i, find the sentence that either contains the index or the previous sentence closest * to the index. This uses the internal paragraph index not the all text index. @@ -279,37 +279,37 @@ public Sentence getNextClosestSentenceTo (int i) */ public Sentence getPreviousClosestSentenceTo (int i) { - + Sentence f = this.getSentenceAt (i); - + return f; -/* +/* if (f != null) { - + return f; - + } - + int l = this.sentences.size () - 1; - + for (int j = l; j > -1; j--) { - + Sentence s = this.sentences.get (j); - + if (s.getStart () <= i) { - + f = s; break; - + } - + } - + return f; - */ + */ } /** @@ -320,25 +320,25 @@ public Sentence getPreviousClosestSentenceTo (int i) */ public int getAllTextStartOffset () { - + return this.getStart (); - + } - + public int getAllTextEndOffset () { - + return this.getEnd (); - + } - + public int getEnd () { - + return this.start + this.paragraph.length () - 1; - + } - + /** * Return where the paragraph is in the overall text. * @@ -346,119 +346,119 @@ public int getEnd () */ public int getStart () { - + return this.start; - + } - + public Sentence getSentenceAt (int i) { - + for (Sentence s : this.sentences) { - + if ((s.getEnd () >= i) && (s.getStart () <= i) ) { - + return s; - + } - + } - + return null; - + } - + public NoTextBlock getParent () { - + return null; - + } - + public String getText () { - + return this.paragraph; - + } - + public Paragraph getNext () { - + return this.next; - + } - + public Paragraph getPrevious () { - + return this.prev; - + } - + public void setNext (Paragraph p) { - + this.next = p; - + } - + public void setPrevious (Paragraph p) { - + this.prev = p; - + } - + public boolean isWordInDialogue (Word w) { - + return false; - + } public boolean isFirst (Sentence s) { - + if (s == null) { - + return false; - + } - + Sentence f = this.getFirstSentence (); - + if (f != null) { - + return f == s; - + } - + return false; - + } - + public Sentence getLastSentence () { - + return this.sentences.get (this.sentences.size () - 1); - + } - + public Sentence getFirstSentence () { - + return this.sentences.get (0); - + } - + /** * Look for the collection of words in each sentence. * @@ -469,32 +469,32 @@ public Sentence getFirstSentence () public Map> findInSentences (String text, DialogueConstraints constraints) { - - Map> matches = new LinkedHashMap (); - + + Map> matches = new LinkedHashMap<> (); + for (Sentence s : this.sentences) { - + NavigableSet inds = s.find (text, constraints); - + if ((inds != null) && (inds.size () > 0) ) { - + matches.put (s, inds); - + } - + } - + return matches; - + } - + /** * Get the text in this paragraph, marked up as html with the markup passed in. * It assumes that the markup is relative to the getAllTextStartOffset. @@ -504,22 +504,22 @@ public Map> findInSentences (String */ public String markupAsHTML (Markup m) { - + if (m == null) { - + return this.paragraph; - + } - + Markup pm = new Markup (m, this.getAllTextStartOffset (), this.getAllTextEndOffset ()); - + pm.shiftBy (-1 * this.getAllTextStartOffset ()); - + return pm.markupAsHTML (this.paragraph); - + } - -} \ No newline at end of file + +} diff --git a/src/main/java/com/quollwriter/text/ProblemFinder.java b/src/main/java/com/quollwriter/text/ProblemFinder.java new file mode 100644 index 00000000..26aadba1 --- /dev/null +++ b/src/main/java/com/quollwriter/text/ProblemFinder.java @@ -0,0 +1,1227 @@ +package com.quollwriter.text; + +import java.awt.Color; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.event.*; + +import java.text.*; + +import java.util.*; + +import javax.swing.*; +import javax.swing.border.*; +import javax.swing.text.*; + +import com.quollwriter.*; +import com.quollwriter.events.*; +import com.quollwriter.text.rules.*; + +import com.quollwriter.ui.*; +import com.quollwriter.ui.panels.*; +import com.quollwriter.ui.components.BlockPainter; +import com.quollwriter.ui.components.QTextEditor; +import com.quollwriter.ui.components.TextUnderlinePainter; +import com.quollwriter.ui.components.ActionAdapter; + +import static com.quollwriter.LanguageStrings.*; +import static com.quollwriter.Environment.getUIString; + +public class ProblemFinder extends Box +{ + + private QuollEditorPanel editor = null; + private int lastCaret = -1; + private List ignores = new ArrayList (); + private ActionListener showIgnores = null; + private boolean endReached = false; + private boolean startReached = false; + private boolean doSentences = false; + private boolean donePara = false; + private String currPara = null; + private Paragraph paragraph = null; + private Sentence sentence = null; + private TextIterator textIter = null; + private TextBlockIterator iter = null; + private int start = 0; + private int end = -1; + private JLabel limitLabel = null; + private JLabel noProblemsLabel = null; + private int origStart = -1; + private int origEnd = -1; + private Box issuesBox = null; + private boolean inited = false; + private BlockPainter lineHighlight = null; + private TextUnderlinePainter issueHighlight = null; + private ProjectViewer viewer = null; + + public ProblemFinder (QuollEditorPanel editor, + ProjectViewer viewer) + { + + super (BoxLayout.Y_AXIS); + + this.lineHighlight = ProblemFinder.getTextBlockHighlighter (); + this.issueHighlight = ProblemFinder.getIssueHighlighter (); + + this.setAlignmentX (Component.LEFT_ALIGNMENT); + this.setMaximumSize (new Dimension (Short.MAX_VALUE, + Short.MAX_VALUE)); + + this.editor = editor; + this.viewer = viewer; + + // Load the ignores. + try + { + + this.editor.getChapter ().initProblemFinderIgnoreDocumentPositions (this.editor.getEditor ().getDocument ()); + +/* + ((ProjectViewer) this.editor.getViewer ()).getProblemFinderIgnores (this.editor.getChapter (), + this.editor.getEditor ().getDocument ()); +*/ + } catch (Exception e) + { + + Environment.logError ("Unable to load problem finder ignores for chapter: " + + this.editor.getChapter (), + e); + + } + + final ProblemFinder _this = this; + + this.editor.getEditor ().getCaret ().addChangeListener (new javax.swing.event.ChangeListener () + { + + public void stateChanged (javax.swing.event.ChangeEvent ev) + { + + if (!_this.isShowing ()) + { + + return; + + } + + _this.inited = false; + + _this.start = _this.editor.getEditor ().getSelectionStart (); + _this.end = _this.editor.getEditor ().getSelectionEnd (); + + } + + }); + + java.util.List prefix = new ArrayList<> (); + prefix.add (LanguageStrings.project); + prefix.add (LanguageStrings.editorpanel); + prefix.add (LanguageStrings.actions); + prefix.add (LanguageStrings.problemfinder); + + this.limitLabel = new JLabel (Environment.getUIString (prefix, + LanguageStrings.limit), + //"Limiting find to selected text.", + Environment.getIcon ("information", + Constants.ICON_MENU), + SwingConstants.TRAILING); + + this.limitLabel.setVisible (false); + + this.limitLabel.setBorder (UIUtils.createPadding (5, 10, 3, 3)); + + this.noProblemsLabel = new JLabel (Environment.getUIString (prefix, + LanguageStrings.noproblemsfound), + //"No problems found.", + Environment.getIcon ("information", + Constants.ICON_MENU), + SwingConstants.TRAILING); + + this.noProblemsLabel.setAlignmentX (Component.LEFT_ALIGNMENT); + this.noProblemsLabel.setOpaque (false); + this.noProblemsLabel.setBorder (UIUtils.createPadding (5, 10, 3, 3)); + this.noProblemsLabel.setVisible (false); + + this.issuesBox = new Box (BoxLayout.Y_AXIS); + this.issuesBox.setAlignmentX (Component.LEFT_ALIGNMENT); + + this.add (this.limitLabel); + this.add (this.noProblemsLabel); + this.add (this.issuesBox); + + } + + public void removeAllIgnores () + { + + this.editor.getChapter ().getProblemFinderIgnores ().clear (); + + try + { + + this.viewer.saveProblemFinderIgnores (this.editor.getChapter ()); + + } catch (Exception e) { + + Environment.logError ("Unable to save problem finder ignores for chapter: " + + this.editor.getChapter (), + e); + + UIUtils.showErrorMessage (this.viewer, + Environment.getUIString (LanguageStrings.project, + LanguageStrings.editorpanel, + LanguageStrings.actions, + LanguageStrings.problemfinder, + LanguageStrings.unignoreall, + LanguageStrings.actionerror)); + //"Unable to remove all ignores."); + + return; + + } + + if (this.showIgnores != null) + { + + this.showIgnores.actionPerformed (new ActionEvent (this, + 0, + "")); + + } + + this.viewer.fireProjectEvent (ProjectEvent.PROBLEM_FINDER, + ProjectEvent.UNIGNORE); + + } + + public Set getIgnoredIssues () + { + + return this.editor.getChapter ().getProblemFinderIgnores (); + + } + + public void saveIgnores () + { + + // Check to see if they are still valid. + try + { + + this.viewer.saveProblemFinderIgnores (this.editor.getChapter ()); + + } catch (GeneralException e) + { + + Environment.logError ("Unable to save problem finder ignores for chapter: " + + this.editor.getChapter (), + e); + + } + + } + + public void reset () + { + + this.getIgnores (); + + this.clearHighlights (); + + } + + private void init (int start, + int end) + { + + this.start = start; + this.end = end; + + this.getIgnores (); + this.clearHighlights (); + + if (this.end < this.start) + { + + this.end = -1; + + } + + if (this.start == this.end) + { + + this.end = -1; + + } + + this.noProblemsLabel.setVisible (false); + this.clearIssuesBox (); + + this.limitLabel.setVisible (this.end > -1); + + this.iter = new TextBlockIterator (this.editor.getEditor ().getText (), + this.start, + this.end); + + this.inited = true; + + } + + public int start () + throws Exception + { + + this.origStart = this.editor.getEditor ().getSelectionStart (); + this.origEnd = this.editor.getEditor ().getSelectionEnd (); + + this.init (this.origStart, + this.origEnd); + + return this.next (); + + } + + private void clearHighlights () + { + + this.editor.getEditor ().removeAllHighlights (this.lineHighlight); + this.editor.getEditor ().removeAllHighlights (this.issueHighlight); + + } + + private int processTextBlock (TextBlock b) + throws Exception + { + + if (b == null) + { + + return 0; + + } + + if (b instanceof Paragraph) + { + + return this.handleParagraph ((Paragraph) b); + + } + + if (b instanceof Sentence) + { + + return this.handleSentence ((Sentence) b); + + } + + throw new GeneralException ("Type: " + + b.getClass ().getName () + + " not supported."); + + } + + private int handleParagraph (Paragraph p) + throws Exception + { + + List issues = RuleFactory.getParagraphIssues (p, + this.viewer.getProject ().getProperties ()); + + this.setPositions (issues); + + if ((issues.size () != 0) + && + (!this.allIgnores (issues)) + ) + { + + this.handleIssues (issues, + p); + + return issues.size (); + + } + + return 0; + + } + + private int handleSentence (Sentence s) + throws Exception + { + + List issues = RuleFactory.getSentenceIssues (s, + this.viewer.getProject ().getProperties ()); + + this.setPositions (issues); + + if ((issues.size () != 0) + && + (!this.allIgnores (issues)) + ) + { + + this.handleIssues (issues, + s); + + return issues.size (); + + } + + return 0; + + } + + public int next () + throws Exception + { + + if (!this.inited) + { + + this.init (this.start, + this.end); + + } + + this.noProblemsLabel.setVisible (false); + + // Prevent the block being highlighted but ensure that inited is still true since the caret + // change will set it to false. + this.editor.getEditor ().setSelectionEnd (this.start); + + this.inited = true; + + final ProblemFinder _this = this; + + this.getIgnores (); + + this.clearHighlights (); + + TextBlock b = null; + + while ((b = this.iter.next ()) != null) + { + + Environment.logDebugMessage ("Looking for problems in: " + b); + + int c = this.processTextBlock (b); + + if (c > 0) + { + + Environment.logDebugMessage ("Got: " + c + " problems for text: " + b); + + return c; + + } + + } + + this.addNoProblems (); + + if (this.end > -1) + { + + java.util.List prefix = Arrays.asList (project,editorpanel,actions,problemfinder,nomoreproblems,selected,LanguageStrings.end); + + UIUtils.showMessage (this.viewer, + getUIString (prefix,title), + //"No more problems found", + getUIString (prefix,text), + //"No more problems found in selected text.", + getUIString (buttons,finish), + //"Finish", + new ActionListener () + { + + public void actionPerformed (ActionEvent ev) + { + + _this.editor.getEditor ().select (_this.start, + _this.end); + + _this.inited = false; + + } + + }); + + return 0; + + } + + ActionListener onCancel = new ActionListener () + { + + public void actionPerformed (ActionEvent ev) + { + + _this.reset (); + + } + + }; + + final java.util.List prefix = new ArrayList<> (); + prefix.add (LanguageStrings.project); + prefix.add (LanguageStrings.editorpanel); + prefix.add (LanguageStrings.actions); + prefix.add (LanguageStrings.problemfinder); + prefix.add (LanguageStrings.nomoreproblems); + prefix.add (LanguageStrings.end); + + UIUtils.createQuestionPopup (this.viewer, + Environment.getUIString (prefix, + LanguageStrings.title), + //"No more problems found", + Constants.INFO_ICON_NAME, + Environment.getUIString (prefix, + LanguageStrings.text), + //"No more problems found. Return to the start of the {chapter}?", + Environment.getUIString (prefix, + LanguageStrings.buttons, + LanguageStrings.confirm), + //"Yes, return to the start", + Environment.getUIString (prefix, + LanguageStrings.buttons, + LanguageStrings.cancel), + //null, + new ActionListener () + { + + public void actionPerformed (ActionEvent ev) + { + + UIUtils.doLater (new ActionListener () + { + + public void actionPerformed (ActionEvent ev) + { + + try + { + + _this.init (0, + -1); + + _this.next (); + + } catch (Exception e) { + + Environment.logError ("Unable to move back to start", + e); + + UIUtils.showErrorMessage (_this.viewer, + Environment.getUIString (prefix, + LanguageStrings.actionerror)); + //"Unable to move back to start of {chapter}"); + + } + + } + + }); + + } + + }, + onCancel, + onCancel, + null); + + return 0; + + } + + public int previous () + throws Exception + { + + if (!this.inited) + { + + this.init (this.start, + this.end); + + } + + this.noProblemsLabel.setVisible (false); + + final ProblemFinder _this = this; + + this.getIgnores (); + + this.clearHighlights (); + + TextBlock b = null; + + while ((b = this.iter.previous ()) != null) + { + + Environment.logDebugMessage ("Looking for problems in: " + b); + + int c = this.processTextBlock (b); + + if (c > 0) + { + + Environment.logDebugMessage ("Got: " + c + " problems for text: " + b); + + return c; + + } + + } + + this.addNoProblems (); + + if (this.end > -1) + { + + java.util.List prefix = Arrays.asList (project,editorpanel,actions,problemfinder,nomoreproblems,selected,LanguageStrings.end); + + UIUtils.showMessage (this.viewer, + getUIString (prefix,title), + //"No more problems found", + getUIString (prefix,text), + //"No more problems found in selected text.", + getUIString (buttons,finish), + //"Finish", + null); + + return 0; + + } + + final java.util.List prefix = new ArrayList<> (); + prefix.add (LanguageStrings.project); + prefix.add (LanguageStrings.editorpanel); + prefix.add (LanguageStrings.actions); + prefix.add (LanguageStrings.problemfinder); + prefix.add (LanguageStrings.nomoreproblems); + prefix.add (LanguageStrings.start); + + UIUtils.showMessage ((PopupsSupported) this.editor, + Environment.getUIString (prefix, + LanguageStrings.title), + //"No more problems", + Environment.getUIString (prefix, + LanguageStrings.text)); + //"No more problems found"); + + return 0; + + } + + private void addNoProblems () + { + + this.clearIssuesBox (); + + this.noProblemsLabel.setVisible (true); + + this.getParent ().getParent ().validate (); + this.getParent ().getParent ().repaint (); + + } + + public void removeCheckboxesForRule (Rule r) + { + + for (IgnoreCheckbox b : this.ignores) + { + + if (r.getId ().equals (b.issue.getRule ().getId ())) + { + + this.remove (b); + + } + + } + + this.getParent ().getParent ().validate (); + this.getParent ().getParent ().repaint (); + + } + + private void getIgnores () + { + + for (IgnoreCheckbox b : this.ignores) + { + + if (b.isSelected ()) + { + + this.editor.getChapter ().getProblemFinderIgnores ().add (b.issue); + + this.viewer.fireProjectEvent (ProjectEvent.PROBLEM_FINDER, + ProjectEvent.IGNORE); + + } else { + + if (this.editor.getChapter ().getProblemFinderIgnores ().remove (b.issue)) + { + + this.viewer.fireProjectEvent (ProjectEvent.PROBLEM_FINDER, + ProjectEvent.UNIGNORE); + + } + + } + + } + + this.ignores = new ArrayList (); + + } + + private IgnoreCheckbox createIssueItem (Issue iss) + { + + IgnoreCheckbox cb = new IgnoreCheckbox (iss.getDescription (), + iss, + this.editor, + this.viewer); + cb.setAlignmentX (Component.LEFT_ALIGNMENT); + cb.setOpaque (false); + cb.setBorder (new EmptyBorder (5, + 10, + 3, + 3)); + + final ProblemFinder _this = this; + + final QTextEditor ed = this.editor.getEditor (); + + final Issue issue = iss; + + cb.addMouseListener (new MouseEventHandler () + { + + @Override + public void mouseEntered (MouseEvent ev) + { + + try + { + + ed.addHighlight (iss.getStartIssuePosition (), + iss.getEndIssuePosition (), + _this.issueHighlight, + false); + + } catch (Exception e) + { + + // Ignore. + + } + + } + + @Override + public void mouseExited (MouseEvent ev) + { + + ed.removeAllHighlights (_this.issueHighlight); + + } + + }); + + this.ignores.add (cb); + + return cb; + + } + + private void setPositions (List issues) + { + + try + { + + for (Issue i : issues) + { + + i.setStartPosition (this.editor.getEditor ().getDocument ().createPosition (i.getStartIssuePosition ())); + + // Set the end position of the sentence. + i.setEndPosition (this.editor.getEditor ().getDocument ().createPosition (i.getEndIssuePosition ())); + + } + + } catch (Exception e) + { + + // Ignore. + + } + + } + + private void clearIssuesBox () + { + + this.issuesBox.removeAll (); + + } + + private void handleIssues (final List issues, + final TextBlock textBlock) + throws Exception + { + + Collections.sort (issues, + new IssueSorter ()); + + List ignored = this.removeIgnores (issues); + + if (issues.size () > 0) + { + + this.clearIssuesBox (); + + final ProblemFinder _this = this; + + this.lastCaret = this.editor.getEditor ().getSelectionStart (); + + // Convert to the view. + int height = -1; + + UIUtils.doLater (new ActionListener () + { + + public void actionPerformed (ActionEvent ev) + { + + try + { + + _this.editor.scrollToPosition (textBlock.getAllTextStartOffset ());//selStart);//_this.sentIter.getOffset ()); + + } catch (Exception e) { + + Environment.logError ("Unable to scroll to: " + + textBlock.getAllTextStartOffset (), //selStart, //_this.sentIter.getOffset (), + e); + + } + + } + + }); + + final QTextEditor ed = this.editor.getEditor (); + + for (Issue i : issues) + { + + this.issuesBox.add (this.createIssueItem (i)); +/* + if (i.getRule () instanceof SentenceRule) + { + + this.issuesBox.add (this.createSentenceIssueItem (i, + (Sentence) textBlock)); + + } else { + + this.issuesBox.add (this.createIssueItem (i)); + + } +*/ + } + + if (ignored.size () > 0) + { + + java.util.List prefix = new ArrayList<> (); + prefix.add (LanguageStrings.project); + prefix.add (LanguageStrings.editorpanel); + prefix.add (LanguageStrings.actions); + prefix.add (LanguageStrings.problemfinder); + prefix.add (LanguageStrings.unignoreissues); + + String t = null; + + if (ignored.size () == 1) + { + + t = Environment.getUIString (prefix, + LanguageStrings.single); + + } else { + + t = String.format (Environment.getUIString (prefix, + LanguageStrings.plural), + Environment.formatNumber (ignored.size ())); + + } + + final JLabel l = UIUtils.createClickableLabel (t, + Environment.getIcon ("warning", + Constants.ICON_MENU)); + + l.setBorder (new EmptyBorder (5, + 10, + 3, + 3)); + + this.issuesBox.add (l); + + final java.util.List ignoredItems = new ArrayList (); + + for (Issue i : ignored) + { + + IgnoreCheckbox icb = this.createIssueItem (i); + + ignoredItems.add (icb); + icb.setVisible (false); + icb.setSelected (true); + this.issuesBox.add (icb); + + } + + this.showIgnores = new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + for (IgnoreCheckbox icb : ignoredItems) + { + + icb.setVisible (true); + + icb.setSelected ("selected".equals (ev.getActionCommand ())); + + //_this.issuesToIgnore.remove (icb.issue); + + } + + l.setVisible (false); + + _this.viewer.fireProjectEvent (ProjectEvent.PROBLEM_FINDER, + ProjectEvent.UNIGNORE); + + _this.getParent ().getParent ().validate (); + _this.getParent ().getParent ().repaint (); + + } + + }; + + l.addMouseListener (new MouseAdapter () + { + + public void mousePressed (MouseEvent ev) + { + + _this.showIgnores.actionPerformed (new ActionEvent (l, + 0, + "selected")); + + _this.viewer.fireProjectEvent (ProjectEvent.PROBLEM_FINDER, + ProjectEvent.UNIGNORE); + + } + + }); + + } + + int end = textBlock.getAllTextEndOffset () + 1; + + if (textBlock instanceof Sentence) + { + + end = ((Sentence) textBlock).getLastWord ().getAllTextEndOffset (); + + } + + ed.addHighlight (textBlock.getAllTextStartOffset (), + end, + this.lineHighlight, + false); + + this.getParent ().getParent ().validate (); + this.getParent ().getParent ().repaint (); + + } + + } + + private boolean allIgnores (List issues) + { + + for (Issue i : issues) + { + + if (!this.shouldIgnore (i)) + { + + return false; + + } + + } + + return true; + + } + + private List removeIgnores (List issues) + { + + Iterator iter = issues.iterator (); + + List ignored = new ArrayList (); + + while (iter.hasNext ()) + { + + Issue i = iter.next (); + + if (this.shouldIgnore (i)) + { + + ignored.add (i); + iter.remove (); + + } + + } + + return ignored; + + } + + private boolean shouldIgnore (Issue iss) + { + + for (Issue i : this.editor.getChapter ().getProblemFinderIgnores ()) + { + + if (i.equals (iss)) + { + + return true; + + } + + } + + return false; + + } + + private class TextBlockIterator + { + + private TextIterator iter = null; + private Paragraph para = null; + private Sentence sent = null; + private int endAt = -1; + private int startAt = -1; + private TextBlock current = null; + + public TextBlockIterator (String text, + int startAt, + int endAt) + { + + this.iter = new TextIterator (text); + this.startAt = startAt; + + this.endAt = endAt; + + } + + public TextBlock next () + { + + if (this.para == null) + { + + this.para = this.iter.getNextClosestParagraphTo (this.startAt); + + if (this.para == null) + { + + // At the end. + return null; + + } + + if (this.startAt > this.para.getStart ()) + { + + this.sent = this.para.getNextClosestSentenceTo (this.startAt - this.para.getStart ()); + + return this.sent; + + } + + } else { + + if (this.sent == null) + { + + this.sent = this.para.getFirstSentence (); + + } else { + + this.sent = this.sent.getNext (); + + } + + if (this.sent == null) + { + + // Get the next paragraph. + this.para = this.para.getNext (); + + } else { + + if ((this.sent.getAllTextStartOffset () > this.endAt) + && + (this.endAt > -1) + ) + { + + return null; + + } + + return this.sent; + + } + + if (this.para == null) + { + + // Reached the end; + return null; + + } + + } + + if ((this.para.getAllTextStartOffset () > this.endAt) + && + (this.endAt > -1) + ) + { + + return null; + + } + + return this.para; + + } + + public TextBlock previous () + { + + if (this.para == null) + { + + this.para = this.iter.getPreviousClosestParagraphTo (this.startAt); + + if (this.para == null) + { + + return null; + + } + + if (this.startAt > this.para.getEnd ()) + { + + this.sent = this.para.getLastSentence (); + + } else { + + this.sent = this.para.getPreviousClosestSentenceTo (this.startAt - this.para.getStart ()); + + } + + } else { + + if (this.sent == null) + { + + this.para = this.para.getPrevious (); + + if (this.para == null) + { + + return null; + + } + + this.sent = this.para.getLastSentence (); + + } else { + + this.sent = this.sent.getPrevious (); + + } + + if (this.sent == null) + { + + if ((this.startAt > this.para.getAllTextStartOffset ()) + && + (this.endAt > -1) + ) + { + + return null; + + } + + return this.para; + + } + + } + + if ((this.startAt > this.sent.getAllTextStartOffset ()) + && + (this.endAt > 1) + ) + { + + return null; + + } + + return this.sent; + + } + + } + + public static BlockPainter getTextBlockHighlighter () + { + + return new BlockPainter (UIUtils.getHighlightColor ()); + + } + + public static TextUnderlinePainter getIssueHighlighter () + { + + return new TextUnderlinePainter (Color.RED); + + } + +} diff --git a/src/main/java/com/quollwriter/text/Rule.java b/src/main/java/com/quollwriter/text/Rule.java new file mode 100644 index 00000000..0ce51a10 --- /dev/null +++ b/src/main/java/com/quollwriter/text/Rule.java @@ -0,0 +1,64 @@ +package com.quollwriter.text; + +import java.util.*; +import javafx.beans.property.*; +//import com.quollwriter.ui.forms.*; + +import com.quollwriter.ui.fx.components.Form; +import com.quollwriter.*; + +import org.dom4j.*; + + +public interface Rule +{ + + public static final String WORD_CATEGORY = "word"; + public static final String SENTENCE_CATEGORY = "sentence"; + public static final String PARAGRAPH_CATEGORY = "paragraph"; + + public String getDescription (); + + public void setDescription (String d); + + public String getDefaultSummary (); + + public String getSummary (); + + public void setSummary (String i); +/* + public List getIssues (String sentence, + boolean inDialogue); +*/ + + public List getIssues (E block); + + public void init (Element root) + throws GeneralException; + + public Element getAsElement (); + + public String getId (); + + public void setId (String id); + + public String getCategory (); + + public void setUserRule (boolean u); + + public boolean isUserRule (); + + public String getEditFormTitle (boolean add); + + public com.quollwriter.ui.forms.Form getEditForm (java.awt.event.ActionListener onSaveComplete, + java.awt.event.ActionListener onCancel, + com.quollwriter.ui.AbstractProjectViewer viewer, + boolean add); + + public void updateFromForm (); + public void updateFromForm2 (); + + public Set getFormItems2 (); + public StringProperty getFormError2 (); + +} diff --git a/src/com/quollwriter/text/Sentence.java b/src/main/java/com/quollwriter/text/Sentence.java similarity index 85% rename from src/com/quollwriter/text/Sentence.java rename to src/main/java/com/quollwriter/text/Sentence.java index f94d88cc..fca16e99 100644 --- a/src/com/quollwriter/text/Sentence.java +++ b/src/main/java/com/quollwriter/text/Sentence.java @@ -8,11 +8,11 @@ public class Sentence implements TextBlock { - + private Paragraph parent = null; private int start = 0; private String sentence = null; - private List words = new ArrayList (); + private List words = new ArrayList<> (); private Sentence next = null; private Sentence previous = null; private int syllableCount = -1; @@ -21,23 +21,23 @@ public class Sentence implements TextBlock public Sentence (String sentence, DialogueInd inDialogue) { - + if (sentence == null) { - + return; - + } - + Word last = null; - + BreakIterator iter = BreakIterator.getWordInstance (); iter.setText (sentence); - + int sl = sentence.length (); - + int st = iter.first (); - + for (int end = iter.next (); end != BreakIterator.DONE; st = end, end = iter.next ()) { @@ -50,137 +50,137 @@ public Sentence (String sentence, continue; } - + char c = ' '; if (word.length () == 1) { - + // Should an opening quote at the start of a sentence always mean - // that the sentence is in dialogue? - + // that the sentence is in dialogue? + c = word.charAt (0); - + } - + Word w = new Word (this, word, st, inDialogue.update (c)); - + this.words.add (w); if (last != null) { - + w.setPrevious (last); last.setNext (w); - + } - + last = w; - - } - - this.sentence = sentence;//.trim (); - + + } + + this.sentence = sentence;//.trim (); + } - + public Sentence (Paragraph parent, String sentence, int start, DialogueInd inDialogue) { - + this (sentence, inDialogue); - + this.parent = parent; this.start = start; - + } - + public int getThreeSyllableWordCount () { - + int c = 0; - + for (Word w : this.words) { - + if (w.getSyllableCount () > 2) { - + c++; - + } - + } - + return c; - + } - + public int getSyllableCount () { - + if (this.syllableCount == -1) { - + int c = 0; - + for (Word w : this.words) { - + c += w.getSyllableCount (); - + } - + this.syllableCount = c; - + } return this.syllableCount; - + } - + public Word getLastWord () { - - return this.words.get (this.words.size () - 1); - + + return this.words.get (this.words.size () - 1); + } - + public int getWordCount () { - + int c = 0; - + if (this.wordCount == -1) { - + for (Word w : this.words) { - + if (w.isPunctuation ()) { - + continue; - + } - + c++; - + } - + this.wordCount = c; - + } - + return this.wordCount; - + } - + /** * Get the nth word in the list of words this sentence models, words are indexed from 0. * @@ -189,18 +189,18 @@ public int getWordCount () */ public Word getWord (int i) { - + if (i < 0 || i > this.words.size () - 1) { - + return null; - + } - + return this.words.get (i); - + } - + /** * Get the word at the specifed offset into the sentence text. This is the word at the nth character in the sentence, * characters start at 0. @@ -210,7 +210,7 @@ public Word getWord (int i) */ public Word getWordAt (int offset) { - + for (Word w : this.words) { @@ -219,74 +219,74 @@ public Word getWordAt (int offset) (w.getStart () <= offset) ) { - + return w; - + } - + } - + return null; - + } - + public List getChildren () { - + return this.words; - + } - + public List getWords () { - + return this.getChildren (); - + } - + public String getText () { - + return this.sentence; - + } - + public int getIndexOfFirstTextWord () { - + for (int i = 0; i < this.words.size (); i++) { - + if (!this.words.get (i).isPunctuation ()) { - + return i; - + } - + } - + return -1; - + } public int getIndexOfLastTextWord () { - + for (int i = this.words.size () - 1; i > -1; i--) { - + if (!this.words.get (i).isPunctuation ()) { - + return i; - + } - + } - + return -1; - + } /** @@ -303,20 +303,20 @@ public NavigableSet find (List findWords, if (constraints == null) { - + constraints = new DialogueConstraints (false, false, DialogueConstraints.ANYWHERE); - + } - - NavigableSet ret = new TreeSet (); + + NavigableSet ret = new TreeSet<> (); for (Integer ind : TextUtilities.find (this.words, findWords, true)) { - + Word fw = this.words.get (ind); if ((constraints.ignoreInDialogue) @@ -324,29 +324,29 @@ public NavigableSet find (List findWords, (fw.isInDialogue ()) ) { - + continue; - + } - + if ((constraints.onlyInDialogue) && (!fw.isInDialogue ()) ) { - + continue; } - + if ((constraints.where.equals (DialogueConstraints.START)) && (ind != this.getIndexOfFirstTextWord ()) ) { - + continue; - + } if ((constraints.where.equals (DialogueConstraints.END)) @@ -354,30 +354,30 @@ public NavigableSet find (List findWords, ((findWords.size () + ind - 1) != this.getIndexOfLastTextWord ()) ) { - + continue; - + } - + ret.add (ind); - + } return ret; /* if (true) { - + return ret; - + } - + int fc = findWords.size (); int wc = this.words.size (); int firstWord = -1; - + for (int i = 0; i < wc; i++) { @@ -394,7 +394,7 @@ public NavigableSet find (List findWords, if ((constraints.onlyInDialogue) && (!w.isInDialogue ())) { - + continue; } @@ -425,27 +425,27 @@ public NavigableSet find (List findWords, } else { - + if ((constraints.ignoreInDialogue) && (w2.isInDialogue ())) { - + wfc++; - + continue; - + } - + if ((constraints.onlyInDialogue) && (!w2.isInDialogue ())) { - + wfc++; - + continue; - - } - + + } + match = true; } @@ -528,7 +528,7 @@ public NavigableSet find (List findWords, return ret; */ } - + /** * Look for the text in the sentence. * @@ -539,15 +539,15 @@ public NavigableSet find (List findWords, public NavigableSet find (String find, DialogueConstraints constraints) { - + List findWords = new Sentence (find, new DialogueInd ()).getWords (); return this.find (findWords, constraints); - - } - + + } + /** * Return where the sentence is within the overall block of text, this is the * this.getParent ().getTextStartOffset () + this.getStart () @@ -556,39 +556,39 @@ public NavigableSet find (String find, */ public int getAllTextStartOffset () { - + if (this.parent == null) { - + return this.start; - + } - + return this.parent.getAllTextStartOffset () + this.start; - + } - + public int getAllTextEndOffset () { - + if (this.parent == null) { - + return this.getEnd (); - + } - + return this.parent.getAllTextStartOffset () + this.getEnd (); - + } public int getEnd () { - + return this.start + this.sentence.length () - 1; - + } - + /** * Return where the sentence is within the parent paragraph. * @@ -596,59 +596,59 @@ public int getEnd () */ public int getStart () { - + return this.start; - + } - + public Paragraph getParent () { - + return this.parent; - + } - + public Paragraph getParagraph () { - + return this.parent; - + } - + public Sentence getPrevious () { - + return this.previous; - + } - + public void setPrevious (Sentence s) { - + this.previous = s; - + } - + public Sentence getNext () { - + return this.next; - + } - + public void setNext (Sentence s) { - + this.next = s; - + } - + @Override public String toString () { - + Map data = new LinkedHashMap (); - + data.put ("type", "sentence"); data.put ("wordCount", @@ -665,11 +665,11 @@ public String toString () this.getSyllableCount ()); data.put ("threeSyllableWordCount", this.getThreeSyllableWordCount ()); - - return Environment.formatObjectToStringProperties (data); - - } - + + return Environment.formatObjectToStringProperties (data); + + } + /** * Get the text in this paragraph, marked up as html with the markup passed in. * It assumes that the markup is relative to the getAllTextStartOffset. @@ -679,22 +679,22 @@ public String toString () */ public String markupAsHTML (Markup m) { - + if (m == null) { - + return this.sentence; - + } - + Markup pm = new Markup (m, this.getAllTextStartOffset (), this.getAllTextEndOffset ()); - + pm.shiftBy (-1 * this.getAllTextStartOffset ()); - + return pm.markupAsHTML (this.sentence); - + } - -} \ No newline at end of file + +} diff --git a/src/com/quollwriter/text/SentenceIterator.java b/src/main/java/com/quollwriter/text/SentenceIterator.java similarity index 100% rename from src/com/quollwriter/text/SentenceIterator.java rename to src/main/java/com/quollwriter/text/SentenceIterator.java diff --git a/src/main/java/com/quollwriter/text/SentenceMatches.java b/src/main/java/com/quollwriter/text/SentenceMatches.java new file mode 100644 index 00000000..f20aed04 --- /dev/null +++ b/src/main/java/com/quollwriter/text/SentenceMatches.java @@ -0,0 +1,47 @@ +package com.quollwriter.text; + +import java.text.*; +import java.util.*; + +import com.quollwriter.*; + +public class SentenceMatches +{ + + private Set indices = null; + private Sentence sentence = null; + private String match = null; + + public SentenceMatches (String match, + Sentence sent, + Set indices) + { + + this.match = match; + this.sentence = sent; + this.indices = indices; + + } + + public Sentence getSentence () + { + + return this.sentence; + + } + + public String getMatch () + { + + return this.match; + + } + + public Set getIndices () + { + + return this.indices; + + } + +} diff --git a/src/com/quollwriter/text/TextBlock.java b/src/main/java/com/quollwriter/text/TextBlock.java similarity index 100% rename from src/com/quollwriter/text/TextBlock.java rename to src/main/java/com/quollwriter/text/TextBlock.java diff --git a/src/main/java/com/quollwriter/text/TextBlockIterator.java b/src/main/java/com/quollwriter/text/TextBlockIterator.java new file mode 100644 index 00000000..44d6af30 --- /dev/null +++ b/src/main/java/com/quollwriter/text/TextBlockIterator.java @@ -0,0 +1,402 @@ +package com.quollwriter.text; + +import java.util.*; + +public class TextBlockIterator implements Iterator +{ + + private TextBlock current = null; + private boolean firstDone = false; + + public TextBlockIterator (String t) + { + + if (t == null) + { + + return; + + } + + TextIterator ti = new TextIterator (t); + + this.current = ti.getFirstParagraph (); + + } + + public TextBlockIterator (TextIterator ti) + { + + if (ti == null) + { + + return; + + } + + this.current = ti.getFirstParagraph (); + + + } + + public TextBlockIterator (Sentence s) + { + + this.current = s; + + } + + public TextBlockIterator (Paragraph p) + { + + this.current = p; + + } + + public boolean hasNext () + { + + if (this.current == null) + { + + return false; + + } + + if (this.current instanceof Sentence) + { + + Sentence n = (Sentence) this.current.getNext (); + + if (n == null) + { + + n = (Sentence) this.current; + + return (Paragraph) n.getParagraph ().getNext () != null; + + } + + } + + return true; + + } + + public boolean hasPrevious () + { + + if (this.current == null) + { + + return false; + + } + + if (this.current instanceof Sentence) + { + + Sentence n = (Sentence) this.current.getPrevious (); + + if (n == null) + { + + n = (Sentence) this.current; + + return (Paragraph) n.getParagraph ().getPrevious () != null; + + } + + } + + return true; + + } + + public boolean hasNextSentence () + { + + if (this.current == null) + { + + return false; + + } + + if (this.current instanceof Sentence) + { + + Sentence n = (Sentence) this.current.getNext (); + + if (n == null) + { + + n = (Sentence) this.current; + + return (Paragraph) n.getParagraph ().getNext () != null; + + } + + } + + return true; + + } + + public boolean hasPreviousSentence () + { + + if (this.current == null) + { + + return false; + + } + + if (this.current instanceof Sentence) + { + + Sentence n = (Sentence) this.current.getPrevious (); + + if (n == null) + { + + n = (Sentence) this.current; + + return (Paragraph) n.getParagraph ().getPrevious () != null; + + } + + } + + return true; + + } + + public boolean hasNextParagraph () + { + + if (this.current == null) + { + + return false; + + } + + if (this.current instanceof Sentence) + { + + Sentence n = (Sentence) this.current; + + return (Paragraph) n.getParagraph ().getNext () != null; + + } + + if (this.current instanceof Paragraph) + { + + return ((Paragraph) this.current).getNext () != null; + + } + + return false; + + } + + public boolean hasPreviousParagraph () + { + + if (this.current == null) + { + + return false; + + } + + if (this.current instanceof Sentence) + { + + Sentence n = (Sentence) this.current; + + return (Paragraph) n.getParagraph ().getPrevious () != null; + + } + + if (this.current instanceof Paragraph) + { + + return ((Paragraph) this.current).getPrevious () != null; + + } + + return false; + + } + + public TextBlock current () + { + + return this.current; + + } + + public TextBlock next () + { + + if (!this.firstDone) + { + + this.firstDone = true; + + return this.current; + + } + + if (this.current instanceof Sentence) + { + + Sentence n = (Sentence) this.current.getNext (); + + if (n == null) + { + + n = (Sentence) this.current; + + this.current = (Paragraph) n.getParagraph ().getNext (); + + } else { + + this.current = n; + + } + + return this.current; + + } + + if (this.current instanceof Paragraph) + { + + this.current = ((Paragraph) this.current).getFirstSentence (); + + } + + return this.current; + + } + + public TextBlock previous () + { + + if (!this.firstDone) + { + + this.firstDone = true; + + return this.current; + + } + + if (this.current instanceof Sentence) + { + + Sentence n = ((Sentence) this.current).getPrevious (); + + if (n == null) + { + + n = (Sentence) this.current; + + this.current = n.getParagraph ().getPrevious (); + + } else { + + this.current = n; + + } + + } + + if (this.current instanceof Paragraph) + { + + this.current = ((Paragraph) this.current).getPrevious ().getLastSentence (); + + } + + return this.current; + + } + + public Sentence previousSentence () + { + + TextBlock prev = this.previous (); + + if (prev instanceof Paragraph) + { + + this.current = ((Paragraph) prev).getLastSentence (); + + } + + return (Sentence) this.current; + + } + + public Sentence nextSentence () + { + + TextBlock next = this.next (); + + if (next instanceof Paragraph) + { + + this.current = ((Paragraph) next).getFirstSentence (); + + } + + return (Sentence) this.current; + + } + + public Paragraph nextParagraph () + { + + TextBlock next = this.next (); + + if (next instanceof Sentence) + { + + this.current = ((Sentence) next).getParagraph ().getNext (); + + } + + return (Paragraph) this.current; + + } + + public Paragraph previousParagraph () + { + + TextBlock prev = this.previous (); + + if (prev instanceof Sentence) + { + + this.current = ((Sentence) prev).getParagraph ().getPrevious (); + + } + + return (Paragraph) this.current; + + } + + public void remove () + { + + throw new UnsupportedOperationException ("Not supported."); + + } + +} diff --git a/src/com/quollwriter/text/TextIterator.java b/src/main/java/com/quollwriter/text/TextIterator.java similarity index 80% rename from src/com/quollwriter/text/TextIterator.java rename to src/main/java/com/quollwriter/text/TextIterator.java index f5d1e25e..8847f5f9 100644 --- a/src/com/quollwriter/text/TextIterator.java +++ b/src/main/java/com/quollwriter/text/TextIterator.java @@ -5,88 +5,88 @@ public class TextIterator { - + private List paragraphs = new ArrayList (); - + public TextIterator (String t) { - + if (t == null) { - + return; - + } - + int l = t.length (); - + Paragraph last = null; - + int start = 0; - + for (int i = 0; i < l; i++) { - + if (t.charAt (i) == '\n') { - + String pt = t.substring (start, i); - + if (pt.length () == 0) { - + start = i + 1; - + continue; - + } - + Paragraph p = new Paragraph (t.substring (start, i), start); - + this.paragraphs.add (p); - + if (last != null) { - + p.setPrevious (last); last.setNext (p); - + } - - start = i + 1; - + + start = i + 1; + last = p; - - } - + + } + } String lt = t.substring (start, l); - + if (lt.length () > 0) { Paragraph p = new Paragraph (lt, start); - + if (last != null) { - + p.setPrevious (last); last.setNext (p); - + } - + this.paragraphs.add (p); } - + } - + /** * Look for the collection of words and return a set of all text indexes (indexes within the entire text) for the * matches. @@ -100,41 +100,41 @@ public NavigableSet findAllTextIndexes (String words, { NavigableSet matches = new TreeSet (); - + for (Paragraph p : this.paragraphs) { - + for (Sentence s : p.getSentences ()) { - + int st = s.getAllTextStartOffset (); // These indexes will be sentence local. NavigableSet found = s.find (words, constraints); - + if (found != null) { - + for (Integer i : found) { - + matches.add (s.getWord (i).getAllTextStartOffset ()); - + //matches.add (i + st); - + } - + } - + } - + } - + return matches; - + } - + /** * Look for the collection of words in each sentence. * @@ -145,53 +145,53 @@ public NavigableSet findAllTextIndexes (String words, public Map> findInSentences (String words, DialogueConstraints constraints) { - - Map> matches = new LinkedHashMap (); - + + Map> matches = new LinkedHashMap<> (); + for (Paragraph p : this.paragraphs) { - + matches.putAll (p.findInSentences (words, constraints)); - + } - + return matches; - + } - + public Sentence getSentenceAt (int i) { - + Paragraph p = this.getParagraphAt (i); - + if (p == null) { - + return null; - + } - + return p.getSentenceAt (i - p.getAllTextStartOffset ()); - + } public Word getWordAt (int i) { - + Sentence s = this.getSentenceAt (i); - + if (s == null) { - + return null; - + } - + return s.getWordAt (i - s.getAllTextStartOffset ()); - + } - + /** * For index i, find the paragraph that either contains the index or the previous paragraph closest * to the index. @@ -203,35 +203,35 @@ public Word getWordAt (int i) */ public Paragraph getPreviousClosestParagraphTo (int i) { - + Paragraph f = this.getParagraphAt (i); if (f != null) { - + return f; - + } - + int l = this.paragraphs.size () - 1; - + for (int j = l; j > -1; j--) { - + Paragraph p = this.paragraphs.get (j); - + if (p.getAllTextStartOffset () <= i) { - + f = p; break; - + } - + } - + return f; - + } /** @@ -245,22 +245,22 @@ public Paragraph getPreviousClosestParagraphTo (int i) */ public Sentence getPreviousClosestSentenceTo (int i) { - + return this.getSentenceAt (i); /* Paragraph p = this.getPreviousClosestParagraphTo (i); - + if (p != null) { - + return p.getPreviousClosestSentenceTo (i); - + } - + return null; */ } - + /** * For index i, find the paragraph that either contains the index or the following paragraph closest * to the index. @@ -272,36 +272,36 @@ public Sentence getPreviousClosestSentenceTo (int i) */ public Paragraph getNextClosestParagraphTo (int i) { - + Paragraph f = this.getParagraphAt (i); - + if (f != null) { - + return f; - + } - + for (Paragraph p : this.paragraphs) { - + if ((p.getAllTextStartOffset () >= i) && (i <= p.getAllTextEndOffset ()) ) { - + f = p; break; - + } - + } - + return f; - + } - + /** * Get the first sentence of the first paragraph. * @@ -309,20 +309,20 @@ public Paragraph getNextClosestParagraphTo (int i) */ public Sentence getFirstSentence () { - + Paragraph p = this.getFirstParagraph (); - + if (p == null) { - + return null; - + } - + return p.getFirstSentence (); - + } - + /** * For index i, find the sentence that either starts on that boundary or the following sentence closest * to the boundary. @@ -334,198 +334,205 @@ public Sentence getFirstSentence () */ public Sentence getNextClosestSentenceTo (int i) { - + return this.getSentenceAt (i); /* Paragraph p = this.getNextClosestParagraphTo (i); - + if (p != null) { - + return p.getNextClosestSentenceTo (i); - + } - + return null; - */ + */ } public Paragraph getParagraphAt (int i) { - + for (Paragraph p : this.paragraphs) { - + if ((p.getAllTextEndOffset () >= i) && (p.getAllTextStartOffset () <= i) ) { - + return p; - + } - + } - + return null; - + } - + public List getParagraphs () { - + return this.paragraphs; - + } - + public Paragraph getLastParagraph () { - + Paragraph p = null; - + for (Paragraph pp : this.paragraphs) { - + p = pp; - + } - + return p; - + } - + public Paragraph getFirstParagraph () { - + for (Paragraph p : this.paragraphs) { - + return p; - + } - + return null; - + } public int getThreeSyllableWordCount () { int c = 0; - + for (Paragraph p : this.paragraphs) { - + c += p.getThreeSyllableWordCount (); - + } - - return c; + + return c; } - + public int getSyllableCount () { - + int c = 0; - + for (Paragraph p : this.paragraphs) { - + c += p.getSyllableCount (); - + } - - return c; - + + return c; + } - + public int getWordCount () { - + int c = 0; - + for (Paragraph p : this.paragraphs) { - + c += p.getWordCount (); - + } - + return c; - + } public List getWords () { - + List words = new ArrayList (); - + for (Paragraph p : this.paragraphs) { - + words.addAll (p.getWords ()); - + } - - return words; - + + return words; + } - + public Map getWordFrequency () { - + Map ret = new HashMap (); - + for (Word w : this.getWords ()) { - + String word = w.getText ().toLowerCase (); Integer wc = ret.get (word); - + int c = 0; - + if (wc != null) { - + c = wc.intValue (); - + } - + c++; ret.put (word, c); - + } - + return ret; - + } - + + public int getParagraphCount () + { + + return this.paragraphs.size (); + + } + public int getSentenceCount () { int c = 0; - + for (Paragraph p : this.paragraphs) { - + c += p.getSentenceCount (); - + } - + return c; - + } - + public String toString () { - + return "" + this.paragraphs.size (); - + } - -} \ No newline at end of file + +} diff --git a/src/main/java/com/quollwriter/text/TextSnippet.java b/src/main/java/com/quollwriter/text/TextSnippet.java new file mode 100644 index 00000000..929fd1b3 --- /dev/null +++ b/src/main/java/com/quollwriter/text/TextSnippet.java @@ -0,0 +1,101 @@ +package com.quollwriter.text; + +import java.text.*; +import java.util.*; + +import com.quollwriter.*; +import com.quollwriter.ui.components.*; + +public class TextSnippet implements TextBlock +{ + + private int start = -1; + private Sentence parent = null; + private String snippet = null; + private List words = new ArrayList<> (); + + public TextSnippet (String snippet, + Sentence parent, + int start) + { + + this.snippet = snippet; + this.parent = parent; + this.start = start; + this.words = TextUtilities.getAsWords (this.snippet); + + } + + @Override + public int getAllTextStartOffset () + { + + return this.parent.getAllTextStartOffset () + this.start; + + } + + @Override + public int getAllTextEndOffset () + { + + return this.getAllTextStartOffset () + this.snippet.length (); + + } + + @Override + public int getEnd () + { + + return this.start + this.snippet.length (); + + } + + @Override + public int getStart () + { + + return this.start; + + } + + @Override + public String getText () + { + + return this.snippet; + + } + + @Override + public Sentence getParent () + { + + return this.parent; + + } + + @Override + public TextSnippet getPrevious () + { + + return null; + + } + + @Override + public TextSnippet getNext () + { + + return null; + + } + + @Override + public List getChildren () + { + + return this.words; + + } + +} diff --git a/src/com/quollwriter/text/TextUtilities.java b/src/main/java/com/quollwriter/text/TextUtilities.java similarity index 88% rename from src/com/quollwriter/text/TextUtilities.java rename to src/main/java/com/quollwriter/text/TextUtilities.java index 28c168b9..cccbf0a9 100644 --- a/src/com/quollwriter/text/TextUtilities.java +++ b/src/main/java/com/quollwriter/text/TextUtilities.java @@ -8,10 +8,7 @@ import javax.swing.text.*; -import com.gentlyweb.utils.*; - import com.quollwriter.*; -import com.quollwriter.ui.components.Markup; public class TextUtilities { @@ -24,12 +21,12 @@ public class TextUtilities public static String DEFAULT_ELLIPSIS = "..."; private static Map wordSyllableCounts = null; - private static Map contractionEnds = new HashMap (); - private static Map> openCloseQs = new HashMap (); + private static Map contractionEnds = new HashMap<> (); + private static Map> openCloseQs = new HashMap<> (); static { - Map m = TextUtilities.contractionEnds; + Map m = TextUtilities.contractionEnds; m.put ("m", ""); @@ -42,7 +39,7 @@ public class TextUtilities m.put ("ll", ""); - m = TextUtilities.openCloseQs; + // TODO REmove m = TextUtilities.openCloseQs; // Taken from: http://en.wikipedia.org/wiki/International_variation_in_quotation_marks // The assumption here is (perhaps erroneously) that any text will be language consistent @@ -132,7 +129,7 @@ private static void addToOpenQCloseQ (char openQ, char... closeQs) { - Set s = new HashSet (); + Set s = new HashSet<> (); for (int i = 0; i < closeQs.length; i++) { @@ -259,7 +256,7 @@ public static List getParagraphMarkup (Paragraph para, { // Get the markup from the start of the paragraph (all text) to the end of the text. - List items = new ArrayList (); + List items = new ArrayList<> (); //int end = -1; @@ -324,7 +321,7 @@ public static boolean isWord (String w) public static List stripPunctuation (List words) { - List ret = new ArrayList (); + List ret = new ArrayList<> (); for (String w : words) { @@ -497,14 +494,14 @@ public static int getSyllableCountForWord (String word) { // Init the word counts. - TextUtilities.wordSyllableCounts = new HashMap (); + TextUtilities.wordSyllableCounts = new HashMap<> (); String c = null; try { - c = Environment.getResourceFileAsString (Constants.WORD_SYLLABLE_COUNTS_FILE); + c = Utils.getResourceFileAsString (Constants.WORD_SYLLABLE_COUNTS_FILE); } catch (Exception e) { @@ -723,24 +720,24 @@ public static String sanitizeText (String t) } - t = StringUtils.replaceString (t, + t = Utils.replaceString (t, String.valueOf ('\r'), ""); - t = StringUtils.replaceString (t, + t = Utils.replaceString (t, String.valueOf ('\u201c'), DEFAULT_OPEN_Q); - t = StringUtils.replaceString (t, + t = Utils.replaceString (t, String.valueOf ('\u201d'), DEFAULT_CLOSE_Q); - t = StringUtils.replaceString (t, + t = Utils.replaceString (t, String.valueOf ('\u2019'), DEFAULT_APOS); - t = StringUtils.replaceString (t, + t = Utils.replaceString (t, String.valueOf ('\u2018'), DEFAULT_APOS); // Ellipsis - t = StringUtils.replaceString (t, + t = Utils.replaceString (t, String.valueOf ('\u2026'), DEFAULT_ELLIPSIS); @@ -753,7 +750,7 @@ public static NavigableSet find (List words, boolean ignoreCase) { - NavigableSet ret = new TreeSet (); + NavigableSet ret = new TreeSet<> (); if ((findWords == null) || @@ -765,7 +762,7 @@ public static NavigableSet find (List words, } - List _words = new ArrayList (); + List _words = new ArrayList<> (); for (Word w : words) { @@ -774,7 +771,7 @@ public static NavigableSet find (List words, } - List _findWords = new ArrayList (); + List _findWords = new ArrayList<> (); for (Word w : findWords) { @@ -836,7 +833,7 @@ public static List getTextSnippetsForNames (Collection names, if (text != null) { - text = StringUtils.replaceString (text, + text = Utils.replaceString (text, String.valueOf ('\r'), ""); @@ -892,7 +889,7 @@ public static List getTextSnippetsForNames (Collection names, q.parse ("SELECT * FROM javax.swing.text.Segment ORDER BY beginIndex"); QueryResults qr = q.execute (snippets); - snippets = new ArrayList (qr.getResults ()); + snippets = new ArrayList<> (qr.getResults ()); } catch (Exception e) { @@ -905,4 +902,71 @@ public static List getTextSnippetsForNames (Collection names, } + public static List getSentenceMatches (Collection names, + String text) + { + + List snippets = new ArrayList<> (); + + if (text != null) + { + + text = Utils.replaceString (text, + String.valueOf ('\r'), + ""); + + } + + TextIterator ti = new TextIterator (text); + + for (String n : names) + { + + Map> matches = ti.findInSentences (n, + null); + + if (matches != null) + { + + Iterator iter = matches.keySet ().iterator (); + + while (iter.hasNext ()) + { + + Sentence sen = iter.next (); + + Set inds = matches.get (sen); + + if ((inds != null) + && + (inds.size () > 0) + ) + { + + SentenceMatches s = new SentenceMatches (n, + sen, + inds); + + snippets.add (s); + + } + + } + + } + + } +/* + Collections.sort (snippets, + (o1, o2) -> + { + + return Integer.valueOf (o1.getAllTextStartOffset ()).compareTo (o2.getAllTextStartOffset ()); + + }); +*/ + return snippets; + + } + } diff --git a/src/com/quollwriter/text/Word.java b/src/main/java/com/quollwriter/text/Word.java similarity index 80% rename from src/com/quollwriter/text/Word.java rename to src/main/java/com/quollwriter/text/Word.java index 36fd67ad..734e3c49 100644 --- a/src/com/quollwriter/text/Word.java +++ b/src/main/java/com/quollwriter/text/Word.java @@ -4,7 +4,7 @@ public class Word implements TextBlock { - + private Sentence parent = null; private int start = -1; private String word = null; @@ -13,81 +13,81 @@ public class Word implements TextBlock private boolean inDialogue = false; private int syllableCount = -1; private boolean isPunctuation = false; - + public Word (Sentence parent, String word, int start, boolean inDialogue) { - + this.parent = parent; this.word = word; this.start = start; this.inDialogue = inDialogue; - + if (word.length () == 1) { - + this.isPunctuation = !Character.isLetterOrDigit (word.charAt (0)); if (this.isPunctuation) { - + this.syllableCount = 0; - + } - + } - + } public boolean isPunctuation () { - + return this.isPunctuation; - + } - + public int getSyllableCount () { if (this.syllableCount == -1) { - + this.syllableCount = TextUtilities.getSyllableCountForWord (this.word); - + } - + return this.syllableCount; - + } - + public Word getWordsAhead (int count) { - + Word w = this; - + for (int i = 0; i < count; i++) { - + w = w.getNext (); - + if (w == null) { - + return null; - + } - + } - + return w; - + } - + public boolean isDialogueStart () { - + if ((TextUtilities.isOpenQ (this)) && ((this.previous == null) @@ -96,18 +96,18 @@ public boolean isDialogueStart () ) ) { - + return true; - + } - + return false; - + } - + public boolean isDialogueEnd () { - + if ((TextUtilities.isCloseQ (this)) && ((this.next == null) @@ -116,153 +116,173 @@ public boolean isDialogueEnd () ) ) { - + return true; - + } - + return false; - + } public boolean isInDialogue () { - + return this.inDialogue; - + } - + public int getAllTextStartOffset () { - + if (this.parent == null) { - + return this.start; - + } - + return this.parent.getAllTextStartOffset () + this.start; - + } - + public int getAllTextEndOffset () { - + if (this.parent == null) { - + return this.getEnd (); - + } return this.parent.getAllTextStartOffset () + this.getEnd (); - + } - + public List getChildren () { - + return null; - + } - + public String getText () { - + return this.word; - + } - + public int getEnd () { - + return this.start + this.word.length (); - + } - + public int getStart () { - + return this.start; - + } - + public Sentence getParent () { - + return this.parent; - + } - + public Sentence getSentence () { - + return this.getParent (); - + } - + public Word getNext () { - + return this.next; - + } - + public boolean textEquals (String w) { - + if (w == null) { - + return false; - + } - + return this.word.equalsIgnoreCase (w); - + } - + public boolean textEquals (Word w) { - + if (w == null) { - + return false; - + } - + return this.word.equalsIgnoreCase (w.getText ()); - + } public void setNext (Word w) { - + this.next = w; - + } - + public Word getPrevious () { - + return this.previous; - + } - + public void setPrevious (Word w) { - + this.previous = w; - + } - + public String toString () { - + return "[" + this.start + ", " + this.word + ", indialogue: " + this.inDialogue + "]"; - + } - -} \ No newline at end of file + + public boolean equals (Object o) + { + + if (!(o instanceof Word)) + { + + return false; + + } + + Word ow = (Word) o; + + return this.getAllTextStartOffset () == ow.getAllTextStartOffset () + && + this.getAllTextEndOffset () == ow.getAllTextEndOffset () + && + this.getText ().equals (ow.getText ()); + + } + +} diff --git a/src/com/quollwriter/text/WordsCapitalizer.java b/src/main/java/com/quollwriter/text/WordsCapitalizer.java similarity index 100% rename from src/com/quollwriter/text/WordsCapitalizer.java rename to src/main/java/com/quollwriter/text/WordsCapitalizer.java diff --git a/src/com/quollwriter/text/rules/AbstractDialogueRule.java b/src/main/java/com/quollwriter/text/rules/AbstractDialogueRule.java similarity index 84% rename from src/com/quollwriter/text/rules/AbstractDialogueRule.java rename to src/main/java/com/quollwriter/text/rules/AbstractDialogueRule.java index c29a1024..ab86e5c5 100644 --- a/src/com/quollwriter/text/rules/AbstractDialogueRule.java +++ b/src/main/java/com/quollwriter/text/rules/AbstractDialogueRule.java @@ -1,10 +1,9 @@ package com.quollwriter.text.rules; -import com.gentlyweb.xml.*; - import com.quollwriter.text.*; +import com.quollwriter.*; -import org.jdom.*; +import org.dom4j.*; public abstract class AbstractDialogueRule extends AbstractRule implements DialogueRule @@ -81,12 +80,12 @@ public boolean isIgnoreInDialogue () @Override public void init (Element root) - throws JDOMException + throws GeneralException { super.init (root); - this.where = JDOMUtils.getAttributeValue (root, + this.where = DOM4JUtils.attributeValue (root, XMLConstants.location, false); @@ -97,10 +96,10 @@ public void init (Element root) } - this.ignoreInDialogue = JDOMUtils.getAttributeValueAsBoolean (root, + this.ignoreInDialogue = DOM4JUtils.attributeValueAsBoolean (root, XMLConstants.ignoreInDialogue, false); - this.onlyInDialogue = JDOMUtils.getAttributeValueAsBoolean (root, + this.onlyInDialogue = DOM4JUtils.attributeValueAsBoolean (root, XMLConstants.onlyInDialogue, false); @@ -115,7 +114,7 @@ public Element getAsElement () if (this.ignoreInDialogue) { - root.setAttribute (XMLConstants.ignoreInDialogue, + root.addAttribute (XMLConstants.ignoreInDialogue, Boolean.toString (this.ignoreInDialogue)); } @@ -123,7 +122,7 @@ public Element getAsElement () if (this.onlyInDialogue) { - root.setAttribute (XMLConstants.onlyInDialogue, + root.addAttribute (XMLConstants.onlyInDialogue, Boolean.toString (this.onlyInDialogue)); } @@ -131,7 +130,7 @@ public Element getAsElement () if (this.where != null) { - root.setAttribute (XMLConstants.location, + root.addAttribute (XMLConstants.location, this.where); } diff --git a/src/com/quollwriter/text/rules/AbstractParagraphRule.java b/src/main/java/com/quollwriter/text/rules/AbstractParagraphRule.java similarity index 100% rename from src/com/quollwriter/text/rules/AbstractParagraphRule.java rename to src/main/java/com/quollwriter/text/rules/AbstractParagraphRule.java diff --git a/src/main/java/com/quollwriter/text/rules/AbstractRule.java b/src/main/java/com/quollwriter/text/rules/AbstractRule.java new file mode 100644 index 00000000..9f3008b2 --- /dev/null +++ b/src/main/java/com/quollwriter/text/rules/AbstractRule.java @@ -0,0 +1,364 @@ +package com.quollwriter.text.rules; + +import java.util.*; + +import javafx.beans.property.*; + +import com.quollwriter.*; +import com.quollwriter.ui.*; +import com.quollwriter.ui.forms.*; +import com.quollwriter.text.*; + +import com.quollwriter.ui.fx.components.Form; + +// TODO import com.quollwriter.ui.fx.components.Form; + +import org.dom4j.*; +import org.dom4j.tree.*; + + +public abstract class AbstractRule implements Rule +{ + + public class XMLConstants + { + + public static final String root = "rule"; + public static final String description = "description"; + public static final String id = "id"; + public static final String user = "user"; + public static final String summary = "summary"; + public static final String createType = "createType"; + + } + + protected String summary = null; + protected String desc = null; + protected String id = null; + protected boolean userRule = false; + private String defaultSummary = null; + + public AbstractRule () + { + + } + + public abstract String getEditFormTitle (boolean add); + + public abstract Set getFormItems (); + + public Set getFormItems2 () + { + + return null; + + } + + public StringProperty getFormError2 () + { + + return null; + + } + + public abstract String getFormError (); + + public String getDefaultSummary () + { + + return this.defaultSummary; + + } + + @Override + public void setSummary (String s) + { + + this.summary = s; + + } + + @Override + public String getSummary () + { + + return this.summary; + + } + + @Override + public void setUserRule (boolean u) + { + + this.userRule = u; + + } + + @Override + public boolean isUserRule () + { + + return this.userRule; + + } + + public void setDescription (String d) + { + + this.desc = d; + + } + + public void setId (String id) + { + + this.id = id; + + } + + public String getId () + { + + return this.id; + + } + + public String getDescription () + { + + return this.desc; + + } + + public void init (Element root) + throws GeneralException + { + + this.id = DOM4JUtils.attributeValue (root, + XMLConstants.id); + + this.userRule = DOM4JUtils.attributeValueAsBoolean (root, + XMLConstants.user, + false); + + this.desc = DOM4JUtils.childElementContent (root, + XMLConstants.description, + false, + null); + + this.summary = DOM4JUtils.childElementContent (root, + XMLConstants.summary); + + if (!this.userRule) + { + + this.defaultSummary = this.summary; + + } + + } + + public Element getAsElement () + { + + Element root = new DefaultElement (XMLConstants.root); + + root.addAttribute (XMLConstants.id, + this.id); + root.addAttribute (XMLConstants.createType, + this.getClass ().getName ()); + + if (this.userRule) + { + + root.addAttribute (XMLConstants.user, + Boolean.toString (this.userRule)); + + } + + Element summ = new DefaultElement (XMLConstants.summary); + + root.add (summ); + + summ.add (new DefaultCDATA (this.summary)); + + if ((this.desc != null) + && + (this.desc.length () > 0) + ) + { + + Element desc = new DefaultElement (XMLConstants.description); + + root.add (desc); + + desc.add (new DefaultCDATA (this.desc)); + + } + + return root; + + } + + public com.quollwriter.ui.forms.Form getEditForm (final java.awt.event.ActionListener onSaveComplete, + final java.awt.event.ActionListener onCancel, + final AbstractProjectViewer viewer, + final boolean add) + { + + final AbstractRule _this = this; + + Set items = new LinkedHashSet<> (); + + final TextFormItem summary = new TextFormItem (Environment.getUIString (LanguageStrings.form, + LanguageStrings.labels, + LanguageStrings.summary), + //"Summary", + this.getSummary ()); + + items.add (summary); + + items.addAll (this.getFormItems ()); + + final MultiLineTextFormItem desc = new MultiLineTextFormItem (Environment.getUIString (LanguageStrings.form, + LanguageStrings.labels, + LanguageStrings.description), + //"Description", + viewer, + 5); + desc.setText (this.getDescription ()); + desc.setCanFormat (false); + + items.add (desc); + + Map buttons = new LinkedHashMap<> (); + + buttons.put (com.quollwriter.ui.forms.Form.Button.save, + new java.awt.event.ActionListener () + { + + @Override + public void actionPerformed (java.awt.event.ActionEvent ev) + { + + com.quollwriter.ui.forms.Form f = (com.quollwriter.ui.forms.Form) ev.getSource (); + + String error = _this.getFormError (); + + if (error != null) + { + + f.showError (error); + + return; + + } + + _this.setDescription (desc.getText ().trim ()); + + String summ = summary.getText (); + + if (summ == null) + { + + summ = ""; + + } else { + + summ = summ.trim (); + + } + + if (summ.length () == 0) + { + + summ = _this.getSummary (); + + } + + if (summ == null) + { + + summ = _this.getDefaultSummary (); + + } + + if (summ == null) + { + + f.showError (Environment.getUIString (LanguageStrings.problemfinder, + LanguageStrings.config, + LanguageStrings.entersummaryerror)); + + return; + + } + + _this.setSummary (summ); + + if (onSaveComplete != null) + { + + onSaveComplete.actionPerformed (new java.awt.event.ActionEvent (_this, 1, "saved")); + + } + + } + + }); + + buttons.put (com.quollwriter.ui.forms.Form.Button.cancel, + new java.awt.event.ActionListener () + { + + @Override + public void actionPerformed (java.awt.event.ActionEvent ev) + { + + if (onCancel != null) + { + + onCancel.actionPerformed (new java.awt.event.ActionEvent (_this, 1, "cancelled")); + + } + + return; + + } + + }); + + com.quollwriter.ui.forms.Form f = new com.quollwriter.ui.forms.Form (com.quollwriter.ui.forms.Form.Layout.stacked, + items, + buttons); + + return f; + + } + + @Override + public int hashCode () + { + + return this.id.hashCode (); + + } + + @Override + public boolean equals (Object o) + { + + if ((o == null) || (!(o instanceof AbstractRule))) + { + + return false; + + } + + AbstractRule r = (AbstractRule) o; + + return this.id.equals (r.id); + + } + +} diff --git a/src/com/quollwriter/text/rules/AbstractSentenceRule.java b/src/main/java/com/quollwriter/text/rules/AbstractSentenceRule.java similarity index 100% rename from src/com/quollwriter/text/rules/AbstractSentenceRule.java rename to src/main/java/com/quollwriter/text/rules/AbstractSentenceRule.java diff --git a/src/main/java/com/quollwriter/text/rules/AdverbRule.java b/src/main/java/com/quollwriter/text/rules/AdverbRule.java new file mode 100644 index 00000000..3b3770d5 --- /dev/null +++ b/src/main/java/com/quollwriter/text/rules/AdverbRule.java @@ -0,0 +1,581 @@ +package com.quollwriter.text.rules; + +import java.awt.Component; +import java.awt.event.*; + +import java.util.*; + +import javax.swing.*; +import javax.swing.border.*; + +import javafx.collections.*; +import javafx.scene.layout.*; +import javafx.scene.control.*; +import javafx.scene.control.cell.*; +import javafx.util.converter.*; + +import com.quollwriter.*; + +import com.quollwriter.synonyms.*; + +import com.quollwriter.text.*; +import com.quollwriter.ui.*; +import com.quollwriter.ui.forms.*; + +import com.quollwriter.ui.fx.*; +import com.quollwriter.ui.fx.components.Form; +import com.quollwriter.ui.fx.components.*; + +import org.dom4j.*; + +import static com.quollwriter.LanguageStrings.*; +import static com.quollwriter.uistrings.UILanguageStringsManager.getUILanguageStringProperty; + +public class AdverbRule extends AbstractSentenceRule +{ + + public class XMLConstants + { + + public static final String speechVerbs = "speechVerbs"; + + } + + private Set speechVerbs = new HashSet<> (); + private JTextField newVerbs = null; + private DefaultListModel listModel = null; + + private TextField newVerbs2 = null; + private ListView verbs2 = null; + + public AdverbRule () + { + + } + + @Override + public String getCategory () + { + + return Rule.SENTENCE_CATEGORY; + + } + + @Override + public void init (Element root) + throws GeneralException + { + + super.init (root); + + String sw = DOM4JUtils.attributeValue (root, + XMLConstants.speechVerbs); + + StringTokenizer t = new StringTokenizer (sw, + ","); + + while (t.hasMoreTokens ()) + { + + this.speechVerbs.add (t.nextToken ().trim ().toLowerCase ()); + + } + + } + + public void setSpeechVerbs (Set verbs) + { + + this.speechVerbs = verbs; + + } + + public boolean isSpeechVerb (String w) + { + + if (w == null) + { + + return false; + + } + + return this.speechVerbs.contains (w.toLowerCase ()); + + } + + @Override + public Element getAsElement () + { + + Element root = super.getAsElement (); + + StringBuilder b = new StringBuilder (); + + for (String w : this.speechVerbs) + { + + if (b.length () > 0) + { + + b.append (","); + + } + + b.append (w); + + } + + root.addAttribute (XMLConstants.speechVerbs, + b.toString ()); + + return root; + + } + + @Override + public List getIssues (Sentence sentence) + { + + List issues = new ArrayList<> (); + + String adverbWT = String.valueOf (Synonyms.ADVERB); + + List swords = sentence.getWords (); + + for (Word w : swords) + { + + if (w.isInDialogue ()) + { + + continue; + + } + + if (this.isSpeechVerb (w.getText ())) + { + + Word nw = w.getNext (); + + if (nw != null) + { + + try + { + + SynonymProvider sp = Environment.getSynonymProvider (Constants.ENGLISH); + + String wt = null; + + if (sp != null) + { + + wt = sp.getWordTypes (nw.getText ()); + + } + + if (wt != null) + { + + // We are only interested in those that are purely adverbs (no other word types) + if (wt.equals (adverbWT)) + { + + // Maybe check to see if it's after a " + + // Add an issue. + Issue iss = new Issue (String.format (Environment.getUIString (LanguageStrings.problemfinder, + LanguageStrings.issues, + LanguageStrings.adverb, + LanguageStrings.text), + nw.getText (), + w.getText ()), + //"Use of adverb: " + nw.getText () + + //" to modify speech verb: " + w.getText () + "", + sentence, + sentence.getAllTextStartOffset () + "-" + nw.getText () + "-" + w.getText (), + this); + issues.add (iss); + + } + + } + + + } catch (Exception e) + { + + Environment.logError ("Unable to check for word: " + + nw + + " being an adverb.", + e); + + } + + } + + } + + + } + + return issues; + + } + + @Override + public Set getFormItems2 () + { + + final AdverbRule _this = this; + + List pref = Arrays.asList (problemfinder,config,rules,adverb,labels); + + Set items = new LinkedHashSet<> (); + + VBox b = new VBox (); + + this.newVerbs2 = QuollTextField.builder () + .build (); + + b.getChildren ().add (this.newVerbs2); + + QuollLabel l = QuollLabel.builder () + .label (getUILanguageStringProperty (Utils.newList (pref,separate))) + .styleClassName (StyleClassNames.INFORMATION) + .build (); + + b.getChildren ().add (l); + + items.add (new Form.Item (getUILanguageStringProperty (Utils.newList (pref,newspeechverbs)), + b)); + + Vector v = new Vector<> (this.speechVerbs); + + Collections.sort (v); + + List _vitems = new ArrayList<> (v); + + ObservableList vitems = FXCollections.observableList (_vitems); + + this.verbs2 = new ListView<> (vitems); + this.verbs2.getStyleClass ().add (StyleClassNames.ITEMS); + this.verbs2.getSelectionModel ().setSelectionMode (SelectionMode.MULTIPLE); + this.verbs2.setEditable (true); + this.verbs2.setCellFactory (view -> + { + + TextFieldListCell c = new TextFieldListCell<> () + { + + @Override + public void cancelEdit () + { + + this.pseudoClassStateChanged (StyleClassNames.ERROR_PSEUDO_CLASS, false); + super.cancelEdit (); + + } + + @Override + public void commitEdit (String newVal) + { + + this.pseudoClassStateChanged (StyleClassNames.ERROR_PSEUDO_CLASS, false); + + int ind = -1; + + newVal = newVal.trim (); + + for (int i = 0; i < vitems.size (); i++) + { + + if (newVal.equalsIgnoreCase (vitems.get (i))) + { + + ind = i; + break; + + } + + } + + if ((ind > -1) + && + (ind != this.getIndex ()) + ) + { + + this.pseudoClassStateChanged (StyleClassNames.ERROR_PSEUDO_CLASS, true); + com.quollwriter.ui.fx.UIUtils.setTooltip (this, + getUILanguageStringProperty (manageitems,table,edit,errors,valueexists)); + + return; + + } + + String oldVal = this.getItem (); + + // TODO Check value here and either allow or prevent. + super.commitEdit (newVal); + + vitems.set (this.getIndex (), + newVal); + + _this.speechVerbs = new LinkedHashSet<> (vitems); + + } + + }; + + c.setConverter (new DefaultStringConverter ()); + + return c; + + }); + + HBox bb = new HBox (); + bb.getChildren ().add (this.verbs2); + + bb.getChildren ().add (QuollButton.builder () + .tooltip (getUILanguageStringProperty (problemfinder,config,rules,adverb,buttons,removespeechverbs,tooltip)) + .iconName (StyleClassNames.DELETE) + .onAction (ev -> + { + + vitems.removeAll (verbs2.getSelectionModel ().getSelectedItems ()); + + }) + .build ()); + + items.add (new Form.Item (getUILanguageStringProperty (Utils.newList (pref,speechverbs)), + //"Speech Verbs", + bb)); + + return items; + + } + + @Override + public Set getFormItems () + { + + final AdverbRule _this = this; + + List pref = new ArrayList<> (); + pref.add (LanguageStrings.problemfinder); + pref.add (LanguageStrings.config); + pref.add (LanguageStrings.rules); + pref.add (LanguageStrings.adverb); + pref.add (LanguageStrings.labels); + + Set items = new LinkedHashSet<> (); + + Box b = new Box (BoxLayout.Y_AXIS); + + this.newVerbs = com.quollwriter.ui.UIUtils.createTextField (); + + b.add (newVerbs); + + JLabel label = new JLabel (Environment.getUIString (pref, + LanguageStrings.separate)); + //"(separate with , or ;)"); + label.setBorder (com.quollwriter.ui.UIUtils.createPadding (0, 5, 0, 0)); + + b.add (label); + + items.add (new AnyFormItem (Environment.getUIString (pref, + LanguageStrings.newspeechverbs), + //"New Speech Verbs", + b)); + + Vector v = new Vector<> (this.speechVerbs); + + Collections.sort (v); + + this.listModel = new DefaultListModel (); + + for (int i = 0; i < v.size (); i++) + { + + this.listModel.addElement (v.get (i)); + + } + + b = new Box (BoxLayout.X_AXIS); + + final JList verbs = new JList<> (this.listModel); + + verbs.setVisibleRowCount (5); + verbs.setMaximumSize (verbs.getPreferredSize ()); + + b.add (new JScrollPane (verbs)); + + b.add (Box.createHorizontalStrut (5)); + + Box bb = new Box (BoxLayout.Y_AXIS); + + List buts = new ArrayList<> (); + + buts.add (com.quollwriter.ui.UIUtils.createButton (Constants.DELETE_ICON_NAME, + Constants.ICON_MENU, + Environment.getUIString (LanguageStrings.problemfinder, + LanguageStrings.config, + LanguageStrings.rules, + LanguageStrings.adverb, + LanguageStrings.buttons, + LanguageStrings.removespeechverbs, + LanguageStrings.tooltip), + //"Click to remove the selected Speech Verbs", + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + // Get the selected items, remove them from the model. + int[] inds = verbs.getSelectedIndices (); + + if (inds != null) + { + + for (int i = inds.length - 1; i > -1; i--) + { + + _this.listModel.remove (inds[i]); + + } + + } + + } + + })); + +/* + + ImagePanel del = new ImagePanel (Environment.getIcon ("delete", + Constants.ICON_MENU), + null); + del.setBorder (null); + del.setOpaque (false); + del.setToolTipText ("Click to remove the selected Speech Verbs"); + com.quollwriter.ui.UIUtils.setAsButton (del); + del.setAlignmentY (Component.TOP_ALIGNMENT); + + del.addMouseListener (new MouseAdapter () + { + + public void mouseReleased (MouseEvent ev) + { + + // Get the selected items, remove them from the model. + int[] inds = verbs.getSelectedIndices (); + + if (inds != null) + { + + for (int i = inds.length - 1; i > -1; i--) + { + + _this.listModel.remove (inds[i]); + + } + + } + + } + + }); +*/ + bb.add (com.quollwriter.ui.UIUtils.createButtonBar (buts)); + bb.add (Box.createVerticalGlue ()); + + b.add (bb); + b.add (Box.createHorizontalGlue ()); + + items.add (new AnyFormItem (Environment.getUIString (pref, + LanguageStrings.speechverbs), + //"Speech Verbs", + b)); + + return items; + + } + + @Override + public String getFormError () + { + + return null; + + } + + @Override + public void updateFromForm2 () + { + + Set verbs = new HashSet<> (); + + String n = this.newVerbs2.getText (); + + if (n != null) + { + + StringTokenizer t = new StringTokenizer (n, + ";,"); + + while (t.hasMoreTokens ()) + { + + verbs.add (t.nextToken ().trim ().toLowerCase ()); + + } + + } + + verbs.addAll (this.verbs2.getItems ()); + + this.speechVerbs = verbs; + + } + + public void updateFromForm () + { + + // Reset the speech verbs. + Set verbs = new HashSet<> (); + + String n = this.newVerbs.getText (); + + if (n != null) + { + + StringTokenizer t = new StringTokenizer (n, + ";,"); + + while (t.hasMoreTokens ()) + { + + verbs.add (t.nextToken ().trim ().toLowerCase ()); + + } + + } + + Enumeration en = this.listModel.elements (); + + while (en.hasMoreElements ()) + { + + verbs.add ((String) en.nextElement ()); + + } + + this.speechVerbs = verbs; + + } + +} diff --git a/src/com/quollwriter/text/rules/DialogueRule.java b/src/main/java/com/quollwriter/text/rules/DialogueRule.java similarity index 100% rename from src/com/quollwriter/text/rules/DialogueRule.java rename to src/main/java/com/quollwriter/text/rules/DialogueRule.java diff --git a/src/com/quollwriter/text/rules/DoubleWordRule.java b/src/main/java/com/quollwriter/text/rules/DoubleWordRule.java similarity index 91% rename from src/com/quollwriter/text/rules/DoubleWordRule.java rename to src/main/java/com/quollwriter/text/rules/DoubleWordRule.java index 33dd99d2..468d7083 100644 --- a/src/com/quollwriter/text/rules/DoubleWordRule.java +++ b/src/main/java/com/quollwriter/text/rules/DoubleWordRule.java @@ -2,22 +2,14 @@ import java.util.*; -import javax.swing.*; -import javax.swing.event.*; -import javax.swing.text.*; - -import com.gentlyweb.utils.*; - -import com.gentlyweb.xml.*; +import org.dom4j.*; import com.quollwriter.*; import com.quollwriter.text.*; import com.quollwriter.ui.forms.*; -import org.jdom.Element; -import org.jdom.JDOMException; - +import com.quollwriter.ui.fx.components.Form; public class DoubleWordRule extends AbstractSentenceRule { @@ -38,7 +30,7 @@ public String getDescription () @Override public void init (Element root) - throws JDOMException + throws GeneralException { super.init (root); @@ -98,7 +90,7 @@ private boolean hasThree (Word w, public List getIssues (Sentence sentence) { - List issues = new ArrayList (); + List issues = new ArrayList<> (); if (sentence == null) { @@ -160,11 +152,11 @@ public List getIssues (Sentence sentence) if (curr.textEquals (prev)) { - List pref = new ArrayList (); + List pref = new ArrayList<> (); pref.add (LanguageStrings.problemfinder); pref.add (LanguageStrings.issues); pref.add (LanguageStrings.doubleword); - + Issue iss = null; if (curr.isPunctuation ()) @@ -231,7 +223,17 @@ public String getCategory () public Set getFormItems () { - Set items = new LinkedHashSet (); + Set items = new LinkedHashSet<> (); + + return items; + + } + + @Override + public Set getFormItems2 () + { + + Set items = new LinkedHashSet<> (); return items; @@ -251,4 +253,10 @@ public void updateFromForm () } + @Override + public void updateFromForm2 () + { + + } + } diff --git a/src/main/java/com/quollwriter/text/rules/ParagraphLengthRule.java b/src/main/java/com/quollwriter/text/rules/ParagraphLengthRule.java new file mode 100644 index 00000000..47a8c37e --- /dev/null +++ b/src/main/java/com/quollwriter/text/rules/ParagraphLengthRule.java @@ -0,0 +1,309 @@ +package com.quollwriter.text.rules; + +import java.util.*; + +import javafx.scene.control.*; +import javafx.scene.control.SpinnerValueFactory.*; + +import com.quollwriter.*; +import com.quollwriter.text.*; + +import com.quollwriter.ui.forms.*; +import com.quollwriter.ui.fx.components.Form; +import com.quollwriter.ui.fx.components.*; + +import org.dom4j.*; + +import static com.quollwriter.LanguageStrings.*; +import static com.quollwriter.uistrings.UILanguageStringsManager.getUILanguageStringProperty; + +public class ParagraphLengthRule extends AbstractParagraphRule +{ + + public class XMLConstants + { + + public static final String wordCount = "wordCount"; + public static final String sentenceCount = "sentenceCount"; + + } + + private int sentenceCount = 0; + private int wordCount = 0; + private javax.swing.JSpinner sentCountF = null; + private javax.swing.JSpinner wordCountF = null; + + private Spinner sentCountF2 = null; + private Spinner wordCountF2 = null; + + public ParagraphLengthRule () + { + + } + + public ParagraphLengthRule (int sentenceCount, + int wordCount, + boolean user) + { + + this.sentenceCount = sentenceCount; + this.wordCount = wordCount; + this.setUserRule (user); + + } + + public int getSentenceCount () + { + + return this.sentenceCount; + + } + + public void setSentenceCount (int c) + { + + this.sentenceCount = c; + + } + + public int getWordCount () + { + + return this.wordCount; + + } + + public void setWordCount (int c) + { + + this.wordCount = c; + + } + + @Override + public String getDescription () + { + + String d = super.getDescription (); + + d = Utils.replaceString (d, + "[SENTENCE_COUNT]", + this.sentenceCount + ""); + + d = Utils.replaceString (d, + "[WORD_COUNT]", + this.wordCount + ""); + + return d; + + } + + @Override + public String getSummary () + { + + String t = Utils.replaceString (super.getSummary (), + "[SENTENCE_COUNT]", + this.sentenceCount + ""); + + t = Utils.replaceString (t, + "[WORD_COUNT]", + this.wordCount + ""); + + return t; + + } + + @Override + public void init (Element root) + throws GeneralException + { + + super.init (root); + + this.sentenceCount = DOM4JUtils.attributeValueAsInt (root, + XMLConstants.sentenceCount); + this.wordCount = DOM4JUtils.attributeValueAsInt (root, + XMLConstants.wordCount); + + } + + @Override + public Element getAsElement () + { + + Element root = super.getAsElement (); + + root.addAttribute (XMLConstants.sentenceCount, + this.sentenceCount + ""); + root.addAttribute (XMLConstants.wordCount, + this.wordCount + ""); + + return root; + + } + + @Override + public List getIssues (Paragraph paragraph) + { + + List pref = new ArrayList<> (); + pref.add (LanguageStrings.problemfinder); + pref.add (LanguageStrings.issues); + pref.add (LanguageStrings.paragraphlength); + + List issues = new ArrayList<> (); + + int wc = paragraph.getWordCount (); + + if ((this.wordCount > 0) + && + (wc > this.wordCount) + ) + { + + Issue iss = new Issue (String.format (Environment.getUIString (pref, + LanguageStrings.wordtext), + Environment.formatNumber (wc), + Environment.formatNumber (this.wordCount)), + //"Paragraph word count is: " + Environment.formatNumber (wc) + ". (Max is: " + Environment.formatNumber (this.wordCount) + ")", + paragraph, + paragraph.getAllTextStartOffset () + "-wordcount-" + wc, + this); + + issues.add (iss); + + } + + int sc = paragraph.getSentenceCount (); + + if ((this.sentenceCount > 0) + && + (sc > this.sentenceCount) + ) + { + + Issue iss = new Issue (String.format (Environment.getUIString (pref, + LanguageStrings.sentencetext), + Environment.formatNumber (sc), + Environment.formatNumber (this.sentenceCount)), + //"Paragraph sentence count is: " + Environment.formatNumber (sc) + ". (Max is: " + Environment.formatNumber (this.sentenceCount) + ")", + paragraph, + paragraph.getAllTextStartOffset () + "-sentencecount-" + sc, + this); + + issues.add (iss); + + } + + return issues; + + } + + @Override + public String getCategory () + { + + return Rule.PARAGRAPH_CATEGORY; + + } + + @Override + public String getFormError () + { + + return null; + + } + + @Override + public Set getFormItems () + { + + List pref = new ArrayList<> (); + pref.add (LanguageStrings.problemfinder); + pref.add (LanguageStrings.config); + pref.add (LanguageStrings.rules); + pref.add (LanguageStrings.paragraphlength); + pref.add (LanguageStrings.labels); + + Set items = new LinkedHashSet (); + + this.wordCountF = new javax.swing.JSpinner (new javax.swing.SpinnerNumberModel (this.wordCount, + 1, + 500, + 1)); + + javax.swing.Box b = new javax.swing.Box (javax.swing.BoxLayout.X_AXIS); + b.add (this.wordCountF); + b.add (javax.swing.Box.createHorizontalGlue ()); + + this.wordCountF.setMaximumSize (this.wordCountF.getPreferredSize ()); + + items.add (new com.quollwriter.ui.forms.AnyFormItem (Environment.getUIString (pref, + LanguageStrings.words), + //"Words", + b)); + + this.sentCountF = new javax.swing.JSpinner (new javax.swing.SpinnerNumberModel (this.sentenceCount, + 1, + 500, + 1)); + + b = new javax.swing.Box (javax.swing.BoxLayout.X_AXIS); + + b.add (this.sentCountF); + b.add (javax.swing.Box.createHorizontalGlue ()); + + this.sentCountF.setMaximumSize (this.sentCountF.getPreferredSize ()); + + items.add (new com.quollwriter.ui.forms.AnyFormItem (Environment.getUIString (pref, + LanguageStrings.sentences), + //"Sentences", + b)); + + return items; + + } + + @Override + public Set getFormItems2 () + { + + List pref = Arrays.asList (problemfinder,config,rules,paragraphlength,labels); + + Set items = new LinkedHashSet<> (); + + this.wordCountF2 = new Spinner<> (new IntegerSpinnerValueFactory (1, 500, this.wordCount, 1)); + + items.add (new Form.Item (getUILanguageStringProperty (Utils.newList (pref,words)), + this.wordCountF2)); + + this.sentCountF2 = new Spinner<> (new IntegerSpinnerValueFactory (1, 500, this.sentenceCount, 1)); + + items.add (new Form.Item (getUILanguageStringProperty (Utils.newList (pref,sentences)), + this.sentCountF2)); + + return items; + + } + + @Override + public void updateFromForm2 () + { + + this.sentenceCount = this.sentCountF2.getValue (); + this.wordCount = this.wordCountF2.getValue (); + + } + + @Override + public void updateFromForm () + { + + this.sentenceCount = ((javax.swing.SpinnerNumberModel) this.sentCountF.getModel ()).getNumber ().intValue (); + this.wordCount = ((javax.swing.SpinnerNumberModel) this.wordCountF.getModel ()).getNumber ().intValue (); + + } + +} diff --git a/src/main/java/com/quollwriter/text/rules/ParagraphReadabilityRule.java b/src/main/java/com/quollwriter/text/rules/ParagraphReadabilityRule.java new file mode 100644 index 00000000..b553d0d7 --- /dev/null +++ b/src/main/java/com/quollwriter/text/rules/ParagraphReadabilityRule.java @@ -0,0 +1,352 @@ +package com.quollwriter.text.rules; + +import java.util.*; + +import javafx.scene.control.*; +import javafx.scene.control.SpinnerValueFactory.*; + +import com.quollwriter.*; +import com.quollwriter.data.*; +import com.quollwriter.text.*; + +import com.quollwriter.ui.forms.*; +import com.quollwriter.ui.fx.components.Form; +import com.quollwriter.ui.fx.components.*; + +import org.dom4j.*; + +import static com.quollwriter.LanguageStrings.*; +import static com.quollwriter.uistrings.UILanguageStringsManager.getUILanguageStringProperty; + +public class ParagraphReadabilityRule extends AbstractParagraphRule +{ + + public class XMLConstants + { + + public static final String fleschKincaid = "fleschKincaid"; + public static final String fleschReading = "fleschReading"; + public static final String gunningFog = "gunningFog"; + + } + + private int fleschKincaid = 0; + private int fleschReading = 0; + private int gunningFog = 0; + private javax.swing.JSpinner gfF = null; + private javax.swing.JSpinner fkF = null; + private javax.swing.JSpinner frF = null; + + private Spinner gfF2 = null; + private Spinner fkF2 = null; + private Spinner frF2 = null; + + public ParagraphReadabilityRule () + { + + } + + public ParagraphReadabilityRule (int fleschKincaid, + int fleschReading, + int gunningFog, + boolean user) + { + + this.fleschKincaid = fleschKincaid; + this.fleschReading = fleschReading; + this.gunningFog = gunningFog; + this.setUserRule (user); + + } + + @Override + public String getDescription () + { + + String d = super.getDescription (); + + d = Utils.replaceString (d, + "[FLESCH_KINCAID]", + this.fleschKincaid + ""); + + d =Utils.replaceString (d, + "[FLESCH_READING]", + this.fleschReading + ""); + + d = Utils.replaceString (d, + "[GUNNING_FOG]", + this.gunningFog + ""); + + return d; + + } + + @Override + public String getSummary () + { + + String t = Utils.replaceString (super.getSummary (), + "[FLESCH_KINCAID]", + this.fleschKincaid + ""); + + t = Utils.replaceString (t, + "[FLESCH_READING]", + this.fleschReading + ""); + + t = Utils.replaceString (t, + "[GUNNING_FOG]", + this.gunningFog + ""); + + return t; + + } + + @Override + public void init (Element root) + throws GeneralException + { + + super.init (root); + + this.fleschKincaid = DOM4JUtils.attributeValueAsInt (root, + XMLConstants.fleschKincaid); + this.fleschReading = DOM4JUtils.attributeValueAsInt (root, + XMLConstants.fleschReading); + this.gunningFog = DOM4JUtils.attributeValueAsInt (root, + XMLConstants.gunningFog); + + } + + @Override + public Element getAsElement () + { + + Element root = super.getAsElement (); + + root.addAttribute (XMLConstants.fleschKincaid, + this.fleschKincaid + ""); + root.addAttribute (XMLConstants.fleschReading, + this.fleschReading + ""); + root.addAttribute (XMLConstants.gunningFog, + this.gunningFog + ""); + + return root; + + } + + @Override + public List getIssues (Paragraph paragraph) + { + + List issues = new ArrayList<> (); + + //int wc = TextUtilities.getWordCount (paragraph); + + if (paragraph.getWordCount () > 100) + { + + List pref = new ArrayList<> (); + pref.add (LanguageStrings.problemfinder); + pref.add (LanguageStrings.issues); + pref.add (LanguageStrings.paragraphreadability); + + ReadabilityIndices ri = new ReadabilityIndices (); + ri.add (paragraph.getText ()); + + if ((this.fleschKincaid > 0) + && + (ri.getFleschKincaidGradeLevel () > this.fleschKincaid) + ) + { + + Issue iss = new Issue (String.format (Environment.getUIString (pref, + LanguageStrings.fkfull), + Environment.formatNumber (ri.getFleschKincaidGradeLevel ()), + Environment.formatNumber (this.fleschKincaid)), + //"Paragraph has a Flesch Kincaid grade level of: " + Environment.formatNumber (ri.getFleschKincaidGradeLevel ()) + ". (Max is: " + Environment.formatNumber (this.fleschKincaid) + ")", + paragraph, + paragraph.getAllTextStartOffset () + "-fkgl-" + ri.getFleschKincaidGradeLevel (), + this); + + issues.add (iss); + + } + + if ((this.fleschReading > 0) + && + (ri.getFleschReadingEase () > this.fleschReading) + ) + { + + Issue iss = new Issue (String.format (Environment.getUIString (pref, + LanguageStrings.frfull), + Environment.formatNumber (ri.getFleschReadingEase ()), + Environment.formatNumber (this.fleschReading)), + //"Paragraph has a Flesch Reading ease level of: " + Environment.formatNumber (ri.getFleschReadingEase ()) + ". (Max is: " + Environment.formatNumber (this.fleschReading) + ")", + paragraph, + paragraph.getAllTextStartOffset () + "-fre-" + ri.getFleschReadingEase (), + this); + + issues.add (iss); + + } + + if ((this.gunningFog > 0) + && + (ri.getGunningFogIndex () > this.gunningFog) + ) + { + + Issue iss = new Issue (String.format (Environment.getUIString (pref, + LanguageStrings.gffull), + Environment.formatNumber (ri.getGunningFogIndex ()), + Environment.formatNumber (this.gunningFog)), + //"Paragraph has a Gunning Fog index of: " + Environment.formatNumber (ri.getGunningFogIndex ()) + ". (Max is: " + Environment.formatNumber (this.gunningFog) + ")", + paragraph, + paragraph.getAllTextStartOffset () + "-gfi-" + ri.getGunningFogIndex (), + this); + + issues.add (iss); + + } + + } + + return issues; + + } + + @Override + public String getCategory () + { + + return Rule.PARAGRAPH_CATEGORY; + + } + + @Override + public Set getFormItems2 () + { + + List pref = Arrays.asList (problemfinder,config,rules,paragraphreadability,labels); + + Set items = new LinkedHashSet<> (); + + this.fkF2 = new Spinner<> (new IntegerSpinnerValueFactory (0, 30, this.fleschKincaid, 1)); + + items.add (new Form.Item (getUILanguageStringProperty (Utils.newList (pref,fk)), + //"Flesch Kincaid Grade level", + this.fkF2)); + + this.frF2 = new Spinner<> (new IntegerSpinnerValueFactory (0, 30, this.fleschReading, 1)); + + items.add (new Form.Item (getUILanguageStringProperty (Utils.newList (pref,fr)), + //"Flesch Reading ease level", + this.frF2)); + + this.gfF2 = new Spinner<> (new IntegerSpinnerValueFactory (0, 30, this.gunningFog, 1)); + + items.add (new Form.Item (getUILanguageStringProperty (Utils.newList (pref,gf)), + //"Gunning Fog index", + this.gfF2)); + + return items; + + } + + @Override + public Set getFormItems () + { + + List pref = new ArrayList<> (); + pref.add (LanguageStrings.problemfinder); + pref.add (LanguageStrings.config); + pref.add (LanguageStrings.rules); + pref.add (LanguageStrings.paragraphreadability); + pref.add (LanguageStrings.labels); + + Set items = new LinkedHashSet (); + + this.fkF = new javax.swing.JSpinner (new javax.swing.SpinnerNumberModel (this.fleschKincaid, + 0, + 30, + 1)); + + javax.swing.Box b = new javax.swing.Box (javax.swing.BoxLayout.X_AXIS); + b.add (this.fkF); + b.add (javax.swing.Box.createHorizontalGlue ()); + + this.fkF.setMaximumSize (this.fkF.getPreferredSize ()); + + items.add (new com.quollwriter.ui.forms.AnyFormItem (Environment.getUIString (pref, + LanguageStrings.fk), + //"Flesch Kincaid Grade level", + b)); + + this.frF = new javax.swing.JSpinner (new javax.swing.SpinnerNumberModel (this.fleschReading, + 0, + 30, + 1)); + + b = new javax.swing.Box (javax.swing.BoxLayout.X_AXIS); + + b.add (this.frF); + b.add (javax.swing.Box.createHorizontalGlue ()); + + this.frF.setMaximumSize (this.frF.getPreferredSize ()); + + items.add (new com.quollwriter.ui.forms.AnyFormItem (Environment.getUIString (pref, + LanguageStrings.fr), + //"Flesch Reading ease level", + b)); + + this.gfF = new javax.swing.JSpinner (new javax.swing.SpinnerNumberModel (this.gunningFog, + 0, + 30, + 1)); + + b = new javax.swing.Box (javax.swing.BoxLayout.X_AXIS); + + b.add (this.gfF); + b.add (javax.swing.Box.createHorizontalGlue ()); + + this.gfF.setMaximumSize (this.gfF.getPreferredSize ()); + + items.add (new com.quollwriter.ui.forms.AnyFormItem (Environment.getUIString (pref, + LanguageStrings.gf), + //"Gunning Fog index", + b)); + + return items; + + } + + @Override + public String getFormError () + { + + return null; + + } + + @Override + public void updateFromForm () + { + + this.fleschKincaid = ((javax.swing.SpinnerNumberModel) this.fkF.getModel ()).getNumber ().intValue (); + this.fleschReading = ((javax.swing.SpinnerNumberModel) this.frF.getModel ()).getNumber ().intValue (); + this.gunningFog = ((javax.swing.SpinnerNumberModel) this.gfF.getModel ()).getNumber ().intValue (); + + } + + @Override + public void updateFromForm2 () + { + + this.fleschKincaid = this.fkF2.getValue (); + this.fleschReading = this.frF2.getValue (); + this.gunningFog = this.gfF2.getValue (); + + } + +} diff --git a/src/com/quollwriter/text/rules/ParagraphRule.java b/src/main/java/com/quollwriter/text/rules/ParagraphRule.java similarity index 100% rename from src/com/quollwriter/text/rules/ParagraphRule.java rename to src/main/java/com/quollwriter/text/rules/ParagraphRule.java diff --git a/src/com/quollwriter/text/rules/PassiveSentenceRule.java b/src/main/java/com/quollwriter/text/rules/PassiveSentenceRule.java similarity index 76% rename from src/com/quollwriter/text/rules/PassiveSentenceRule.java rename to src/main/java/com/quollwriter/text/rules/PassiveSentenceRule.java index 83c59e7d..7023c7c4 100644 --- a/src/com/quollwriter/text/rules/PassiveSentenceRule.java +++ b/src/main/java/com/quollwriter/text/rules/PassiveSentenceRule.java @@ -4,10 +4,6 @@ import javax.swing.*; -import com.gentlyweb.utils.*; - -import com.gentlyweb.xml.*; - import com.quollwriter.*; import com.quollwriter.synonyms.*; @@ -16,8 +12,13 @@ import com.quollwriter.ui.forms.*; -import org.jdom.*; +import org.dom4j.*; +import com.quollwriter.ui.fx.components.Form; +import com.quollwriter.ui.fx.components.QuollCheckBox; + +import static com.quollwriter.uistrings.UILanguageStringsManager.getUILanguageStringProperty; +import static com.quollwriter.LanguageStrings.*; public class PassiveSentenceRule extends AbstractSentenceRule { @@ -31,12 +32,14 @@ public class XMLConstants } - private Set beWords = new HashSet (); - private Set irregularForms = new HashSet (); + private Set beWords = new HashSet<> (); + private Set irregularForms = new HashSet<> (); private boolean ignoreInDialogue = false; private CheckboxFormItem ignoreDialogueF = null; + private QuollCheckBox ignoreDialogueF2 = null; + public PassiveSentenceRule () { @@ -45,14 +48,14 @@ public PassiveSentenceRule () public void setIrregularForms (Set forms) { - this.irregularForms = new HashSet (forms); + this.irregularForms = new HashSet<> (forms); } public void setBeWords (Set words) { - this.beWords = new HashSet (words); + this.beWords = new HashSet<> (words); } @@ -90,12 +93,12 @@ public String getSummary () @Override public void init (Element root) - throws JDOMException + throws GeneralException { super.init (root); - String sw = JDOMUtils.getAttributeValue (root, + String sw = DOM4JUtils.attributeValue (root, XMLConstants.beWords); StringTokenizer t = new StringTokenizer (sw, @@ -108,7 +111,7 @@ public void init (Element root) } - String w = JDOMUtils.getAttributeValue (root, + String w = DOM4JUtils.attributeValue (root, XMLConstants.irregularForms); t = new StringTokenizer (w, @@ -121,7 +124,7 @@ public void init (Element root) } - this.ignoreInDialogue = JDOMUtils.getAttributeValueAsBoolean (root, + this.ignoreInDialogue = DOM4JUtils.attributeValueAsBoolean (root, XMLConstants.ignoreInDialogue, false); @@ -136,7 +139,7 @@ public Element getAsElement () if (this.ignoreInDialogue) { - root.setAttribute (XMLConstants.ignoreInDialogue, + root.addAttribute (XMLConstants.ignoreInDialogue, Boolean.toString (this.ignoreInDialogue)); } @@ -157,7 +160,7 @@ public Element getAsElement () } - root.setAttribute (XMLConstants.beWords, + root.addAttribute (XMLConstants.beWords, b.toString ()); b = new StringBuilder (); @@ -176,7 +179,7 @@ public Element getAsElement () } - root.setAttribute (XMLConstants.irregularForms, + root.addAttribute (XMLConstants.irregularForms, b.toString ()); return root; @@ -187,7 +190,7 @@ public Element getAsElement () public List getIssues (Sentence sentence) { - List issues = new ArrayList (); + List issues = new ArrayList<> (); List swords = sentence.getWords (); @@ -299,12 +302,18 @@ public boolean isPastTenseVerb (String w) try { - if (Environment.getWordTypes (w, - // Assume english for now - null) == null) + // Assume english for now + SynonymProvider sp = Environment.getSynonymProvider (Constants.ENGLISH); + + if (sp != null) { - w += "e"; + if (sp.getWordTypes (w) == null) + { + + w += "e"; + + } } @@ -319,9 +328,14 @@ public boolean isPastTenseVerb (String w) try { - t = Environment.getWordTypes (w, - // Assume english for now - null); + SynonymProvider sp = Environment.getSynonymProvider (Constants.ENGLISH); + + if (sp != null) + { + + t = sp.getWordTypes (w); + + } } catch (Exception e) { @@ -360,13 +374,8 @@ public Set getFormItems () Set items = new LinkedHashSet (); - List pref = new ArrayList (); - pref.add (LanguageStrings.problemfinder); - pref.add (LanguageStrings.config); - pref.add (LanguageStrings.rules); - pref.add (LanguageStrings.passivesentence); - pref.add (LanguageStrings.labels); - + List pref = Arrays.asList (LanguageStrings.problemfinder,LanguageStrings.config,LanguageStrings.rules,LanguageStrings.passivesentence,LanguageStrings.labels); + this.ignoreDialogueF = new CheckboxFormItem (null, Environment.getUIString (pref, LanguageStrings.ignoreindialogue)); @@ -380,6 +389,25 @@ public Set getFormItems () } + @Override + public Set getFormItems2 () + { + + Set items = new LinkedHashSet<> (); + + List pref = Arrays.asList (LanguageStrings.problemfinder,LanguageStrings.config,LanguageStrings.rules,LanguageStrings.passivesentence,LanguageStrings.labels); + + this.ignoreDialogueF2 = QuollCheckBox.builder () + .label (getUILanguageStringProperty (Utils.newList (pref,ignoreindialogue))) + .selected (this.ignoreInDialogue) + .build (); + + items.add (new Form.Item (this.ignoreDialogueF2)); + + return items; + + } + @Override public String getFormError () { @@ -388,6 +416,14 @@ public String getFormError () } + @Override + public void updateFromForm2 () + { + + this.ignoreInDialogue = this.ignoreDialogueF2.isSelected (); + + } + @Override public void updateFromForm () { diff --git a/src/com/quollwriter/text/rules/RuleFactory.java b/src/main/java/com/quollwriter/text/rules/RuleFactory.java similarity index 78% rename from src/com/quollwriter/text/rules/RuleFactory.java rename to src/main/java/com/quollwriter/text/rules/RuleFactory.java index 83e32680..a5f1144e 100644 --- a/src/com/quollwriter/text/rules/RuleFactory.java +++ b/src/main/java/com/quollwriter/text/rules/RuleFactory.java @@ -1,19 +1,18 @@ package com.quollwriter.text.rules; import java.io.*; +import java.nio.file.*; +import java.util.stream.*; import java.util.*; import com.gentlyweb.properties.StringProperty; -import com.gentlyweb.xml.*; - import com.quollwriter.*; import com.quollwriter.text.*; -import org.jdom.*; - +import org.dom4j.*; public class RuleFactory { @@ -22,8 +21,8 @@ public class RuleFactory public static final int PROJECT = 2; public static final int ALL = 4; - private static Map> rules = new HashMap (); - private static Map ruleTypes = new HashMap (); + private static Map> rules = new HashMap<> (); + private static Map ruleTypes = new HashMap<> (); private static int lastUserRuleIndex = 0; @@ -32,19 +31,13 @@ public static void init () { // Load the standard rules. - String xml = Environment.getResourceFileAsString (Constants.PROBLEM_FINDER_RULES_FILE); + String xml = Utils.getResourceFileAsString (Constants.PROBLEM_FINDER_RULES_FILE); - Element root = JDOMUtils.getStringAsElement (xml); + Element root = DOM4JUtils.stringAsElement (xml); - List els = JDOMUtils.getChildElements (root, - AbstractRule.XMLConstants.root, - false); - - for (int i = 0; i < els.size (); i++) + for (Element el : root.elements (AbstractRule.XMLConstants.root)) { - Element el = (Element) els.get (i); - Rule r = null; try @@ -57,7 +50,7 @@ public static void init () Environment.logError ("Unable to create rule", new GeneralException ("Unable to create rule from element: " + - JDOMUtils.getPath (el), + DOM4JUtils.getPath (el), e)); continue; @@ -69,7 +62,7 @@ public static void init () if (l == null) { - l = new HashMap (); + l = new HashMap<> (); RuleFactory.rules.put (r.getCategory (), l); @@ -81,54 +74,65 @@ public static void init () } // Load the user defined rules. - File dir = new File (Environment.getUserQuollWriterDir ().getPath () + "/" + Constants.USER_PROBLEM_FINDER_RULES_DIR); + Path dir = Environment.getUserPath (Constants.USER_PROBLEM_FINDER_RULES_DIR); - File[] files = dir.listFiles (new FilenameFilterAdapter () + if (Files.exists (dir)) + { + + try (Stream ls = Files.walk (dir)) { - public boolean accept (File dir, - String name) + ls.filter (f -> f.getFileName ().toString ().endsWith (".xml")) + .forEach (f -> { - if (name.endsWith (".xml")) + try { - return true; + RuleFactory.loadUserRule (f); - } + } catch (Exception e) + { - return false; + // Delete the rule. + try + { - } + Files.delete (f); - }); + } catch (Exception ee) { - if (files != null) - { + Environment.logError ("Unable to delete user rule file: " + + f, + ee); - for (int i = 0; i < files.length; i++) - { + } - try - { + Environment.logError ("Unable to load user rule: " + + f, + e); - RuleFactory.loadUserRule (files[i]); + } - } catch (Exception e) - { + }); - // Delete the rule. - files[i].delete (); + } - Environment.logError ("Unable to load user rule: " + - files[i], - e); + } - } + } - } + public static Path getUserRuleFilePath (Rule r) + { - } + return RuleFactory.getUserRulesDirPath ().resolve (r.getId () + ".xml"); + + } + + public static Path getUserRulesDirPath () + { + + return Environment.getUserPath (Constants.USER_PROBLEM_FINDER_RULES_DIR); } @@ -136,6 +140,20 @@ public static void removeUserRule (Rule r) throws Exception { + Path f = RuleFactory.getUserRuleFilePath (r); + + if (Files.deleteIfExists (f)) + { + + RuleFactory.rules.get (Rule.WORD_CATEGORY).remove (r.getId ()); + + } else { + + throw new GeneralException ("Unable to delete user rule file: " + f); + + } +/* +TODO File f = new File (Environment.getUserQuollWriterDir ().getPath () + "/" + Constants.USER_PROBLEM_FINDER_RULES_DIR + r.getId () + ".xml"); if (f.exists ()) @@ -151,6 +169,41 @@ public static void removeUserRule (Rule r) RuleFactory.rules.get (Rule.WORD_CATEGORY).remove (r.getId ()); } +*/ + } + + public static Set getProjectRules (com.gentlyweb.properties.Properties projProps) + { + + Map ignores = RuleFactory.getIgnores (ALL, + projProps); + + Set iids = ignores.keySet (); + + Set rs = new HashSet<> (); + + for (String t : RuleFactory.rules.keySet ()) + { + + Map rrs = RuleFactory.rules.get (t); + + for (Rule r : rrs.values ()) + { + + if (iids.contains (r.getId ())) + { + + continue; + + } + + rs.add (r); + + } + + } + + return rs; } @@ -198,7 +251,7 @@ public static Map getIgnores (int } - Map rulesToIgnore = new HashMap (); + Map rulesToIgnore = new HashMap<> (); StringTokenizer t = new StringTokenizer (toIgnore, ";"); @@ -327,12 +380,11 @@ private static void saveIgnores (Map ignores, } - private static Rule loadUserRule (File f) + private static Rule loadUserRule (Path f) throws Exception { - Element el = JDOMUtils.getFileAsElement (f, - Environment.GZIP_EXTENSION); + Element el = DOM4JUtils.fileAsElement (f); Rule r = RuleFactory.createRule (el, false); @@ -351,7 +403,7 @@ private static Rule loadUserRule (File f) l.put (r.getId (), r); - String fn = f.getName (); + String fn = f.getFileName ().toString (); if (fn.startsWith ("user-")) { @@ -394,6 +446,11 @@ public static void saveUserRule (Rule r) } + Path f = RuleFactory.getUserRuleFilePath (r); + + Files.createDirectories (f.getParent ()); +/* +TODO Clean up File f = new File (Environment.getUserQuollWriterDir ().getPath () + "/" + Constants.USER_PROBLEM_FINDER_RULES_DIR + r.getId ().toLowerCase () + ".xml"); if (!f.exists ()) @@ -413,10 +470,10 @@ public static void saveUserRule (Rule r) } } - - JDOMUtils.writeElementToFile (r.getAsElement (), - f, - true); +*/ + DOM4JUtils.writeToFile (r.getAsElement (), + f, + true); RuleFactory.loadUserRule (f); @@ -469,7 +526,7 @@ public static List getIssues (TextBlock block, com.gentlyweb.properties.Properties projProps) { - List issues = new ArrayList (); + List issues = new ArrayList<> (); if ((rule == null) || @@ -520,7 +577,7 @@ public static List getParagraphIssues (Paragraph com.gentlyweb.properties.Properties projProps) { - List issues = new ArrayList (); + List issues = new ArrayList<> (); Map rules = RuleFactory.rules.get (Rule.PARAGRAPH_CATEGORY); @@ -561,7 +618,7 @@ public static List getSentenceIssues (Sentence com.gentlyweb.properties.Properties projProps) { - List issues = new ArrayList (); + List issues = new ArrayList<> (); // Get the ignores. Map ignores = RuleFactory.getIgnores (ALL, @@ -623,10 +680,10 @@ public static List getSentenceIssues (Sentence private static Rule createRule (Element root, boolean userRule) - throws JDOMException + throws GeneralException { - String type = JDOMUtils.getAttributeValue (root, + String type = DOM4JUtils.attributeValue (root, AbstractRule.XMLConstants.createType); Class c = null; @@ -649,10 +706,9 @@ private static Rule createRule (Element root, } - throw new JDOMException (String.format ("Unable to load class: %s, referenced by: %s", + throw new GeneralException (String.format ("Unable to load class: %s, referenced by: %s", type, - JDOMUtils.getPath (JDOMUtils.getAttribute (root, - AbstractRule.XMLConstants.createType))), + DOM4JUtils.getPath (root.attribute (AbstractRule.XMLConstants.createType))), e); } @@ -662,14 +718,13 @@ private static Rule createRule (Element root, try { - r = (Rule) c.newInstance (); + r = (Rule) c.getDeclaredConstructor ().newInstance (); } catch (Exception e) { - throw new JDOMException (String.format ("Unable to create new instance of rule for class: %s, referenced by: %s", + throw new GeneralException (String.format ("Unable to create new instance of rule for class: %s, referenced by: %s", type, - JDOMUtils.getPath (JDOMUtils.getAttribute (root, - AbstractRule.XMLConstants.createType))), + DOM4JUtils.getPath (root.attribute (AbstractRule.XMLConstants.createType))), e); } @@ -692,12 +747,12 @@ private static Rule createRule (Element root, */ private static Rule createLegacyRule (Element root, boolean userRule) - throws JDOMException + throws GeneralException { Rule r = null; - String type = JDOMUtils.getAttributeValue (root, + String type = DOM4JUtils.attributeValue (root, AbstractRule.XMLConstants.createType); if (type.equals ("wordFinder")) @@ -795,7 +850,7 @@ public static List getParagraphRules () public static List getRules (String category) { - return new ArrayList (RuleFactory.rules.get (category).values ()); + return new ArrayList<> (RuleFactory.rules.get (category).values ()); } diff --git a/src/main/java/com/quollwriter/text/rules/SentenceComplexityRule.java b/src/main/java/com/quollwriter/text/rules/SentenceComplexityRule.java new file mode 100644 index 00000000..146e4b85 --- /dev/null +++ b/src/main/java/com/quollwriter/text/rules/SentenceComplexityRule.java @@ -0,0 +1,270 @@ +package com.quollwriter.text.rules; + +import java.util.*; + +import javafx.scene.control.*; +import javafx.scene.control.SpinnerValueFactory.*; + +import java.text.*; + +import com.quollwriter.*; +import com.quollwriter.text.*; + +import org.dom4j.*; + +import com.quollwriter.ui.fx.components.Form; +import com.quollwriter.ui.fx.components.*; + +import static com.quollwriter.LanguageStrings.*; +import static com.quollwriter.uistrings.UILanguageStringsManager.getUILanguageStringProperty; + +public class SentenceComplexityRule extends AbstractSentenceRule +{ + + public class XMLConstants + { + + public static final String ratio = "ratio"; + public static final String wordCount = "wordCount"; + + } + + private float ratio = 0; + private int wordCount = 0; + private javax.swing.JSpinner ratioF = null; + private javax.swing.JSpinner wordCountF = null; + + private Spinner ratioF2 = null; + private Spinner wordCountF2 = null; + + public SentenceComplexityRule () + { + + } + + public SentenceComplexityRule (float syllableWordRatio, + int wordCount, + boolean user) + { + + this.ratio = syllableWordRatio; + this.wordCount = wordCount; + this.setUserRule (user); + + } + + @Override + public String getDescription () + { + + String d = super.getDescription (); + + d = Utils.replaceString (d, + "[RATIO]", + Environment.formatNumber (this.ratio) + ""); + + d = Utils.replaceString (d, + "[COUNT]", + this.wordCount + ""); + + return d; + + } + + @Override + public String getSummary () + { + + String t = Utils.replaceString (super.getSummary (), + "[RATIO]", + Environment.formatNumber (this.ratio) + ""); + + t = Utils.replaceString (t, + "[COUNT]", + this.wordCount + ""); + + return t; + + } + + @Override + public void init (Element root) + throws GeneralException + { + + super.init (root); + + this.ratio = DOM4JUtils.attributeValueAsFloat (root, + XMLConstants.ratio); + this.wordCount = DOM4JUtils.attributeValueAsInt (root, + XMLConstants.wordCount); + + } + + @Override + public Element getAsElement () + { + + Element root = super.getAsElement (); + + root.addAttribute (XMLConstants.ratio, + this.ratio + ""); + root.addAttribute (XMLConstants.wordCount, + this.wordCount + ""); + + return root; + + } + + @Override + public List getIssues (Sentence sentence) + { + + List issues = new ArrayList<> (); + + float wordC = (float) sentence.getWordCount (); + + if (wordC <= this.wordCount) + { + + return issues; + + } + + float syllC = (float) sentence.getSyllableCount (); + + float r = syllC / wordC; + + r = (float) Math.round (r * 10) / 10; + + if (r > this.ratio) + { + + DecimalFormat df = new DecimalFormat ("##.#"); + + String n = df.format (r); + + Issue iss = new Issue (String.format (Environment.getUIString (LanguageStrings.problemfinder, + LanguageStrings.issues, + LanguageStrings.sentencecomplexity, + LanguageStrings.text), + //"Sentence syllable/word ratio is: %s. (Max is: %s)", + n, + Environment.formatNumber (this.ratio)), + sentence, + sentence.getAllTextStartOffset () + "-sentencetoocomplex-" + r, + this); + + issues.add (iss); + + } + + return issues; + + } + + @Override + public String getCategory () + { + + return Rule.SENTENCE_CATEGORY; + + } + + @Override + public Set getFormItems () + { + + List pref = new ArrayList<> (); + pref.add (LanguageStrings.problemfinder); + pref.add (LanguageStrings.config); + pref.add (LanguageStrings.rules); + pref.add (LanguageStrings.sentencecomplexity); + pref.add (LanguageStrings.labels); + + Set items = new LinkedHashSet<> (); + + this.ratioF = new javax.swing.JSpinner (new javax.swing.SpinnerNumberModel (this.ratio, + 0.1f, + 3.0f, + 0.1)); + + javax.swing.Box b = new javax.swing.Box (javax.swing.BoxLayout.X_AXIS); + b.add (this.ratioF); + b.add (javax.swing.Box.createHorizontalGlue ()); + + this.ratioF.setMaximumSize (this.ratioF.getPreferredSize ()); + + items.add (new com.quollwriter.ui.forms.AnyFormItem (Environment.getUIString (pref, + LanguageStrings.ratio), + b)); + + this.wordCountF = new javax.swing.JSpinner (new javax.swing.SpinnerNumberModel (this.wordCount, + 1, + 500, + 1)); + + b = new javax.swing.Box (javax.swing.BoxLayout.X_AXIS); + + b.add (this.wordCountF); + b.add (javax.swing.Box.createHorizontalGlue ()); + + this.wordCountF.setMaximumSize (this.wordCountF.getPreferredSize ()); + + items.add (new com.quollwriter.ui.forms.AnyFormItem (Environment.getUIString (pref, + LanguageStrings.sentencelength), + //"Sentence length (words)", + b)); + + return items; + + } + + @Override + public Set getFormItems2 () + { + + List pref = Arrays.asList (problemfinder,config,rules,sentencecomplexity,labels); + + Set items = new LinkedHashSet<> (); + + this.ratioF2 = new Spinner<> (new DoubleSpinnerValueFactory (0.1d, 3.0d, this.ratio, 0.1d)); + + items.add (new Form.Item (getUILanguageStringProperty (Utils.newList (pref,LanguageStrings.ratio)), + this.ratioF2)); + + this.wordCountF2 = new Spinner<> (new IntegerSpinnerValueFactory (1, 500, this.wordCount, 1)); + + items.add (new Form.Item (getUILanguageStringProperty (Utils.newList (pref,sentencelength)), + //"Sentence length (words)", + this.wordCountF2)); + + return items; + + } + + public String getFormError () + { + + return null; + + } + + public void updateFromForm () + { + + this.ratio = ((javax.swing.SpinnerNumberModel) this.ratioF.getModel ()).getNumber ().floatValue (); + this.wordCount = ((javax.swing.SpinnerNumberModel) this.wordCountF.getModel ()).getNumber ().intValue (); + + } + + @Override + public void updateFromForm2 () + { + + this.ratio = this.ratioF2.getValue ().floatValue (); + this.wordCount = this.wordCountF2.getValue (); + + } + +} diff --git a/src/main/java/com/quollwriter/text/rules/SentenceLengthRule.java b/src/main/java/com/quollwriter/text/rules/SentenceLengthRule.java new file mode 100644 index 00000000..f18996c7 --- /dev/null +++ b/src/main/java/com/quollwriter/text/rules/SentenceLengthRule.java @@ -0,0 +1,210 @@ +package com.quollwriter.text.rules; + +import java.util.*; + +import javafx.scene.control.*; +import javafx.scene.control.SpinnerValueFactory.*; + +import com.quollwriter.*; +import com.quollwriter.text.*; + +import org.dom4j.*; + +import com.quollwriter.ui.fx.components.Form; +import com.quollwriter.ui.fx.components.*; + +import static com.quollwriter.LanguageStrings.*; +import static com.quollwriter.uistrings.UILanguageStringsManager.getUILanguageStringProperty; + +public class SentenceLengthRule extends AbstractSentenceRule +{ + + public class XMLConstants + { + + public static final String wordCount = "wordCount"; + + } + + private int wordCount = 0; + private javax.swing.JSpinner count = null; + + private Spinner count2 = null; + + public SentenceLengthRule () + { + + } + + public SentenceLengthRule (int wordCount, + boolean user) + { + + this.wordCount = wordCount; + this.setUserRule (user); + + } + + @Override + public String getDescription () + { + + String d = super.getDescription (); + + return Utils.replaceString (d, + "[LIMIT]", + this.wordCount + ""); + + } + + @Override + public String getSummary () + { + + return Utils.replaceString (super.getSummary (), + "[LIMIT]", + this.wordCount + ""); + + } + + @Override + public void init (Element root) + throws GeneralException + { + + super.init (root); + + this.wordCount = DOM4JUtils.attributeValueAsInt (root, + XMLConstants.wordCount); + + } + + @Override + public Element getAsElement () + { + + Element root = super.getAsElement (); + + root.addAttribute (XMLConstants.wordCount, + this.wordCount + ""); + + return root; + + } + + @Override + public List getIssues (Sentence sentence) + { + + // Check each word to make sure it's not punctuation. + List issues = new ArrayList<> (); + + int wc = sentence.getWordCount (); + + if (wc > this.wordCount) + { + + Issue iss = new Issue (String.format (Environment.getUIString (LanguageStrings.problemfinder, + LanguageStrings.issues, + LanguageStrings.sentencelength, + LanguageStrings.text), + Environment.formatNumber (wc), + Environment.formatNumber (this.wordCount)), + //"Sentence contains: " + wc + " words.", + sentence, + sentence.getAllTextStartOffset (), + sentence.getLastWord ().getAllTextEndOffset () - sentence.getAllTextStartOffset (), + sentence.getAllTextStartOffset () + "-toomanywords-" + wc, + this); + + issues.add (iss); + + } + + return issues; + + } + + @Override + public String getCategory () + { + + return Rule.SENTENCE_CATEGORY; + + } + + @Override + public Set getFormItems () + { + + List pref = new ArrayList (); + pref.add (LanguageStrings.problemfinder); + pref.add (LanguageStrings.config); + pref.add (LanguageStrings.rules); + pref.add (LanguageStrings.sentencelength); + pref.add (LanguageStrings.labels); + + Set items = new LinkedHashSet (); + + this.count = new javax.swing.JSpinner (new javax.swing.SpinnerNumberModel (this.wordCount, + 1, + 200, + 1)); + + javax.swing.Box b = new javax.swing.Box (javax.swing.BoxLayout.X_AXIS); + b.add (this.count); + b.add (javax.swing.Box.createHorizontalGlue ()); + + this.count.setMaximumSize (this.count.getPreferredSize ()); + + items.add (new com.quollwriter.ui.forms.AnyFormItem (Environment.getUIString (pref, + LanguageStrings.words), + //"No of Words", + b)); + + return items; + + } + + @Override + public Set getFormItems2 () + { + + List pref = Arrays.asList (problemfinder,config,rules,sentencelength,labels); + + Set items = new LinkedHashSet<> (); + + this.count2 = new Spinner (new IntegerSpinnerValueFactory (1, 200, this.wordCount, 1)); + + items.add (new Form.Item (getUILanguageStringProperty (Utils.newList (pref,words)), + //"No of Words", + this.count2)); + + return items; + + } + + @Override + public String getFormError () + { + + return null; + + } + + public void updateFromForm () + { + + this.wordCount = ((javax.swing.SpinnerNumberModel) this.count.getModel ()).getNumber ().intValue (); + + } + + @Override + public void updateFromForm2 () + { + + this.wordCount = this.count2.getValue (); + + } + +} diff --git a/src/com/quollwriter/text/rules/SentenceRule.java b/src/main/java/com/quollwriter/text/rules/SentenceRule.java similarity index 100% rename from src/com/quollwriter/text/rules/SentenceRule.java rename to src/main/java/com/quollwriter/text/rules/SentenceRule.java diff --git a/src/main/java/com/quollwriter/text/rules/TooManyClausesRule.java b/src/main/java/com/quollwriter/text/rules/TooManyClausesRule.java new file mode 100644 index 00000000..c317301b --- /dev/null +++ b/src/main/java/com/quollwriter/text/rules/TooManyClausesRule.java @@ -0,0 +1,236 @@ +package com.quollwriter.text.rules; + +import java.util.*; +import java.awt.event.*; + +import javafx.scene.control.*; +import javafx.scene.control.SpinnerValueFactory.*; + +import com.quollwriter.*; +import com.quollwriter.text.*; + +import org.dom4j.*; + +import com.quollwriter.ui.fx.components.Form; +import com.quollwriter.ui.fx.components.*; + +import static com.quollwriter.uistrings.UILanguageStringsManager.getUILanguageStringProperty; +import static com.quollwriter.LanguageStrings.*; + +public class TooManyClausesRule extends AbstractSentenceRule +{ + + public class XMLConstants + { + + public static final String clauseCount = "clauseCount"; + + } + + private int clauseCount = 0; + private javax.swing.JSpinner count = null; + private Map separators = new HashMap<> (); + + private Spinner count2 = null; + + public TooManyClausesRule () + { + + this.separators.put (",", + ","); + this.separators.put ("-", + "-"); + + } + + public TooManyClausesRule (int clauseCount, + boolean user) + { + + this (); + + this.clauseCount = clauseCount; + this.setUserRule (user); + + } + + public String getDescription () + { + + String d = super.getDescription (); + + return Utils.replaceString (d, + "[LIMIT]", + this.clauseCount + ""); + + } + + @Override + public String getSummary () + { + + return Utils.replaceString (super.getSummary (), + "[LIMIT]", + this.clauseCount + ""); + + } + + @Override + public void init (Element root) + throws GeneralException + { + + super.init (root); + + this.clauseCount = DOM4JUtils.attributeValueAsInt (root, + XMLConstants.clauseCount); + + } + + @Override + public Element getAsElement () + { + + Element root = super.getAsElement (); + + root.addAttribute (XMLConstants.clauseCount, + this.clauseCount + ""); + + return root; + + } + + @Override + public List getIssues (Sentence sentence) + { + + int c = 1; + int i = 0; + + for (Word w : sentence.getWords ()) + { + + if (this.separators.containsKey (w.getText ())) + { + + if (i > 0) + { + + c++; + + } + + } + + i++; + + } + + // Look for , ; or -. + List issues = new ArrayList<> (); + + if (c > this.clauseCount) + { + + Issue iss = new Issue (String.format (Environment.getUIString (LanguageStrings.problemfinder, + LanguageStrings.issues, + LanguageStrings.toomanyclauses, + LanguageStrings.text), + Environment.formatNumber (c), + Environment.formatNumber (this.clauseCount)), + //"Sentence contains: " + c + " clauses.", + sentence, + sentence.getAllTextStartOffset () + "-toomanyclauses-" + c, + this); + + issues.add (iss); + + } + + return issues; + + } + + @Override + public Set getFormItems () + { + + List pref = new ArrayList (); + pref.add (LanguageStrings.problemfinder); + pref.add (LanguageStrings.config); + pref.add (LanguageStrings.rules); + pref.add (LanguageStrings.toomanyclauses); + pref.add (LanguageStrings.labels); + + Set items = new LinkedHashSet<> (); + + this.count = new javax.swing.JSpinner (new javax.swing.SpinnerNumberModel (this.clauseCount, + 1, + 200, + 1)); + + javax.swing.Box b = new javax.swing.Box (javax.swing.BoxLayout.X_AXIS); + b.add (this.count); + b.add (javax.swing.Box.createHorizontalGlue ()); + + this.count.setMaximumSize (this.count.getPreferredSize ()); + + items.add (new com.quollwriter.ui.forms.AnyFormItem (Environment.getUIString (pref, + LanguageStrings.clauses), + //"No of Clauses", + b)); + + return items; + + } + + @Override + public Set getFormItems2 () + { + + List pref = Arrays.asList (problemfinder,config,rules,toomanyclauses,labels); + + Set items = new LinkedHashSet<> (); + + this.count2 = new Spinner<> (new IntegerSpinnerValueFactory (1, 200, this.clauseCount, 1)); + + items.add (new Form.Item (getUILanguageStringProperty (Utils.newList (pref,clauses)), + //"No of Clauses", + this.count2)); + + return items; + + } + + @Override + public String getFormError () + { + + return null; + + } + + @Override + public void updateFromForm () + { + + this.clauseCount = ((javax.swing.SpinnerNumberModel) this.count.getModel ()).getNumber ().intValue (); + + } + + public String getCategory () + { + + return Rule.SENTENCE_CATEGORY; + + } + + @Override + public void updateFromForm2 () + { + + this.clauseCount = this.count2.getValue (); + + } + +} diff --git a/src/main/java/com/quollwriter/text/rules/WordFinder.java b/src/main/java/com/quollwriter/text/rules/WordFinder.java new file mode 100644 index 00000000..0847db17 --- /dev/null +++ b/src/main/java/com/quollwriter/text/rules/WordFinder.java @@ -0,0 +1,638 @@ +package com.quollwriter.text.rules; + +import java.util.*; + +import javafx.scene.control.*; +import javafx.beans.property.*; + +import com.quollwriter.*; +import com.quollwriter.text.*; +import com.quollwriter.uistrings.*; + +import com.quollwriter.ui.fx.components.Form; +import com.quollwriter.ui.fx.components.QuollTextField; +import com.quollwriter.ui.fx.components.QuollCheckBox; + +import org.dom4j.*; + +import static com.quollwriter.uistrings.UILanguageStringsManager.getUILanguageStringProperty; +import static com.quollwriter.LanguageStrings.*; + +public class WordFinder extends AbstractDialogueRule +{ + + public class XMLConstants + { + + public static final String word = "word"; + + } + + private String word = null; + + private TextField words2 = null; + private CheckBox ignoreInDialogueCB2 = null; + private CheckBox onlyInDialogueCB2 = null; + private ChoiceBox where2 = null; + + //private TextFormItem words = null; + private List tWords = null; + //private CheckboxFormItem ignoreInDialogueCB = null; + //private CheckboxFormItem onlyInDialogueCB = null; + //private ComboBoxFormItem whereCB = null; + + public WordFinder () + { + + } + + public boolean isForLanguage (String language) + { + + return UILanguageStrings.isEnglish (language); + + } + + public String toString () + { + + return "rule(word=" + this.word + ")"; + + } + + public String getCategory () + { + + return Rule.WORD_CATEGORY; + + } + + public void setWord (String w) + { + + this.word = w; + + this.tWords = TextUtilities.getAsWords (this.word.toLowerCase ()); + + } + + @Override + public String getSummary () + { + + if (this.word == null) + { + + return null; + + } + + return String.format ("\"%s\" %s", + this.word, + this.getWhereDesc ()); + + } + + @Override + public String getEditFormTitle (boolean add) + { + + return (add ? Environment.getUIString (LanguageStrings.problemfinder, + LanguageStrings.config, + LanguageStrings.rules, + LanguageStrings.wordfinder, + LanguageStrings.addtitle) + : Environment.getUIString (LanguageStrings.problemfinder, + LanguageStrings.config, + LanguageStrings.rules, + LanguageStrings.wordfinder, + LanguageStrings.edittitle)); + + } + + private String getWhereDesc () + { + + String suffix = ""; + + if (this.where != null) + { + + List pref = new ArrayList (); + pref.add (LanguageStrings.problemfinder); + pref.add (LanguageStrings.config); + pref.add (LanguageStrings.rules); + pref.add (LanguageStrings.wordfinder); + pref.add (LanguageStrings.description); + + String s = (this.ignoreInDialogue ? Environment.getUIString (pref, + LanguageStrings.suffixes, + LanguageStrings.ignoreindialogue) : + Environment.getUIString (pref, + LanguageStrings.suffixes, + LanguageStrings.onlyindialogue)); + + if (this.where.equals (DialogueConstraints.ANYWHERE)) + { + + suffix = String.format (Environment.getUIString (pref, + LanguageStrings.anywhere), + s); + //"anywhere in a sentence"; + + } else + { + + suffix = String.format (Environment.getUIString (pref, + LanguageStrings.insentence), + //"at the %s of a sentence", + this.where, + s); + + } +/* + if (this.ignoreInDialogue) + { + + suffix += ", ignore in dialogue"; + + } + + if (this.onlyInDialogue) + { + + suffix += ", but only in dialogue"; + + } +*/ + } + + return suffix; + + } + + @Override + public void init (Element root) + throws GeneralException + { + + super.init (root); + + this.setWord (DOM4JUtils.attributeValue (root, + XMLConstants.word)); + + } + + public String getWord () + { + + return this.word; + + } + + @Override + public Element getAsElement () + { + + Element root = super.getAsElement (); + + root.addAttribute (XMLConstants.word, + this.word); + + return root; + + } + + @Override + public List getIssues (Sentence sentence) + { + + // Check our list of words. + + List issues = new ArrayList (); + + Set inds = sentence.find (this.tWords, + this.getConstraints ()); + + if ((inds != null) + && + (inds.size () > 0) + ) + { + + for (Integer i : inds) + { + + Word w = sentence.getWord (i); + + int l = w.getText ().length (); + + if (this.tWords.size () > 1) + { + + Word nw = w.getWordsAhead (this.tWords.size () - 1); + + l = nw.getAllTextEndOffset () - w.getAllTextStartOffset (); + + } + + String suffix = ""; + + List pref = new ArrayList (); + + pref.add (LanguageStrings.problemfinder); + pref.add (LanguageStrings.issues); + pref.add (LanguageStrings.wordfinder); + + if (this.onlyInDialogue) + { + + suffix = Environment.getUIString (pref, + LanguageStrings.suffixes, + LanguageStrings.onlyindialogue); + //" (in dialogue)"; + + } + + if (!this.where.equals (DialogueConstraints.ANYWHERE)) + { + + if (this.onlyInDialogue) + { + + suffix = Environment.getUIString (pref, + LanguageStrings.suffixes, + LanguageStrings.indialogue); + + } else { + + suffix = Environment.getUIString (pref, + LanguageStrings.suffixes, + LanguageStrings.notindialogue); + + } + + suffix = String.format (suffix, + this.where); + + } + + Issue iss = new Issue (String.format (Environment.getUIString (pref, + LanguageStrings.text), + this.word, + suffix), + //"Contains: " + this.word + "" + suffix, + sentence, + w.getAllTextStartOffset (), + l, + w.getAllTextStartOffset () + "-" + this.word, + this); + issues.add (iss); + + } + + } + + return issues; + + } + + public void updateFromForm2 () + { + + this.setOnlyInDialogue (this.onlyInDialogueCB2.isSelected ()); + this.setIgnoreInDialogue (this.ignoreInDialogueCB2.isSelected ()); + + int ws = this.where2.getSelectionModel ().getSelectedIndex (); + + if (ws == 0) + { + + this.setWhere (DialogueConstraints.ANYWHERE); + + } + + if (ws == 1) + { + + this.setWhere (DialogueConstraints.START); + + } + + if (ws == 2) + { + + this.setWhere (DialogueConstraints.END); + + } + + this.setWord (this.words2.getText ().trim ()); + + } + + public void updateFromForm () + { +/* +TODO Remove + this.setOnlyInDialogue (this.onlyInDialogueCB.isSelected ()); + this.setIgnoreInDialogue (this.ignoreInDialogueCB.isSelected ()); + + int ws = this.whereCB.getSelectedIndex (); + + if (ws == 0) + { + + this.setWhere (DialogueConstraints.ANYWHERE); + + } + + if (ws == 1) + { + + this.setWhere (DialogueConstraints.START); + + } + + if (ws == 2) + { + + this.setWhere (DialogueConstraints.END); + + } + + this.setWord (this.words.getText ().trim ()); +*/ + } + + @Override + public String getDescription () + { + + String d = super.getDescription (); + + if (d == null) + { + + return null; + + } + + return Utils.replaceString (d, + "[WORD]", + ((this.word == null) ? "[WORD]" : this.word)); + + } + + @Override + public Set getFormItems2 () + { + + Set items = new LinkedHashSet<> (); + + List pref = Arrays.asList (problemfinder,config,rules,wordfinder,labels); + + this.words2 = QuollTextField.builder () + .text (this.word) + .build (); + + items.add (new Form.Item (getUILanguageStringProperty (Utils.newList (pref, wordphrase)), + this.words2)); + + this.where2 = new ChoiceBox<> (); + + this.where2.getItems ().addAll (getUILanguageStringProperty (Utils.newList (pref, anywhere)).getValue (), + getUILanguageStringProperty (Utils.newList (pref, startofsentence)).getValue (), + getUILanguageStringProperty (Utils.newList (pref, endofsentence)).getValue ()); + + int sel = 0; + + String loc = this.getWhere (); + + if (loc.equals (DialogueConstraints.START)) + { + + sel = 1; + + } + + if (loc.equals (DialogueConstraints.END)) + { + + sel = 2; + + } + + this.where2.getSelectionModel ().select (sel); + + items.add (new Form.Item (getUILanguageStringProperty (Utils.newList (pref, where)), + this.where2)); + + this.ignoreInDialogueCB2 = QuollCheckBox.builder () + .label (getUILanguageStringProperty (Utils.newList (pref, ignoreindialogue))) + .build (); + + items.add (new Form.Item (this.ignoreInDialogueCB2)); + + this.onlyInDialogueCB2 = QuollCheckBox.builder () + .label (getUILanguageStringProperty (Utils.newList (pref, onlyindialogue))) + .build (); + + items.add (new Form.Item (this.onlyInDialogueCB2)); + + this.ignoreInDialogueCB2.selectedProperty ().addListener ((pr, oldv, newv) -> + { + + if (newv) + { + + this.onlyInDialogueCB2.setSelected (false); + + } + + }); + + this.onlyInDialogueCB2.selectedProperty ().addListener ((pr, oldv, newv) -> + { + + if (newv) + { + + this.ignoreInDialogueCB2.setSelected (false); + + } + + }); + + this.ignoreInDialogueCB2.setSelected (this.isIgnoreInDialogue ()); + this.onlyInDialogueCB2.setSelected (this.isOnlyInDialogue ()); + + items.add (new Form.Item (this.ignoreInDialogueCB2)); + + items.add (new Form.Item (this.onlyInDialogueCB2)); + + return items; + + } + + @Override + // TODO REmove + public Set getFormItems () + { + + Set items = new LinkedHashSet<> (); + +/* + List pref = new ArrayList (); + pref.add (LanguageStrings.problemfinder); + pref.add (LanguageStrings.config); + pref.add (LanguageStrings.rules); + pref.add (LanguageStrings.wordfinder); + pref.add (LanguageStrings.labels); + + this.words = new TextFormItem (Environment.getUIString (pref, + LanguageStrings.wordphrase), + //"Word/Phrase", + this.word); + + items.add (this.words); + + Vector whereVals = new Vector<> (); + whereVals.add (Environment.getUIString (pref, + LanguageStrings.anywhere)); + //"Anywhere"); + whereVals.add (Environment.getUIString (pref, + LanguageStrings.startofsentence)); + //"Start of sentence"); + whereVals.add (Environment.getUIString (pref, + LanguageStrings.endofsentence)); + //"End of sentence"); + + String selected = whereVals.get (0); + + String loc = this.getWhere (); + + if (loc.equals (DialogueConstraints.START)) + { + + selected = whereVals.get (1); + + } + + if (loc.equals (DialogueConstraints.END)) + { + + selected = whereVals.get (2); + + } + + this.whereCB = new ComboBoxFormItem (Environment.getUIString (pref, + LanguageStrings.where), + //"Where", + whereVals, + selected, + null); + + final WordFinder _this = this; + + items.add (this.whereCB); + + this.ignoreInDialogueCB = new CheckboxFormItem (null, + Environment.getUIString (pref, + LanguageStrings.ignoreindialogue)); + //"Ignore in dialogue"); + this.onlyInDialogueCB = new CheckboxFormItem (null, + Environment.getUIString (pref, + LanguageStrings.onlyindialogue)); + //"Only in dialogue"); + + this.ignoreInDialogueCB.addItemListener (new ItemListener () + { + + @Override + public void itemStateChanged (ItemEvent ev) + { + + if (_this.ignoreInDialogueCB.isSelected ()) + { + + _this.onlyInDialogueCB.setSelected (false); + + } + + } + + }); + + this.onlyInDialogueCB.addItemListener (new ItemListener () + { + + @Override + public void itemStateChanged (ItemEvent ev) + { + + if (_this.onlyInDialogueCB.isSelected ()) + { + + _this.ignoreInDialogueCB.setSelected (false); + + } + + } + + }); + + this.ignoreInDialogueCB.setSelected (this.isIgnoreInDialogue ()); + this.onlyInDialogueCB.setSelected (this.isOnlyInDialogue ()); + + items.add (this.ignoreInDialogueCB); + + items.add (this.onlyInDialogueCB); +*/ + return items; + + } + + public StringProperty getFormError2 () + { + + String newWords = this.words2.getText (); + + if ((newWords == null) + || + (newWords.trim ().length () == 0) + ) + { + + return getUILanguageStringProperty (problemfinder,config,rules,wordfinder,nowordserror); + + } + + return null; + + } + + public String getFormError () + { +/* +TODO Remove + String newWords = this.words.getText (); + + if ((newWords == null) + || + (newWords.trim ().length () == 0) + ) + { + + return Environment.getUIString (LanguageStrings.problemfinder, + LanguageStrings.config, + LanguageStrings.rules, + LanguageStrings.wordfinder, + LanguageStrings.nowordserror); + + } +*/ + return null; + + } + +} diff --git a/src/com/quollwriter/tools/CreatePromptFiles.java b/src/main/java/com/quollwriter/tools/CreatePromptFiles.java similarity index 93% rename from src/com/quollwriter/tools/CreatePromptFiles.java rename to src/main/java/com/quollwriter/tools/CreatePromptFiles.java index 9a628ea9..9de87fca 100644 --- a/src/com/quollwriter/tools/CreatePromptFiles.java +++ b/src/main/java/com/quollwriter/tools/CreatePromptFiles.java @@ -1,16 +1,15 @@ package com.quollwriter.tools; import java.io.*; +import java.nio.file.*; import java.util.*; -import com.gentlyweb.xml.*; - import com.quollwriter.*; import com.quollwriter.data.*; -import org.jdom.*; +import org.dom4j.*; public class CreatePromptFiles @@ -125,13 +124,13 @@ public static void main (String[] argv) url, text); - File pFile = new File (outputDir.getPath () + "/" + id + ".txt"); + Path pFile = outputDir.toPath ().resolve (id + ".txt"); Element root = p.getAsElement (); - JDOMUtils.writeElementToFile (root, - pFile, - true); + DOM4JUtils.writeToFile (root, + pFile, + true); System.out.println ("STORY: " + storyName + ", AUTHOR: " + authorName + ", URL: " + url + ", ID: " + id); System.out.println ("WRITING TO: " + pFile); diff --git a/src/com/quollwriter/tools/CreateThesaurusFiles.java b/src/main/java/com/quollwriter/tools/CreateThesaurusFiles.java similarity index 100% rename from src/com/quollwriter/tools/CreateThesaurusFiles.java rename to src/main/java/com/quollwriter/tools/CreateThesaurusFiles.java diff --git a/src/com/quollwriter/tools/DeleteInstallJars.java b/src/main/java/com/quollwriter/tools/DeleteInstallJars.java similarity index 80% rename from src/com/quollwriter/tools/DeleteInstallJars.java rename to src/main/java/com/quollwriter/tools/DeleteInstallJars.java index e2e042ed..7458e5a7 100644 --- a/src/com/quollwriter/tools/DeleteInstallJars.java +++ b/src/main/java/com/quollwriter/tools/DeleteInstallJars.java @@ -25,54 +25,54 @@ public static void main (String[] argv) if (!userDir.endsWith ("jars")) { - + userDir += "/jars"; - + } - + if (!new File (userDir).exists ()) { - + return; } - userDirF = new File (userDir).getCanonicalFile (); - + userDirF = new File (userDir).getCanonicalFile (); + Thread.sleep (1000); File newDir = new File (userDirF + "/.new"); - + if (!newDir.exists ()) { - + return; - + } - List files = new ArrayList (); - + List files = new ArrayList<> (); + File toDelete = new File (newDir + "/to-delete.txt"); - + if ((toDelete.exists ()) && (toDelete.isFile ()) ) { - + // Get the file, each line indicates a jar file name to delete. BufferedReader bin = new BufferedReader (new FileReader (toDelete)); String line = null; - + while ((line = bin.readLine ()) != null) { - + if (line.endsWith (".jar")) { - + File toDel = new File (userDirF + "/" + line).getCanonicalFile (); - + if ((!toDel.exists ()) || (!toDel.getPath ().startsWith (userDirF.getPath ())) @@ -86,59 +86,59 @@ public static void main (String[] argv) files.add (toDel); } - + } bin.close (); files.add (toDelete); - + deleteFiles (files); - + } - + tryCount = 0; File jarsDir = new File (userDir); - files = new ArrayList (); - + files = new ArrayList<> (); + // Move any jar files from .new to the main dir. - + wlog.println ("New dir: " + newDir); if (newDir.exists ()) { - + File[] newFiles = newDir.listFiles (); - + if (newFiles != null) { - + for (int i = 0; i < newFiles.length; i++) { - + File f = newFiles[i]; - + if (!f.getName ().endsWith (".jar")) { - + continue; - + } wlog.println ("Adding file: " + f); files.add (f); - + } - + } moveFiles (files, jarsDir); - + newDir.deleteOnExit (); - + } - wlog.close (); + wlog.close (); } catch (Exception e) { @@ -154,8 +154,8 @@ private static void moveFiles (List files, PrintWriter wlog = new PrintWriter (new FileWriter ("d:/development/quollwriter/main/upgrade.log", true), true); - List toMove = new ArrayList (); - + List toMove = new ArrayList<> (); + for (File f : files) { wlog.println ("File: " + f); @@ -163,21 +163,21 @@ private static void moveFiles (List files, wlog.println ("New file: " + nFile); if (nFile.exists ()) { - + // Try deleting it first. nFile.delete (); - + } - + if (!f.renameTo (nFile)) { wlog.println ("Cant rename: " + nFile); toMove.add (f); - + } - + } - + if ((toMove.size () > 0) && (tryCount < 5) @@ -185,28 +185,28 @@ private static void moveFiles (List files, { tryCount++; - + try { - + Thread.sleep (1000); - + } catch (Exception e) { - - + + } - + moveFiles (toMove, jarsDir); - + } - + } - + private static void deleteFiles (List files) throws Exception { - List toDelete = new ArrayList (); + List toDelete = new ArrayList<> (); for (File f : files) { diff --git a/src/com/quollwriter/tools/GetPromptAuthors.java b/src/main/java/com/quollwriter/tools/GetPromptAuthors.java similarity index 81% rename from src/com/quollwriter/tools/GetPromptAuthors.java rename to src/main/java/com/quollwriter/tools/GetPromptAuthors.java index fee86661..67f31dd0 100644 --- a/src/com/quollwriter/tools/GetPromptAuthors.java +++ b/src/main/java/com/quollwriter/tools/GetPromptAuthors.java @@ -4,13 +4,11 @@ import java.util.*; -import com.gentlyweb.xml.*; - import com.quollwriter.*; import com.quollwriter.data.*; -import org.jdom.*; +import org.dom4j.*; public class GetPromptAuthors @@ -21,8 +19,8 @@ public static void main (String[] argv) File promptsDir = new File (argv[0]); - List authors = new ArrayList (); - Map seen = new HashMap (); + List authors = new ArrayList<> (); + Map seen = new HashMap<> (); try { @@ -37,8 +35,7 @@ public static void main (String[] argv) try { - root = JDOMUtils.getFileAsElement (files[i], - ".zip"); + root = DOM4JUtils.fileAsElement (files[i]); } catch (Exception e) { diff --git a/src/com/quollwriter/tools/UpgradeQuollWriter.java b/src/main/java/com/quollwriter/tools/UpgradeQuollWriter.java similarity index 77% rename from src/com/quollwriter/tools/UpgradeQuollWriter.java rename to src/main/java/com/quollwriter/tools/UpgradeQuollWriter.java index 18539e7d..38156188 100644 --- a/src/com/quollwriter/tools/UpgradeQuollWriter.java +++ b/src/main/java/com/quollwriter/tools/UpgradeQuollWriter.java @@ -24,54 +24,54 @@ public static void main (String[] argv) if (!userDir.endsWith ("jars")) { - + userDir += "/jars"; - + } - + if (!new File (userDir).exists ()) { - + return; } - userDirF = new File (userDir).getCanonicalFile (); - + userDirF = new File (userDir).getCanonicalFile (); + Thread.sleep (1000); File newDir = new File (userDirF + "/.new"); - + if (!newDir.exists ()) { - + return; - + } - List files = new ArrayList (); - + List files = new ArrayList<> (); + File toDelete = new File (newDir + "/to-delete.txt"); - + if ((toDelete.exists ()) && (toDelete.isFile ()) ) { - + // Get the file, each line indicates a jar file name to delete. BufferedReader bin = new BufferedReader (new FileReader (toDelete)); String line = null; - + while ((line = bin.readLine ()) != null) { - + if (line.endsWith (".jar")) { - + File toDel = new File (userDirF + "/" + line).getCanonicalFile (); - + if ((!toDel.exists ()) || (!toDel.getPath ().startsWith (userDirF.getPath ())) @@ -85,57 +85,57 @@ public static void main (String[] argv) files.add (toDel); } - + } bin.close (); files.add (toDelete); - + deleteFiles (files); - + } - + tryCount = 0; File jarsDir = new File (userDir); - files = new ArrayList (); - - // Move any jar files from .new to the main dir. + files = new ArrayList<> (); + + // Move any jar files from .new to the main dir. if (newDir.exists ()) { - + File[] newFiles = newDir.listFiles (); - + if (newFiles != null) { - + for (int i = 0; i < newFiles.length; i++) { - + File f = newFiles[i]; - + if (!f.getName ().endsWith (".jar")) { - + continue; - + } - + files.add (f); - + } - + } moveFiles (files, jarsDir); - + newDir.deleteOnExit (); - + } - + } catch (Exception e) { @@ -149,8 +149,8 @@ private static void moveFiles (List files, File jarsDir) throws Exception { - List toMove = new ArrayList (); - + List toMove = new ArrayList<> (); + for (File f : files) { @@ -158,21 +158,21 @@ private static void moveFiles (List files, if (nFile.exists ()) { - + // Try deleting it first. nFile.delete (); - + } - + if (!f.renameTo (nFile)) { - + toMove.add (f); - + } - + } - + if ((toMove.size () > 0) && (tryCount < 5) @@ -180,28 +180,28 @@ private static void moveFiles (List files, { tryCount++; - + try { - + Thread.sleep (1000); - + } catch (Exception e) { - - + + } - + moveFiles (toMove, jarsDir); - + } - + } - + private static void deleteFiles (List files) throws Exception { - List toDelete = new ArrayList (); + List toDelete = new ArrayList<> (); for (File f : files) { diff --git a/src/main/java/com/quollwriter/ui/AbstractLanguageStringsEditor.java b/src/main/java/com/quollwriter/ui/AbstractLanguageStringsEditor.java new file mode 100644 index 00000000..6b2baf00 --- /dev/null +++ b/src/main/java/com/quollwriter/ui/AbstractLanguageStringsEditor.java @@ -0,0 +1,2767 @@ +package com.quollwriter.ui; + +import java.awt.*; +import java.io.*; +import java.awt.datatransfer.*; +import java.awt.event.*; +import java.util.*; +import java.util.concurrent.*; +import java.text.*; +import java.net.*; + +import javax.swing.*; +import javax.swing.border.*; +import javax.swing.text.*; +import javax.swing.event.*; +import javax.swing.filechooser.*; +import javax.swing.plaf.LayerUI; +import javax.swing.tree.*; + +import com.gentlyweb.properties.*; + +import org.josql.*; + +import com.jgoodies.forms.builder.*; +import com.jgoodies.forms.factories.*; +import com.jgoodies.forms.layout.*; + +import com.quollwriter.*; +import com.quollwriter.events.*; +import com.quollwriter.data.*; +import com.quollwriter.ui.events.*; +import com.quollwriter.data.comparators.*; +import com.quollwriter.data.editors.*; +import com.quollwriter.editors.*; +import com.quollwriter.ui.components.*; +import com.quollwriter.ui.panels.*; +import com.quollwriter.text.*; +import com.quollwriter.db.*; +import com.quollwriter.ui.sidebars.*; +import com.quollwriter.editors.*; +import com.quollwriter.editors.ui.*; +import com.quollwriter.editors.ui.sidebars.*; +import com.quollwriter.achievements.ui.*; +import com.quollwriter.ui.charts.*; +import com.quollwriter.ui.actionHandlers.*; +import com.quollwriter.ui.forms.*; +import com.quollwriter.ui.components.ScrollableBox; +import com.quollwriter.ui.components.SpellChecker; +import com.quollwriter.uistrings.*; + +import static com.quollwriter.LanguageStrings.*; +import static com.quollwriter.Environment.getUIString; + +public abstract class AbstractLanguageStringsEditor extends AbstractViewer implements RefValueProvider +{ + + public static final int DEFAULT_WINDOW_WIDTH = 800; + public static final int DEFAULT_WINDOW_HEIGHT = 500; + public static final int PROJECT_BOX_WIDTH = 250; + + public static final String MAIN_CARD = "main"; + public static final String OPTIONS_CARD = "options"; + + public static final String SUBMIT_HEADER_CONTROL_ID = "submit"; + public static final String USE_HEADER_CONTROL_ID = "use"; + public static final String HELP_HEADER_CONTROL_ID = "help"; + public static final String FIND_HEADER_CONTROL_ID = "find"; + + public static int INTERNAL_SPLIT_PANE_DIVIDER_WIDTH = 2; + + private JSplitPane splitPane = null; + private Header title = null; + private Box notifications = null; + private Box sideBar = null; + private Box sideBarWrapper = null; + private Box toolbarPanel = null; + private AbstractSideBar currentSideBar = null; + private AccordionItemsSideBar mainSideBar = null; + private Finder finder = null; + private Map sideBars = new HashMap (); + private Stack activeSideBars = new Stack (); + private java.util.List sideBarListeners = new ArrayList (); + private java.util.List mainPanelListeners = new ArrayList (); + private JPanel cards = null; + private CardLayout cardsLayout = null; + private JLabel importError = null; + private JLabel forwardLabel = null; + private ImportTransferHandlerOverlay importOverlay = null; + protected Map panels = new HashMap<> (); + private String currentCard = null; + ///private Finder finder = null; + protected U userStrings = null; + private String toolbarLocation = null; + private Map sectionTrees = new LinkedHashMap<> (); + protected B baseStrings = null; + protected Filter nodeFilter = null; + private Map> valuesCache = new HashMap<> (); + private Map errCounts = new HashMap<> (); + private Map userCounts = new HashMap<> (); + private boolean inited = false; + private TreeCellRenderer treeCellRenderer = null; + private boolean updatingPreviews = false; + + public AbstractLanguageStringsEditor (U userStrings) + { + + this.userStrings = userStrings; + + this.baseStrings = (B) this.userStrings.getDerivedFrom (); + + } + + public AbstractLanguageStringsEditor (U userStrings, + B baseStrings) + { + + this.userStrings = userStrings; + this.baseStrings = baseStrings; + + } + + public abstract void tryOut (); + + public abstract void save () + throws Exception; + + public abstract void submit (ActionListener onSuccess, + ActionListener onFailure); + + public abstract void delete () + throws Exception; + + public abstract void onForwardLabelClicked () + throws Exception; + + public abstract void showReportProblemForId (String id); + + public void showForwardLabel (String text) + { + + this.forwardLabel.setText (text); + this.forwardLabel.setVisible (true); + + } + + public TreeCellRenderer getTreeCellRenderer () + { + + return this.treeCellRenderer; + + } + + public int getErrorCount (Node n) + { + + int c = 0; + + // Get the card. + Number num = this.errCounts.get (n); + + if (num != null) + { + + return num.intValue (); + + } + + LanguageStringsIdsPanel panel = this.panels.get (BaseStrings.toId (n.getId ())); + + if (panel != null) + { + + c = panel.getErrorCount (); + + } else { + + for (Value nv : this.valuesCache.get (n)) + { + + Value uv = this.userStrings.getValue (nv.getId (), + true); + + if (uv instanceof TextValue) + { + + TextValue _nv = this.baseStrings.getTextValue (uv.getId ()); + + if (nv == null) + { + + // The string is present in the user strings but not the base! + Environment.logError ("Found string: " + uv.getId () + " present in user strings but not base."); + + continue; + + } + + if (BaseStrings.getErrors (((TextValue) uv).getRawText (), + BaseStrings.toId (nv.getId ()), + _nv.getSCount (), + this).size () > 0) + { + + c++; + + }; + + } + + } + + } + + this.errCounts.put (n, + c); + + return c; + + } + + private int getUserValueCount (Node n) + { + + int c = 0; + + Number num = this.userCounts.get (n); + + if (num != null) + { + + return num.intValue (); + + } + + LanguageStringsIdsPanel panel = this.panels.get (BaseStrings.toId (n.getId ())); + + if (panel != null) + { + + c = panel.getUserValueCount (); + + } else { + + for (Value nv : this.valuesCache.get (n)) + { + + Value uv = this.userStrings.getValue (nv.getId (), + true); + + if (uv != null) + { + + c++; + + } + + } + + } + + this.userCounts.put (n, + c); + + return c; + + } + + public void setNodeFilter (Filter filter) + { + + this.nodeFilter = filter; + + this.initSideBar (); + + } + + private void initSideBar () + { + + if (this.baseStrings == null) + { + + throw new IllegalStateException ("No base strings set."); + + } + + String defSection = "General"; + + Map> sections = this.baseStrings.getNodesInSections (defSection); + + java.util.List items = new ArrayList<> (); + + this.valuesCache = new HashMap<> (); + + for (Section sect : (Set
    ) this.baseStrings.getSections ()) + { + + AccordionItem it = this.createSectionTree (sect.name, + sect.icon, + sections.get (sect.id)); + + if (it == null) + { + + continue; + + } + + items.add (it); + + } + + this.mainSideBar.setItems (items); + + } + + public void showAllStrings () + { + + try + { + + this.save (); + + } catch (Exception e) { + + Environment.logError ("Unable to save", + e); + + UIUtils.showErrorMessage (this, + "Unable to update view."); + + return; + + } + + // Clear out the panel cache. + this.panels = new HashMap<> (); + + this.currentCard = null; + this.cards.removeAll (); + + this.nodeFilter = null; + this.initSideBar (); + + this.validate (); + this.repaint (); + + } + +/* + public void showChanges (LanguageStrings newls) + { + + Version v = this.userStrings.getQuollWriterVersion (); + + try + { + + Environment.saveUserUILanguageStrings (newls); + + this.userStrings.setQuollWriterVersion (newls.getQuollWriterVersion ()); + + Environment.saveUserUILanguageStrings (this.userStrings); + + this.userStrings.setQuollWriterVersion (v); + + LanguageStrings uls = Environment.getUserUILanguageStrings (newls.getQuollWriterVersion (), + this.userStrings.getId ()); + + // Get a diff of the default to this new. + LanguageStringsEditor lse = Environment.editUILanguageStrings (uls, + newls.getQuollWriterVersion ()); + lse.limitViewToPreviousVersionDiff (); + + } catch (Exception e) { + + Environment.logError ("Unable to show strings editor for: " + + newls, + e); + + UIUtils.showErrorMessage (this, + "Unable to show strings."); + + } + + } +*/ +/* + public void limitViewToPreviousVersionDiff () + throws Exception + { + + try + { + + this.save (); + + } catch (Exception e) { + + Environment.logError ("Unable to save", + e); + + UIUtils.showErrorMessage (this, + "Unable to update view."); + + return; + + } + + final LanguageStrings basels = this.baseStrings; + + // Get the previous version (which will be the current QW version). + final LanguageStrings prevbasels = Environment.getUserUIEnglishLanguageStrings (Environment.getQuollWriterVersion ()); + + if (prevbasels == null) + { + + // No strings. + return; + + } + + this.nodeFilter = new LanguageStrings.Filter () + { + + @Override + public boolean accept (LanguageStrings.Node n) + { + + LanguageStrings.Node pn = prevbasels.getNode (n.getId ()); + + // Does the node exist in the current base strings but not the previous? + if (pn == null) + { + + // This is a new node. + return true; + + } + + // It exists, but has it changed? + if ((n instanceof LanguageStrings.Value) + && + (!(pn instanceof LanguageStrings.Value)) + ) + { + + // Node type changed. + return true; + + } + + if ((pn instanceof LanguageStrings.Value) + && + (!(n instanceof LanguageStrings.Value)) + ) + { + + // Node type changed. + return true; + + } + + if ((pn instanceof LanguageStrings.TextValue) + && + (n instanceof LanguageStrings.TextValue) + ) + { + + LanguageStrings.TextValue pnv = (LanguageStrings.TextValue) pn; + LanguageStrings.TextValue nv = (LanguageStrings.TextValue) n; + + // Value changed? + if (pnv.getRawText ().equals (nv.getRawText ())) + { + + return false; + + } + + } + + return true; + + } + + }; + + this.initSideBar (); + + // Clear out the panel cache. + this.panels = new HashMap<> (); + + this.currentCard = null; + this.cards.removeAll (); + + this.validate (); + this.repaint (); + + } +*/ + public void updateSideBar (final Node n) + { + + final AbstractLanguageStringsEditor _this = this; + + this.errCounts.remove (n); + this.userCounts.remove (n); + + UIUtils.doLater (new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + for (JTree t : _this.sectionTrees.values ()) + { + + // See how many children there are. + TreePath tp = UIUtils.getTreePathForUserObject ((DefaultMutableTreeNode) t.getModel ().getRoot (), + n); + + if (tp != null) + { + + ((DefaultTreeModel) t.getModel ()).nodeChanged ((DefaultMutableTreeNode) tp.getLastPathComponent ()); + + t.validate (); + t.repaint (); + + break; + + } + + } + + _this.sideBar.validate (); + _this.sideBar.repaint (); + + } + + }); + + } +/* + private void updateSideBar () + { + + this.sideBar.validate (); + this.sideBar.repaint (); + + } +*/ + private void fireMainPanelShownEvent (QuollPanel p) + { + + MainPanelEvent ev = new MainPanelEvent (this, + p); + + for (MainPanelListener l : this.mainPanelListeners) + { + + l.panelShown (ev); + + } + + } + + public void removeMainPanelListener (MainPanelListener l) + { + + this.mainPanelListeners.remove (l); + + } + + public void addMainPanelListener (MainPanelListener l) + { + + this.mainPanelListeners.add (l); + + } + + public String getPreviewText (String t) + { + + return BaseStrings.buildText (t, + this); + + } + + public void updatePreviews () + { + + // XXX TODO + if (true) + { + + return; + + } + + final AbstractLanguageStringsEditor _this = this; + + UIUtils.doLater (new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + if (_this.updatingPreviews) + { + + return; + + } + + try + { + + _this.updatingPreviews = true; + + for (LanguageStringsIdsPanel p : _this.panels.values ()) + { + + p.updatePreviews (); + + } + + } catch (Exception e) { + + Environment.logError ("Unable to update previews.", + e); + + } finally { + + _this.updatingPreviews = false; + + } + + } + + }); + + } + + @Override + public String getString (String id) + { + + java.util.List idparts = BaseStrings.getIdParts (id); + + // See if we have a panel. + if (idparts.size () > 0) + { + + for (LanguageStringsIdsPanel p : this.panels.values ()) + { + + String t = p.getIdValue (id); + + if (t != null) + { + + return this.getPreviewText (t); + + } + + } + + } + + return this.userStrings.getString (id); + + } + + @Override + public int getSCount (String id) + { + + return this.baseStrings.getSCount (id); + + } + + @Override + public String getRawText (String id) + { + + for (LanguageStringsIdsPanel p : this.panels.values ()) + { + + String t = p.getIdValue (id); + + if (t != null) + { + + return t; + + } + + } + + return this.userStrings.getRawText (id); + + } + + public void setToolbarLocation (String loc) + { + + if (loc == null) + { + + loc = Constants.BOTTOM; + + } +/* + if (loc.equals (Constants.TOP)) + { + + this.toolbarPanel.setBorder (new CompoundBorder (new MatteBorder (0, 0, 1, 0, UIUtils.getBorderColor ()), + new EmptyBorder (0, + 0, + 0, + 0))); + + this.sideBar.add (this.toolbarPanel, + 0); + + } else + { + + this.toolbarPanel.setBorder (new CompoundBorder (new MatteBorder (1, 0, 0, 0, UIUtils.getBorderColor ()), + new EmptyBorder (0, + 0, + 0, + 0))); + + this.sideBar.add (this.toolbarPanel); + + } +*/ + this.toolbarLocation = loc; + + } + + private AccordionItem createSectionTree (String title, + String iconType, + Set sections) + { + + final AbstractLanguageStringsEditor _this = this; + + final JTree tree = this.createStringsTree (sections); + + if (tree == null) + { + + return null; + + } + + tree.setCellRenderer (this.treeCellRenderer); + + tree.addMouseListener (new MouseEventHandler () + { + + @Override + public void handlePress (MouseEvent ev) + { + + TreePath tp = tree.getPathForLocation (ev.getX (), + ev.getY ()); + + if (tp != null) + { + + DefaultMutableTreeNode n = (DefaultMutableTreeNode) tp.getLastPathComponent (); + + Node node = (Node) n.getUserObject (); + + String id = BaseStrings.toId (node.getId ()); + + _this.showIds (id); + + } + + } + + }); + + AccordionItem acc = new AccordionItem (title, + iconType) + { + + @Override + public JComponent getContent () + { + + return tree; + + } + + }; + + this.sectionTrees.put (title, + tree); + + return acc; + + } + + public void showIds (String idPrefix) + { + + this.showIds (idPrefix, + null); + + } + + public void showIds (String idPrefix, + ActionListener onShow) + { + + if (!this.valuesCache.containsKey (this.baseStrings.getNode (idPrefix))) + { + + return; + + } + + //String id = node.getNodeId (); + LanguageStringsIdsPanel p = this.panels.get (idPrefix); + + if (p == null) + { + + p = this.createIdsPanel (idPrefix); + + try + { + + p.init (); + + } catch (Exception e) { + + Environment.logError ("Unable to show ids for id: " + + idPrefix, + e); + + UIUtils.showErrorMessage (this, + "Unable to show panel."); + + return; + + } + + this.panels.put (idPrefix, + p); + + this.cards.add (p, idPrefix); + + } + + this.showCard (idPrefix); + + this.fireMainPanelShownEvent (p); + + if (onShow != null) + { + + UIUtils.doLater (onShow); + + } + + } + + public void showId (final String id) + { + + final AbstractLanguageStringsEditor _this = this; + + String idPrefix = null; + + // Get the relevant prefix. + for (JTree t : this.sectionTrees.values ()) + { + + Enumeration en = ((DefaultMutableTreeNode) t.getModel ().getRoot ()).children (); + + while (en.hasMoreElements ()) + { + + DefaultMutableTreeNode node = (DefaultMutableTreeNode) en.nextElement (); + + Node n = (Node) node.getUserObject (); + + if (id.startsWith (BaseStrings.toId (n.getId ()))) + { + + idPrefix = BaseStrings.toId (n.getId ()); + + break; + + } + + } + + if (idPrefix != null) + { + + break; + + } + + } + + if (idPrefix == null) + { + + return; + + } + + this.showIds (idPrefix, + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + _this.scrollToNode (id); + + } + + }); + + } + + public void scrollToNode (String n) + { + + LanguageStringsIdsPanel c = this.panels.get (this.currentCard); + + c.scrollToNode (n); + + } + + public void setIdSelectedInSidebar (String id) + { + + for (JTree t : this.sectionTrees.values ()) + { + + t.clearSelection (); + + // See how many children there are. + TreePath tp = UIUtils.getTreePathForUserObject ((DefaultMutableTreeNode) t.getModel ().getRoot (), + this.baseStrings.createNode (id)); + + if (tp != null) + { + + t.setSelectionPath (tp); + + } + + } + + } + + private JTree createStringsTree (Set sections) + { + + final AbstractLanguageStringsEditor _this = this; + + DefaultMutableTreeNode root = new DefaultMutableTreeNode ("_strings"); + + for (Node k : sections) + { + + // Find all the top level nodes. + Set tlNodes = k.getTopLevelNodes (); + + Set vals = null; + + Node n = null; + + if ((tlNodes != null) + && + (tlNodes.size () > 0) + ) + { + + // Get the nodes, pass through the filter as well. + vals = new LinkedHashSet<> (); + + for (String tln : tlNodes) + { + + Node x = k.getChild (BaseStrings.getIdParts (tln)); + + if (x != null) + { + + if (this.nodeFilter != null) + { + + if (this.nodeFilter.accept (x)) + { + + n = x; + + } + + } else { + + n = x; + + } + + } + + vals = n.getValues (this.nodeFilter); + + if (vals.size () == 0) + { + + continue; + + } + + this.valuesCache.put (n, vals); + + root.add (new DefaultMutableTreeNode (n)); + + } + + continue; + + } + + vals = k.getValues (this.nodeFilter); + + if (vals.size () == 0) + { + + continue; + + } + + this.valuesCache.put (k, vals); + + root.add (new DefaultMutableTreeNode (k)); + + } + + if (root.getChildCount () == 0) + { + + // Filtered out everything. + return null; + + } + + final JTree tree = UIUtils.createTree (); + + DefaultTreeModel dtm = (DefaultTreeModel) tree.getModel (); + + dtm.setRoot (root); + + return tree; + + } + + public void showMainCard () + { + + this.showCard (MAIN_CARD); + + } + + public void showCard (String name) + { + + this.cardsLayout.show (this.cards, + name); + + this.currentCard = name; + + this.updateToolbarForPanel (this.panels.get (this.currentCard)); + + this.validate (); + this.repaint (); + + } + + @Override + public void showPopupAt (Component popup, + Component showAt, + boolean hideOnParentClick) + { + + Point po = SwingUtilities.convertPoint (showAt, + 0, + 0, + this.getContentPane ()); + + this.showPopupAt (popup, + po, + hideOnParentClick); + + + } + + @Override + public void showPopupAt (Component c, + Point p, + boolean hideOnParentClick) + { + + Insets ins = this.getInsets (); + + if ((c.getParent () == null) + && + (c.getParent () != this.getLayeredPane ()) + ) + { + + this.addPopup (c, + hideOnParentClick, + false); + + } + + Dimension cp = c.getPreferredSize (); + + if ((p.y + cp.height) > (this.getBounds ().height - ins.top - ins.bottom)) + { + + p = new Point (p.x, + p.y); + + // See if the child is changing height. + if (c.getBounds ().height != cp.height) + { + + p.y = p.y - (cp.height - c.getBounds ().height); + + } else { + + p.y = p.y - cp.height; + + } + + } + + if (p.y < 0) + { + + p = new Point (p.x, + p.y); + + p.y = 10; + + } + + if ((p.x + cp.width) > (this.getBounds ().width - ins.left - ins.right)) + { + + p = new Point (p.x, + p.y); + + p.x = p.x - cp.width; + + } + + if (p.x < 0) + { + + p = new Point (p.x, + p.y); + + p.x = 10; + + } + + c.setBounds (p.x, + p.y, + c.getPreferredSize ().width, + c.getPreferredSize ().height); + + c.setVisible (true); + this.validate (); + this.repaint (); + + } + + public void addPopup (Component c) + { + + this.addPopup (c, + false, + false); + + } + + @Override + public void addPopup (Component c, + boolean hideOnClick, + boolean hideViaVisibility) + { + + this.getLayeredPane ().add (c, + JLayeredPane.POPUP_LAYER); + + this.getLayeredPane ().moveToFront (c); + + } + + @Override + public void removePopup (Component c) + { + + this.getLayeredPane ().remove (c); + + this.getLayeredPane ().validate (); + + this.getLayeredPane ().repaint (); + + } + + protected void setBaseStrings (B ls) + { + + this.baseStrings = ls; + + if (this.inited) + { + + this.initSideBar (); + + } + + } + + @Override + public void init () + throws Exception + { + + if (this.inited) + { + + return; + + } + + this.inited = true; + + super.init (); + + final AbstractLanguageStringsEditor _this = this; + + this.treeCellRenderer = new DefaultTreeCellRenderer () + { + + public Component getTreeCellRendererComponent (JTree tree, + Object value, + boolean sel, + boolean expanded, + boolean leaf, + int row, + boolean hasFocus) + { + + super.getTreeCellRendererComponent (tree, + value, + sel, + expanded, + leaf, + row, + hasFocus); + + DefaultMutableTreeNode tn = (DefaultMutableTreeNode) value; + + if (tn.getUserObject () instanceof String) + { + + return this; + + } + + this.setIcon (null); + + Node n = (Node) tn.getUserObject (); + + final java.util.List id = n.getId (); + + int c = _this.getUserValueCount (n); + int alls = 0; + int errCount = _this.getErrorCount (n); + + Set vals = _this.valuesCache.get (n); + + if (vals != null) + { + + alls = vals.size (); + + } + + String title = (n.getTitle () != null ? n.getTitle () : n.getNodeId ()); + + String name = null; + + if (errCount > 0) + { + + name = String.format ("%s (%s/%s) [%s errors]", + title, + Environment.formatNumber (c), + Environment.formatNumber (alls), + Environment.formatNumber (errCount)); + + this.setIcon (Environment.getIcon (Constants.ERROR_ICON_NAME, + Constants.ICON_SIDEBAR)); + + } else { + + name = String.format ("%s (%s/%s)", + title, + Environment.formatNumber (c), + Environment.formatNumber (alls)); + + if (alls == c) + { + + this.setIcon (Environment.getIcon (Constants.SAVE_ICON_NAME, + Constants.ICON_SIDEBAR)); + + } else { + + if (c > 0) + { + + this.setIcon (Environment.getIcon (Constants.NEXT_ICON_NAME, + Constants.ICON_SIDEBAR)); + + } + + } + + } + + this.setText ("" + name + ""); + + this.setBorder (new EmptyBorder (2, 2, 2, 2)); + + return this; + + } + + }; + + // Create a split pane. + this.splitPane = new JSplitPane (JSplitPane.HORIZONTAL_SPLIT, + false); + this.splitPane.setDividerSize (UIUtils.getSplitPaneDividerSize ()); + this.splitPane.setBorder (null); + + javax.swing.plaf.basic.BasicSplitPaneDivider div = ((javax.swing.plaf.basic.BasicSplitPaneUI) this.splitPane.getUI ()).getDivider (); + div.setBorder (new MatteBorder (0, 0, 0, 1, UIUtils.getBorderColor ())); + this.splitPane.setOpaque (false); + this.splitPane.setBackground (UIUtils.getComponentColor ()); + + this.cardsLayout = new CardLayout (0, 0); + + this.cards = new JPanel (this.cardsLayout); + this.cards.setBackground (UIUtils.getComponentColor ()); + + this.splitPane.setRightComponent (this.cards); + + this.userStrings = userStrings; + + this.forwardLabel = UIUtils.createClickableLabel ("", + Environment.getIcon (Constants.INFO_ICON_NAME, + Constants.ICON_CLICKABLE_LABEL)); + this.forwardLabel.setBorder (UIUtils.createBottomLineWithPadding (5, 5, 5, 5)); + this.forwardLabel.setVisible (false); + + UIUtils.makeClickable (this.forwardLabel, + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + try + { + + _this.onForwardLabelClicked (); + + } catch (Exception e) { + + Environment.logError ("Unable to update view", + e); + + UIUtils.showErrorMessage (_this, + "Unable to update view."); + + } + + } + + }); + + // Create the sidebar. + this.mainSideBar = new AccordionItemsSideBar (this, + null)//items) + { + + @Override + public String getId () + { + + return "main"; + + } + + @Override + public JComponent getContent () + { + + Box b = new Box (BoxLayout.Y_AXIS); + + b.add (_this.forwardLabel); + + //_this.forwardLabel.setVisible (Environment.getQuollWriterVersion ().isNewer (_this.userStrings.getQuollWriterVersion ())); + + b.add (super.getContent ()); + + b.setBorder (UIUtils.createPadding (0, 0, 0, 0)); + + b.setPreferredSize (new Dimension (200, Short.MAX_VALUE)); + + return b; + + } + + @Override + public Dimension getMinimumSize () + { + + return new Dimension (250, + 250); + } + + @Override + public void panelShown (MainPanelEvent ev) + { + + _this.setIdSelectedInSidebar (ev.getPanel ().getPanelId ()); + + } + + }; + + this.addSideBar (this.mainSideBar); + + this.finder = new Finder (this) + { + + @Override + public String getTitle () + { + + return "Find"; + + } + + @Override + public Set search (String t) + { + + Set res = new LinkedHashSet<> (); + + Map sects = new HashMap<> (); + + for (Section sect : (Set
    ) _this.baseStrings.getSections ()) + { + + sects.put (sect.id, + sect); + + } + + Set results = _this.baseStrings.find (t); + + Set uresults = _this.userStrings.find (t); + + for (Value v : uresults) + { + + results.add (_this.baseStrings.getValue (v.getId ())); + + } + + Map>> vals = new HashMap<> (); + + for (Value v : results) + { + + Node r = v.getRoot (); + + Section s = sects.get (r.getSection ()); + + Map> svs = vals.get (s); + + if (svs == null) + { + + svs = new LinkedHashMap<> (); + + vals.put (s, + svs); + + } + + Set tlns = r.getTopLevelNodes (); + + if (tlns != null) + { + + for (String tln : tlns) + { + + String tlnid = r.getNodeId () + "." + tln; + + Node tlnn = _this.baseStrings.getNode (tlnid); + + if (BaseStrings.toId (v.getId ()).startsWith (tlnid)) + { + + java.util.List l = svs.get (tlnn); + + if (l == null) + { + + l = new ArrayList<> (); + + svs.put (tlnn, + l); + + } + + l.add (v); + + } + + } + + } else { + + java.util.List l = svs.get (r); + + if (l == null) + { + + l = new ArrayList<> (); + + svs.put (r, + l); + + } + + l.add (v); + + } + + } + + for (Section sect : vals.keySet ()) + { + + final Map> vs = vals.get (sect); + + // Build the tree. + DefaultMutableTreeNode root = new DefaultMutableTreeNode ("_strings"); + + for (Node n : vs.keySet ()) + { + + DefaultMutableTreeNode tn = new DefaultMutableTreeNode (n); + + root.add (tn); + + for (Value v : vs.get (n)) + { + + tn.add (new DefaultMutableTreeNode (BaseStrings.toId (v.getId ()))); + + } + + } + + final JTree tree = UIUtils.createTree (); + + tree.setBorder (new EmptyBorder (0, 7, 0, 0)); + + DefaultTreeModel dtm = (DefaultTreeModel) tree.getModel (); + + dtm.setRoot (root); + + tree.setCellRenderer (new DefaultTreeCellRenderer () + { + + public Component getTreeCellRendererComponent (JTree tree, + Object value, + boolean sel, + boolean expanded, + boolean leaf, + int row, + boolean hasFocus) + { + + super.getTreeCellRendererComponent (tree, + value, + sel, + expanded, + leaf, + row, + hasFocus); + + DefaultMutableTreeNode tn = (DefaultMutableTreeNode) value; + + if (tn.getUserObject () instanceof String) + { + + this.setIcon (null); + + return this; + + } + + this.setIcon (null); + + DefaultMutableTreeNode pn = (DefaultMutableTreeNode) tn.getParent (); + + Node n = (Node) tn.getUserObject (); + + final java.util.List id = n.getId (); + + int c = tn.getChildCount (); + + String title = (n.getTitle () != null ? n.getTitle () : n.getNodeId ()); + + String name = null; + + name = String.format ("%s (%s)", + title, + Environment.formatNumber (c)); + + this.setText ("" + name + ""); + + this.setBorder (new EmptyBorder (2, 2, 2, 2)); + + return this; + + } + + }); + + tree.addMouseListener (new MouseEventHandler () + { + + @Override + public void handlePress (MouseEvent ev) + { + + TreePath tp = tree.getPathForLocation (ev.getX (), + ev.getY ()); + + if (tp != null) + { + + DefaultMutableTreeNode n = (DefaultMutableTreeNode) tp.getLastPathComponent (); + + Object o = n.getUserObject (); + + DefaultMutableTreeNode p = (DefaultMutableTreeNode) n.getParent (); + + Node pnode = (Node) p.getUserObject (); + + String id = BaseStrings.toId (pnode.getId ()); + + _this.showIds (id, + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + _this.scrollToNode (o.toString ()); + + } + + }); + + } + + } + + }); + + AccordionItem it = new AccordionItem (sect.name, + sect.icon) + { + + @Override + public JComponent getContent () + { + + return tree; + + } + + }; + + it.init (); + + res.add (it); + + } + + return res; + + } + + }; + + this.addSideBar (this.finder); + + if (this.baseStrings != null) + { + + this.initSideBar (); + + } + + //this.initSideBar (); +/* + this.finder = new Finder (this); + + this.addSideBar (this.finder); +*/ + this.currentSideBar = this.mainSideBar; + + this.addMainPanelListener (this.currentSideBar); + + this.currentSideBar.init (null); + + this.sideBarWrapper = new Box (BoxLayout.Y_AXIS); + this.toolbarPanel = new Box (BoxLayout.Y_AXIS); + this.sideBarWrapper.setAlignmentX (LEFT_ALIGNMENT); + this.toolbarPanel.setAlignmentX (LEFT_ALIGNMENT); + + this.sideBar = new Box (BoxLayout.Y_AXIS); + this.sideBar.add (this.sideBarWrapper); + this.sideBar.add (this.toolbarPanel); + + this.setToolbarLocation (null); + + this.toolbarPanel.setBorder (new CompoundBorder (new MatteBorder (1, 0, 0, 0, UIUtils.getBorderColor ()), + new EmptyBorder (0, + 5, + 0, + 5))); + + this.toolbarPanel.setMaximumSize (new Dimension (Short.MAX_VALUE, + this.toolbarPanel.getPreferredSize ().height)); + + this.splitPane.setLeftComponent (this.sideBar); + + this.sideBarWrapper.add (this.currentSideBar); + + this.setContent (this.splitPane); + + this.importOverlay = new ImportTransferHandlerOverlay (); + + this.importOverlay.addMouseListener (new MouseEventHandler () + { + + public void handlePress (MouseEvent ev) + { + + _this.importOverlay.setVisible (false); + + _this.validate (); + _this.repaint (); + + } + + }); + + this.setTransferHandler (new ImportTransferHandler (new ActionListener () + { + + public void actionPerformed (ActionEvent ev) + { + + File f = (File) ev.getSource (); + + _this.importOverlay.setFile (f); + + _this.setGlassPane (_this.importOverlay); + + _this.importOverlay.setVisible (true); + _this.validate (); + _this.repaint (); + + } + + }, + new ActionListener () + { + + public void actionPerformed (ActionEvent ev) + { + + _this.importOverlay.setVisible (false); + _this.validate (); + _this.repaint (); + + File f = (File) ev.getSource (); + + } + + }, + new ActionListener () + { + + public void actionPerformed (ActionEvent ev) + { + + _this.importOverlay.setVisible (false); + _this.validate (); + _this.repaint (); + + } + + }, + new java.io.FileFilter () + { + + @Override + public boolean accept (File f) + { + + return f.getName ().endsWith (".json"); + + } + + })); + + this.setMinimumSize (new Dimension (500, 500)); + + int width = 0; + int height = 0; + + try + { + + width = UserProperties.getAsInt ("languagestringseditor-window-width"); + + height = UserProperties.getAsInt ("languagestringseditor-window-height"); + + } catch (Exception e) { + + // Ignore. + + } + + if (width < 1) + { + + width = DEFAULT_WINDOW_WIDTH; + + } + + if (height < 1) + { + + height = DEFAULT_WINDOW_HEIGHT; + + } + + this.splitPane.setPreferredSize (new Dimension (width, + height)); + + int scroll = 0; + + try + { + + scroll = UserProperties.getAsInt ("languagestringseditor-sidebar-scroll"); + + } catch (Exception e) { + + // Ignore. + + } + + if (scroll > 0) + { + + this.mainSideBar.scrollVerticalTo (scroll); + + } + + this.setTitleHeaderControlsVisible (true); + + this.showViewer (); + + String lastId = UserProperties.get ("languagestringseditor-stringsid-lasteditingid-" + this.userStrings.getId ()); + + if (lastId != null) + { + + this.showIds (lastId); + + } + + scroll = 0; + + try + { + + scroll = UserProperties.getAsInt ("languagestringseditor-stringsid-lasteditingscroll"); + + } catch (Exception e) { + + // Ignore. + + } + + if (scroll > 0) + { + + final int _scroll = scroll; + + UIUtils.doLater (new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + _this.panels.get (_this.currentCard).getScrollPane ().getVerticalScrollBar ().setValue (_scroll); + + } + + }); + + } + + } + + private void updateToolbarForPanel (QuollPanel qp) + { + + if (qp != null) + { + + this.toolbarPanel.removeAll (); + + JToolBar tb = qp.getToolBar (false); + + this.toolbarPanel.add (tb); + + this.toolbarPanel.setMaximumSize (new Dimension (Short.MAX_VALUE, + this.toolbarPanel.getPreferredSize ().height)); + + this.toolbarPanel.revalidate (); + this.toolbarPanel.repaint (); + + } + + } + + public void showSideBar (String name) + { + + if ((this.currentSideBar != null) + && + (this.currentSideBar.getName ().equals (name)) + ) + { + + return; + + } + + AbstractSideBar b = this.sideBars.get (name); + + if (b == null) + { + + throw new IllegalArgumentException ("Unable to show sidebar: " + + name + + ", no sidebar found with that name."); + + } + + if (this.currentSideBar != null) + { + + // Will be hiding this one. + this.currentSideBar.onHide (); + + } + + this.currentSideBar = b; + + this.sideBarWrapper.removeAll (); + + this.sideBarWrapper.add (this.currentSideBar); + + this.activeSideBars.remove (b); + + this.activeSideBars.push (b); + + this.currentSideBar.setVisible (true); + + this.validate (); + this.repaint (); + + this.setUILayout (); + + try + { + + b.onShow (); + + } catch (Exception e) { + + Environment.logError ("Unable to call onShow for sidebar: " + + name + + ", instance: " + + b, + e); + + } + + } + + public void setUILayout () + { + + if (true) + { + + return; + + } + + final AbstractLanguageStringsEditor _this = this; + + this.splitPane.setResizeWeight (1f); + + if (this.currentSideBar != null) + { + + this.splitPane.setDividerSize (INTERNAL_SPLIT_PANE_DIVIDER_WIDTH); + this.splitPane.setLeftComponent (this.currentSideBar); + + final Dimension min = this.currentSideBar.getMinimumSize (); + + int ww = this.splitPane.getSize ().width; + + int sbw = this.currentSideBar.getSize ().width; + + if (sbw == 0) + { + + sbw = min.width; + + } + + if (min.width > sbw) + { + + sbw = min.width; + + } + + int h = this.splitPane.getSize ().height; + + if (h == 0) + { + + h = 200; + + } + + int w = ww - sbw - INTERNAL_SPLIT_PANE_DIVIDER_WIDTH; + + this.splitPane.setDividerLocation (w); + + final int fw2 = w; + + UIUtils.doLater (new ActionListener () + { + + public void actionPerformed (ActionEvent ev) + { + + // For reasons best known to swing this has to be done separately otherwise when + // you exit full screen it will have the other sidebar as taking up all the space. + _this.splitPane.setDividerLocation (fw2); + + } + + }); + + } else { + + this.splitPane.setDividerSize (0); + this.splitPane.setRightComponent (this.createLayoutFiller ()); + + } + + } + + public void removeSideBarListener (SideBarListener l) + { + + this.sideBarListeners.remove (l); + + } + + public void addSideBarListener (SideBarListener l) + { + + this.sideBarListeners.add (l); + + } + + public void addSideBar (AbstractSideBar sb) + throws GeneralException + { + + if (sb == null) + { + + throw new IllegalArgumentException ("No sidebar provided."); + + } + + String id = sb.getId (); + + String state = null; + + if (id != null) + { + + state = UserProperties.get ("sidebarState-" + id); + + } + + sb.init (state); + + this.sideBars.put (id, + sb); + + } + + @Override + public void doSaveState () + { + + // Get the state from the sidebars. + for (AbstractSideBar sb : this.sideBars.values ()) + { + + String id = sb.getId (); + + if (id == null) + { + + continue; + + } + + UserProperties.set ("sidebarState-" + id, + sb.getSaveState ()); + + } + + } + + @Override + public boolean viewEditors () + throws GeneralException + { + + throw new UnsupportedOperationException ("Not supported."); + + } + + @Override + public void viewEditor (final EditorEditor ed) + throws GeneralException + { + + throw new UnsupportedOperationException ("Not supported."); + + } + + @Override + public boolean isEditorsVisible () + { + + return false; + + } + + @Override + public JComponent getTitleHeaderControl (String id) + { + + if (id == null) + { + + return null; + + } + + java.util.List prefix = Arrays.asList (allprojects,headercontrols,items); + + final AbstractLanguageStringsEditor _this = this; + + JComponent c = null; + + if (id.equals (FIND_HEADER_CONTROL_ID)) + { + + return UIUtils.createButton (Constants.FIND_ICON_NAME, + Constants.ICON_TITLE_ACTION, + "Find", + new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + _this.showFind (null); + + } + + }); + + } + + if (id.equals (SUBMIT_HEADER_CONTROL_ID)) + { + + c = UIUtils.createButton (Constants.UP_ICON_NAME, + Constants.ICON_TITLE_ACTION, + "Click to submit the strings", + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + _this.submit (null, + null); + + } + + }); + + } + + if (id.equals (USE_HEADER_CONTROL_ID)) + { + + c = UIUtils.createButton (Constants.PLAY_ICON_NAME, + Constants.ICON_TITLE_ACTION, + "Click to try out your strings", + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + _this.tryOut (); + + } + + }); + + } +/* + if (id.equals (HELP_HEADER_CONTROL_ID)) + { + + c = UIUtils.createButton (Constants.HELP_ICON_NAME, + Constants.ICON_TITLE_ACTION, + "Click to view the help about editing your strings", + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + UIUtils.openURL (_this, + "help://uilanguages/overview"); + + } + + }); + + } +*/ + if (c != null) + { + + return c; + + } + + return super.getTitleHeaderControl (id); + + } + + @Override + public String getViewerIcon () + { + + return Constants.EDIT_ICON_NAME; + + } + + public U getUserLanguageStrings () + { + + return this.userStrings; + + } + + @Override + public boolean viewStatistics () + throws GeneralException + { + + throw new UnsupportedOperationException ("Not supported."); + + } + + @Override + public boolean showChart (String chartType) + throws GeneralException + { + + throw new UnsupportedOperationException ("Not supported."); + + } + + @Override + public boolean showOptions (String section) + { + + throw new UnsupportedOperationException ("Not supported."); + + } + + @Override + public void showHelpText (String title, + String text, + String iconType, + String helpTextId) + { + + // TODO + + } + + @Override + public boolean viewAchievements () + { + + return true; + + } + + @Override + public void sendMessageToEditor (final EditorEditor ed) + throws GeneralException + { + + throw new UnsupportedOperationException ("Not supported."); + + } + + @Override + public boolean close (boolean noConfirm, + final ActionListener afterClose) + { + + try + { + + this.save (); + + } catch (Exception e) { + + Environment.logError ("Unable to save language strings: " + + this.userStrings, + e); + + UIUtils.showErrorMessage (this, + "Unable to save language strings."); + + return false; + + } + + this.setVisible (false); + + // Save state. + Map m = new LinkedHashMap (); + + UserProperties.set ("languagestringseditor-window-height", + this.splitPane.getSize ().height); + + UserProperties.set ("languagestringseditor-window-width", + this.splitPane.getSize ().width); + + if (this.currentCard != null) + { + + UserProperties.set ("languagestringseditor-stringsid-lasteditingid-" + this.userStrings.getId (), + this.currentCard); + + UserProperties.set ("languagestringseditor-stringsid-lasteditingscroll", + this.panels.get (this.currentCard).getScrollPane ().getVerticalScrollBar ().getValue ()); + + } + + UserProperties.set ("languagestringseditor-sidebar-scroll", + this.mainSideBar.getScrollPane ().getVerticalScrollBar ().getValue ()); + + // Close and remove all sidebars. + for (AbstractSideBar sb : new ArrayList (this.activeSideBars)) + { + + this.removeSideBar (sb); + + } + + super.close (true, + afterClose); + + return true; + + } + + public void removeSideBar (AbstractSideBar sb) + { + + if (sb == null) + { + + return; + + } + + try + { + + // Close the sidebar down gracefully. + sb.onHide (); + + sb.onClose (); + + } catch (Exception e) { + + Environment.logError ("Unable to close sidebar: " + sb.getName (), + e); + + } + + this.sideBars.remove (sb.getName ()); + + this.activeSideBars.remove (sb); + + this.removeSideBarListener (sb); + + AbstractSideBar _sb = (this.activeSideBars.size () > 0 ? this.activeSideBars.peek () : null); + + if (_sb != null) + { + + this.showSideBar (_sb.getName ()); + + } else { + + this.setUILayout (); + + } + + } + + @Override + public void closeSideBar () + { + + this.currentSideBar = null; + + this.showMainSideBar (); + + this.setUILayout (); + + } + + public void showMainSideBar () + { + + this.showSideBar (this.getMainSideBarId ()); + + } + + public String getMainSideBarId () + { + + return this.mainSideBar.getId (); + + } + + @Override + public AbstractSideBar getActiveOtherSideBar () + { + + return null; + + } + + @Override + public int getActiveSideBarCount () + { + + return this.activeSideBars.size (); + + } + + @Override + public JPopupMenu getShowOtherSideBarsPopupSelector () + { + + final AbstractLanguageStringsEditor _this = this; + + JPopupMenu m = new JPopupMenu (); + + // Means we are showing the main sidebar and the other sidebar. + // Exclude those from the list. + for (AbstractSideBar sb : this.activeSideBars) + { + + if ((this.currentSideBar != null) + && + (this.currentSideBar == sb) + ) + { + + continue; + + } + + final AbstractSideBar _sb = sb; + + JMenuItem mi = UIUtils.createMenuItem (sb.getActiveTitle (), + sb.getActiveIconType (), + new ActionListener () + { + + public void actionPerformed (ActionEvent ev) + { + + _this.showSideBar (_sb.getName ()); + + } + + }); + + m.add (mi); + + } + + return m; + + } + + private JComponent createLayoutFiller () + { + + Box l = new Box (BoxLayout.X_AXIS); + l.setMinimumSize (new Dimension (0, 0)); + l.setPreferredSize (new Dimension (0, 0)); + l.setVisible (false); + + return l; + + } + + @Override + public void handleHTMLPanelAction (String v) + { + + StringTokenizer t = new StringTokenizer (v, + ",;"); + + if (t.countTokens () > 1) + { + + while (t.hasMoreTokens ()) + { + + this.handleHTMLPanelAction (t.nextToken ().trim ()); + + } + + return; + + } + + try + { + + if (v.equals ("import")) + { + + //this.showImport (); + + } + + } catch (Exception e) { + + Environment.logError ("Unable to perform action: " + + v, + e); + + } + + super.handleHTMLPanelAction (v); + + } + + /** + * Display the targets for the project. + * + */ + public void viewTargets () + throws GeneralException + { + + throw new UnsupportedOperationException ("Not supported."); + + } + + @Override + public void initActionMappings (ActionMap am) + { + + super.initActionMappings (am); + + final AbstractLanguageStringsEditor _this = this; + + am.put ("show-main", + new ActionAdapter () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + _this.showMainCard (); + + } + + }); + + am.put (Constants.SHOW_FIND_ACTION, + new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + _this.showFind (null); + + } + + }); + + } + + public void showFind (String text) + { + + this.showSideBar ("find"); + + this.finder.setFindText (text); + + this.finder.onShow (); + + this.setUILayout (); + + } + + @Override + public void initKeyMappings (InputMap im) + { + + super.initKeyMappings (im); + + im.put (KeyStroke.getKeyStroke (KeyEvent.VK_ESCAPE, + 0), + "show-main"); + + im.put (KeyStroke.getKeyStroke (KeyEvent.VK_F1, + 0), + Constants.SHOW_FIND_ACTION); + + im.put (KeyStroke.getKeyStroke (KeyEvent.VK_F, + Event.CTRL_MASK), + Constants.SHOW_FIND_ACTION); + + im.put (KeyStroke.getKeyStroke (KeyEvent.VK_N, + Event.CTRL_MASK), + "new-project"); + im.put (KeyStroke.getKeyStroke (KeyEvent.VK_O, + Event.CTRL_MASK), + "open-project"); + + } + + private LanguageStringsIdsPanel createIdsPanel (String id) + { + + final AbstractLanguageStringsEditor _this = this; + + return new LanguageStringsIdsPanel (this, + this.baseStrings.getNode (id), + this.valuesCache.get (this.baseStrings.getNode (id))); + + } + +} diff --git a/src/main/java/com/quollwriter/ui/AbstractProjectViewer.java b/src/main/java/com/quollwriter/ui/AbstractProjectViewer.java new file mode 100644 index 00000000..6357ae09 --- /dev/null +++ b/src/main/java/com/quollwriter/ui/AbstractProjectViewer.java @@ -0,0 +1,7639 @@ +package com.quollwriter.ui; + +import java.awt.*; +import java.awt.dnd.*; +import java.awt.event.*; + +import java.io.*; +import java.nio.file.*; + +import java.net.*; + +import java.security.*; + +import java.text.*; + +import java.util.Arrays; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Set; +import java.util.StringTokenizer; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.WeakHashMap; +import java.util.Collections; +import java.util.Stack; +import java.util.TimerTask; +import java.util.concurrent.*; + +import org.w3c.dom.Element; +import org.w3c.dom.Node; + +import javax.sound.sampled.*; + +import javax.swing.*; +import javax.swing.border.*; +import javax.swing.event.*; +import javax.swing.tree.*; +import javax.swing.text.*; + +import com.gentlyweb.properties.*; + +import com.jgoodies.forms.builder.*; +import com.jgoodies.forms.factories.*; +import com.jgoodies.forms.layout.*; + +import com.quollwriter.*; + +import com.quollwriter.data.*; + +import com.quollwriter.db.*; +import com.quollwriter.ui.sidebars.*; +import com.quollwriter.ui.panels.*; +import com.quollwriter.events.*; +import com.quollwriter.synonyms.*; +import com.quollwriter.text.*; +import com.quollwriter.text.rules.*; + +import com.quollwriter.ui.actionHandlers.*; +import com.quollwriter.ui.components.*; +import com.quollwriter.ui.events.*; +import com.quollwriter.ui.renderers.*; +import com.quollwriter.ui.charts.*; + +import com.quollwriter.data.editors.*; +import com.quollwriter.editors.*; +import com.quollwriter.editors.ui.*; +import com.quollwriter.editors.ui.sidebars.*; + +import com.quollwriter.achievements.rules.*; +import com.quollwriter.uistrings.*; + +import static com.quollwriter.LanguageStrings.*; +import static com.quollwriter.uistrings.UILanguageStringsManager.getUIString; + +public abstract class AbstractProjectViewer extends AbstractViewer implements PropertyChangedListener, + SpellCheckSupported, + HTMLPanelActionHandler +{ + + public static final String IDEA_BOARD_HEADER_CONTROL_ID = "ideaBoard"; + public static final String FIND_HEADER_CONTROL_ID = "find"; + public static final String FULL_SCREEN_HEADER_CONTROL_ID = "fullScreen"; + public static final String CLOSE_HEADER_CONTROL_ID = "close"; + + public static final String TAB_OBJECT_TYPE = "tab"; + + public static int INTERNAL_SPLIT_PANE_DIVIDER_WIDTH = 2; + + // public static final int CLOSE_WARMUPS_ACTION = 12; //"closeWarmups"; + public static final int CREATE_PROJECT_SNAPSHOT_ACTION = 0; + public static final int NEW_PROJECT_ACTION = 1; + public static final int EDIT_CHAPTER_ACTION = 4; // "editChapter"; + public static final int DELETE_CHAPTER_ACTION = 5; + public static final int RENAME_CHAPTER_ACTION = 7; // "renameChapter"; + public static final int ABOUT_ACTION = 9; // "about"; + public static final int REPORT_BUG_ACTION = 10; // "reportBug"; + public static final int OPEN_PROJECT_ACTION = 11; // "openProject"; + public static final int CLOSE_PROJECT_ACTION = 12; // "closeProject"; + public static final int DELETE_PROJECT_ACTION = 13; // "deleteProject"; + public static final int RENAME_PROJECT_ACTION = 14; // "renameProject"; + public static final int EDIT_PROJECT_PROPERTIES_ACTION = 15; // "editProjectProperties"; + public static final int WARMUP_EXERCISE_ACTION = 26; + public static final int CONTACT_SUPPORT_ACTION = 28; + + public static final String NAME_CHANGED = "nameChanged"; + + protected Project proj = null; + private DnDTabbedPane tabs = null; + private ProjectDictionaryProvider projDict = null; + private String projectLanguage = null; + private SynonymProvider synProv = null; + private JSplitPane splitPane = null; + private JSplitPane splitPane2 = null; + protected ObjectManager dBMan = null; + //private Header title = null; + private Map toolbars = new HashMap (); + private Box toolbarPanel = null; + private Accordion acc = null; + private boolean spellCheckingEnabled = false; + private Date sessionStart = new Date (); + //private Box notifications = null; + private boolean playSoundOnKeyStroke = false; + private Clip keyStrokeSound = null; + //private QPopup achievementsPopup = null; + private ChapterCounts startWordCounts = new ChapterCounts (null); + private Map noEditorReadabilityIndices = new WeakHashMap (); + private Map chapterCounts = new WeakHashMap (); + //private Box itemsBox = null; + private Box sideBar = null; + private Box sideBarWrapper = null; + private Map sideBars = new HashMap (); + private Stack activeSideBars = new Stack (); + private AbstractSideBar currentOtherSideBar = null; + private AbstractSideBar mainSideBar = null; + private Finder finder = null; + private WordCountsSideBar wordCounts = null; + private Map panels = new HashMap (); + private int lastDividerLocation = -1; + private Map sideBarWidths = new HashMap (); + private java.util.List sideBarListeners = new ArrayList (); + private java.util.List mainPanelListeners = new ArrayList (); + private java.util.List fullScreenListeners = new ArrayList (); + //private Map popups = new HashMap (); + + private Timer achievementsHideTimer = null; + + private JTree chapterTree = null; + + private FullScreenFrame fsf = null; + private FullScreenOverlay fullScreenOverlay = null; + + private String toolbarLocation = Constants.BOTTOM; + + private String layout = Constants.LAYOUT_PS_CH; + + private Map tempOptions = new HashMap (); + + //private Set projectEventListeners = new HashSet (); + //private boolean ignoreProjectEvents = false; + + //private Tips tips = null; + + private DictionaryManager dictMan = null; + + private WordCountTimer wordCountTimer = null; + + private int savedOtherSideBarWidth = 0; + private int savedSideBarWidth = 0; + + private JPanel cards = null; + private CardLayout cardsLayout = null; + + private ScheduledFuture autoSaveTask = null; + private ScheduledFuture chapterCountsUpdater = null; + private TargetsData targets = null; + private Map chapterWordCountTargetWarned = new HashMap (); + + public AbstractProjectViewer() + { + + final AbstractProjectViewer _this = this; + + this.wordCountTimer = new WordCountTimer (this, + -1, + -1); + + this.setDefaultCloseOperation (WindowConstants.DO_NOTHING_ON_CLOSE); + + // Create a split pane. + this.splitPane = UIUtils.createSplitPane (JSplitPane.HORIZONTAL_SPLIT); + + this.splitPane.setBorder (null); + + javax.swing.plaf.basic.BasicSplitPaneDivider div = ((javax.swing.plaf.basic.BasicSplitPaneUI) this.splitPane.getUI ()).getDivider (); + div.setBorder (new MatteBorder (0, 0, 0, 1, UIUtils.getBorderColor ())); + this.splitPane.setOpaque (false); + this.splitPane.setBackground (UIUtils.getComponentColor ()); + + this.splitPane2 = UIUtils.createSplitPane (JSplitPane.HORIZONTAL_SPLIT); + this.splitPane2.setBorder (null); + + div = ((javax.swing.plaf.basic.BasicSplitPaneUI) this.splitPane2.getUI ()).getDivider (); + div.setBorder (new MatteBorder (0, 0, 0, 1, UIUtils.getBorderColor ())); + this.splitPane2.setOpaque (false); + this.splitPane2.setBackground (UIUtils.getComponentColor ()); + + InputMap im = this.getInputMap (JComponent.WHEN_IN_FOCUSED_WINDOW); +/* + im.put (KeyStroke.getKeyStroke (KeyEvent.VK_F12, + InputEvent.CTRL_MASK | InputEvent.ALT_MASK), + "debug"); + im.put (KeyStroke.getKeyStroke (KeyEvent.VK_F1, + InputEvent.CTRL_MASK | InputEvent.ALT_MASK), + "debug-mode"); + + im.put (KeyStroke.getKeyStroke (KeyEvent.VK_F11, + 0), + "whatsnew"); +*/ + ActionMap am = this.getActionMap (); + + this.initKeyMappings (im); + + this.initActionMappings (am); + + this.tabs = this.createTabbedPane (); + + this.tabs.addChangeListener (new ChangeListener () + { + + public void stateChanged (ChangeEvent ev) + { + + if (_this.tabs.getTabCount () == 0) + { + + _this.tabs.setVisible (false); + + } else { + + _this.tabs.setVisible (true); + + } + } + + }); + + this.tabs.setMinimumSize (new Dimension (300, 200)); + this.tabs.putClientProperty(com.jgoodies.looks.Options.NO_CONTENT_BORDER_KEY, Boolean.TRUE); + //this.tabs.putClientProperty(com.jgoodies.looks.Options.EMBEDDED_TABS_KEY, Boolean.TRUE); + this.tabs.setBorder (null); + + this.setTabsLocation (null); + + this.splitPane2.setLeftComponent (this.tabs); + + this.splitPane.setRightComponent (this.splitPane2); + + this.sideBar = new Box (BoxLayout.PAGE_AXIS); + this.sideBar.setOpaque (false); + this.sideBar.setMaximumSize (new Dimension (Short.MAX_VALUE, + Short.MAX_VALUE)); + + this.toolbarPanel = new Box (BoxLayout.X_AXIS); + + this.toolbarPanel.setOpaque (false); + + this.toolbarPanel.setAlignmentX (Component.LEFT_ALIGNMENT); + + this.toolbarPanel.setMaximumSize (new Dimension (Short.MAX_VALUE, + 100)); + + this.sideBarWrapper = new Box (BoxLayout.X_AXIS); + this.sideBarWrapper.setOpaque (false); + this.sideBarWrapper.setAlignmentX (Component.LEFT_ALIGNMENT); + + this.sideBar.add (this.sideBarWrapper); + this.sideBar.add (this.toolbarPanel); + + this.splitPane.setLeftComponent (this.sideBar); + this.splitPane.setAlignmentX (Component.LEFT_ALIGNMENT); + + this.cardsLayout = new CardLayout (0, 0); + + this.cards = new JPanel (this.cardsLayout); + this.cards.setBackground (UIUtils.getComponentColor ()); + this.cards.setAlignmentX (Component.LEFT_ALIGNMENT); + + this.cards.add (this.splitPane, "main"); + + this.addTabChangeListener (new ChangeAdapter () + { + + public void stateChanged (ChangeEvent ev) + { + + QuollPanel qp = _this.getCurrentlyVisibleTab (); + + if (qp != null) + { + + _this.fireMainPanelShownEvent (qp); + + } + + } + + }); + + this.setContent (this.cards); + + } + + public void addCard (String name, + JComponent c) + { + + this.cards.add (c, + name); + + } + + public void showMainCard () + { + + this.showCard ("main"); + + } + + public void showCard (String name) + { + + this.cardsLayout.show (this.cards, + name); + + this.validate (); + this.repaint (); + + } + + @Override + public void initActionMappings (ActionMap am) + { + + final AbstractProjectViewer _this = this; + + super.initActionMappings (am); +/* + am.put ("next-tab", + new AbstractAction () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + int ind = _this.tabs.getSelectedIndex (); + + int tc = _this.tabs.getTabCount (); + + ind++; + + if (ind >= tc) + { + + ind = 0; + + } + + _this.tabs.setSelectedIndex (ind); + + } + + }); + + am.put ("prev-tab", + new AbstractAction () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + + } + + }); +*/ + am.put ("close-current-tab", + new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + QuollPanel qp = _this.getCurrentlyVisibleTab (); + + if (qp != null) + { + + _this.closePanel (qp); + + } + + } + + }); + + am.put ("show-main-sidebar", + new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + _this.closeSideBar (); + + } + + }); + + am.put ("new-project", + this.getAction (AbstractProjectViewer.NEW_PROJECT_ACTION, + null)); + + am.put ("open-project", + this.getAction (AbstractProjectViewer.OPEN_PROJECT_ACTION, + null)); + + am.put (Constants.SHOW_FIND_ACTION, + new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + _this.showFind (null); + + } + + }); + + am.put ("fullscreen", + new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + _this.enterFullScreen (); + + } + + }); + + } + + @Override + public void initKeyMappings (InputMap im) + { + + super.initKeyMappings (im); +/* + im.put (KeyStroke.getKeyStroke (KeyEvent.VK_TAB, + InputEvent.ALT_MASK), + "next-tab"); + + im.put (KeyStroke.getKeyStroke (KeyEvent.VK_PAGE_DOWN, + InputEvent.CTRL_MASK), + "next-tab"); + + im.put (KeyStroke.getKeyStroke (KeyEvent.VK_TAB, + InputEvent.CTRL_MASK | InputEvent.SHIFT_MASK), + "prev-tab"); + + im.put (KeyStroke.getKeyStroke (KeyEvent.VK_PAGE_UP, + InputEvent.CTRL_MASK), + "prev-tab"); +*/ + im.put (KeyStroke.getKeyStroke (KeyEvent.VK_F1, + 0), + Constants.SHOW_FIND_ACTION); + + im.put (KeyStroke.getKeyStroke (KeyEvent.VK_F4, + 0), + "close-current-tab"); + + im.put (KeyStroke.getKeyStroke (KeyEvent.VK_F5, + 0), + "fullscreen"); + + im.put (KeyStroke.getKeyStroke (KeyEvent.VK_ESCAPE, + 0), + "show-main-sidebar"); + + im.put (KeyStroke.getKeyStroke (KeyEvent.VK_F, + Event.CTRL_MASK), + Constants.SHOW_FIND_ACTION); + + im.put (KeyStroke.getKeyStroke (KeyEvent.VK_N, + Event.CTRL_MASK), + "new-project"); + im.put (KeyStroke.getKeyStroke (KeyEvent.VK_O, + Event.CTRL_MASK), + "open-project"); + + } + + public WordCountTimer getWordCountTimer () + { + + return this.wordCountTimer; + + } + + protected void initSideBars () + throws GeneralException + { + + this.finder = new ProjectFinder (this); + + this.addSideBar (this.finder); + + this.wordCounts = new WordCountsSideBar (this); + + this.addSideBar (this.wordCounts); + + this.mainSideBar = this.getMainSideBar (); + + this.addSideBar (this.mainSideBar); + + } + + public JComponent getSideBarForFullScreen () + { + + if (this.currentOtherSideBar != null) + { + + this.sideBarWrapper.removeAll (); + this.sideBarWrapper.add (this.currentOtherSideBar); + + } else { + + if (this.mainSideBar != null) + { + + this.sideBarWrapper.removeAll (); + this.sideBarWrapper.add (this.mainSideBar); + + } + + } + + return this.sideBar; + + } + + private void fireMainPanelShownEvent (QuollPanel p) + { + + MainPanelEvent ev = new MainPanelEvent (this, + p); + + for (MainPanelListener l : this.mainPanelListeners) + { + + l.panelShown (ev); + + } + + } + + public void removeMainPanelListener (MainPanelListener l) + { + + this.mainPanelListeners.remove (l); + + } + + public void addMainPanelListener (MainPanelListener l) + { + + this.mainPanelListeners.add (l); + + } + + private void fireFullScreenEnteredEvent () + { + + FullScreenEvent ev = new FullScreenEvent (this); + + for (FullScreenListener l : this.fullScreenListeners) + { + + l.fullScreenEntered (ev); + + } + + } + + private void fireFullScreenExitedEvent () + { + + FullScreenEvent ev = new FullScreenEvent (this); + + for (FullScreenListener l : this.fullScreenListeners) + { + + l.fullScreenExited (ev); + + } + + } + + public void removeFullScreenListener (FullScreenListener l) + { + + this.fullScreenListeners.remove (l); + + } + + public void addFullScreenListener (FullScreenListener l) + { + + this.fullScreenListeners.add (l); + + } + + protected void fireSideBarShownEvent (AbstractSideBar sb) + { + + SideBarEvent ev = new SideBarEvent (this, + sb); + + for (SideBarListener l : this.sideBarListeners) + { + + l.sideBarShown (ev); + + } + + } + + protected void fireSideBarHiddenEvent (AbstractSideBar sb) + { + + SideBarEvent ev = new SideBarEvent (this, + sb); + + for (SideBarListener l : this.sideBarListeners) + { + + l.sideBarHidden (ev); + + } + + } + + public void removeSideBarListener (SideBarListener l) + { + + this.sideBarListeners.remove (l); + + } + + public void addSideBarListener (SideBarListener l) + { + + this.sideBarListeners.add (l); + + } + + private JComponent createLayoutFiller () + { + + Box l = new Box (BoxLayout.X_AXIS); + l.setMinimumSize (new Dimension (0, 0)); + l.setPreferredSize (new Dimension (0, 0)); + l.setVisible (false); + + return l; + + } + + public void closeSideBar () + { + + if (this.currentOtherSideBar != null) + { + + this.currentOtherSideBar.onHide (); + + this.fireSideBarHiddenEvent (this.currentOtherSideBar); + + } + + this.currentOtherSideBar = null; + + this.showMainSideBar (); + + } + + public AbstractSideBar getSideBar (String id) + { + + return this.sideBars.get (id); + + } + + public void removeSideBar (String id) + { + + this.removeSideBar (this.getSideBar (id)); + + } + + public void removeSideBar (AbstractSideBar sb) + { + + if (sb == null) + { + + return; + + } + + this.sideBars.remove (sb.getId ()); + + this.activeSideBars.remove (sb); + + if (this.currentOtherSideBar == sb) + { + + this.currentOtherSideBar = null; + + } + + try + { + + // Close the sidebar down gracefully. + sb.onHide (); + + this.fireSideBarHiddenEvent (sb); + + sb.onClose (); + + } catch (Exception e) { + + Environment.logError ("Unable to close sidebar: " + sb.getId (), + e); + + } + + this.removeSideBarListener (sb); + + this.removeMainPanelListener (sb); + + AbstractSideBar _sb = (this.activeSideBars.size () > 0 ? this.activeSideBars.peek () : null); + + if (_sb != null) + { + + this.showSideBar (_sb.getId ()); + + } else { + + if (this.fsf == null) + { + + this.setUILayout (this.layout); + + } + + } + + } + + public void addSideBar (AbstractSideBar sb) + throws GeneralException + { + + if (sb == null) + { + + throw new IllegalArgumentException ("No sidebar provided."); + + } + + String state = null; + + String id = sb.getId (); + + if (id != null) + { + + state = this.proj.getProperty ("sidebarState-" + id); + + } + + sb.init (state); + + //sb.setName (name); + + this.sideBars.put (id, + sb); + + this.addMainPanelListener (sb); + + } + + public boolean isDistractionFreeModeEnabled () + { + + if (this.fsf != null) + { + + return this.fsf.isDistractionFreeModeEnabled (); + + } + + return false; + + } + + public void exitFullScreen () + { + + try + { + + if (this.fsf != null) + { + + this.fsf.close (); + + this.tabs.setVisible (true); + + this.fullScreenOverlay.setVisible (false); + + } + + this.setUILayout (this.layout); + + } catch (Exception e) { + + Environment.logError ("Unable to exit full screen", + e); + + UIUtils.showErrorMessage (null, + getUIString (fullscreen,actions,exit,actionerror)); + + } finally { + + this.setVisible (true); + + } + + } + + public void closeFind () + { + + this.showMainSideBar (); + + } + + public void viewWordCounts () + { + + this.showSideBar ("wordcounts"); + + this.fireProjectEvent (ProjectEvent.WORD_COUNTS, + ProjectEvent.SHOW); + + this.fireProjectEvent (ProjectEvent.READABILITY, + ProjectEvent.SHOW); + + } + + public void showFind (String text) + { + + this.showSideBar ("find"); + + if (text == null) + { + + QuollPanel qp = this.getCurrentlyVisibleTab (); + + if (qp instanceof AbstractEditorPanel) + { + + text = ((AbstractEditorPanel) qp).getEditor ().getSelectedText (); + + } + + } + + this.finder.setFindText (text); + + this.finder.onShow (); + + } + + public boolean isMainSideBar (AbstractSideBar sb) + { + + return this.mainSideBar == sb; + + } + + public boolean isMainSideBarId (String n) + { + + return (n.equals (this.getMainSideBarId ())); + + } + + protected void setMainSideBar (AbstractSideBar sb) + { + + this.mainSideBar = sb; + + this.sideBars.put (this.getMainSideBarId (), + sb); + + this.showMainSideBar (); + + } + + public void showMainSideBar () + { + + this.showSideBar (this.getMainSideBarId ()); + + } + + public String getMainSideBarId () + { + + return this.mainSideBar.getId (); + + } + + public int getActiveSideBarCount () + { + + int c = this.activeSideBars.size (); + + if ((this.layout.equals (Constants.LEFT)) + || + (this.layout.equals (Constants.RIGHT)) + || + (this.layout.equals (Constants.LAYOUT_PS_CH)) + || + (this.layout.equals (Constants.LAYOUT_CH_PS)) + ) + { + + c++; + + } + + return c; + + } + + public JPopupMenu getShowOtherSideBarsPopupSelector () + { + + final AbstractProjectViewer _this = this; + + JPopupMenu m = new JPopupMenu (); + + if (this.currentOtherSideBar != null) + { + + if ((this.layout.equals (Constants.LEFT)) + || + (this.layout.equals (Constants.RIGHT)) + || + (this.layout.equals (Constants.LAYOUT_PS_CH)) + || + (this.layout.equals (Constants.LAYOUT_CH_PS)) + ) + { + + JMenuItem mi = UIUtils.createMenuItem (this.mainSideBar.getActiveTitle (), + this.mainSideBar.getActiveIconType (), + new ActionListener () + { + + public void actionPerformed (ActionEvent ev) + { + + _this.showMainSideBar (); + + } + + }); + + m.add (mi); + + } + + } + + // Means we are showing the main sidebar and the other sidebar. + // Exclude those from the list. + for (AbstractSideBar sb : this.activeSideBars) + { + + if ((this.currentOtherSideBar != null) + && + (this.currentOtherSideBar == sb) + ) + { + + continue; + + } + + final AbstractSideBar _sb = sb; + + JMenuItem mi = UIUtils.createMenuItem (sb.getActiveTitle (), + sb.getActiveIconType (), + new ActionListener () + { + + public void actionPerformed (ActionEvent ev) + { + + _this.showSideBar (_sb.getId ()); + + } + + }); + + m.add (mi); + + } + + return m; + + } + + public void showSideBar (String id) + { + + if ((this.currentOtherSideBar != null) + && + (this.currentOtherSideBar.getId ().equals (id)) + ) + { + + return; + + } + + AbstractSideBar b = this.sideBars.get (id); + + if (b == null) + { + + throw new IllegalArgumentException ("Unable to show sidebar: " + + id + + ", no sidebar found with that id."); + + } + + if (this.currentOtherSideBar != null) + { + + // Will be hiding this one. + this.currentOtherSideBar.onHide (); + + this.fireSideBarHiddenEvent (this.currentOtherSideBar); + + } + + if (id.equals (this.getMainSideBarId ())) + { + + // Need to check the layout. If we are only showing one sidebar then set the current other + // to null. + if (this.isUILayoutShowSingleSidebar ()) + { + + this.currentOtherSideBar = null; + + } + + } else { + + this.currentOtherSideBar = b; + + this.activeSideBars.remove (b); + + this.activeSideBars.push (b); + + } + + if (this.fsf != null) + { + + if (this.currentOtherSideBar != null) + { + + this.sideBarWrapper.removeAll (); + this.sideBarWrapper.add (this.currentOtherSideBar); + + } else { + + this.sideBarWrapper.removeAll (); + this.sideBarWrapper.add (this.mainSideBar); + + } + + this.fsf.showSideBar (); + + } else { + + this.setUILayout (this.layout); + + } + + try + { + + b.onShow (); + + } catch (Exception e) { + + Environment.logError ("Unable to call onShow for sidebar: " + + id + + ", instance: " + + b, + e); + + } + + this.fireSideBarShownEvent (b); + + } + + public void setSplitPaneColor (Color c) + { + + + ((javax.swing.plaf.basic.BasicSplitPaneUI) this.splitPane.getUI ()).getDivider ().setBackground (UIUtils.getBorderColor ()); + + this.validate (); + this.repaint (); + + } + + public void setSplitPaneColor () + { + + this.setSplitPaneColor (UIUtils.getComponentColor ()); + + } + + public void addTabChangeListener (ChangeListener cl) + { + + this.tabs.addChangeListener (cl); + + } + + private void updateToolbarForPanel (QuollPanel qp) + { + + if (qp != null) + { + + this.toolbarPanel.removeAll (); + + JToolBar tb = qp.getToolBar ((this.fsf != null)); + + if (tb != null) + { + + this.toolbarPanel.add (tb); + + if (tb.getComponentCount () == 0) + { + + this.setToolbarVisible (false); + + } else + { + + this.setToolbarVisible (true); + + } + + } + + this.toolbarPanel.setMaximumSize (new Dimension (Short.MAX_VALUE, + this.toolbarPanel.getPreferredSize ().height)); + + this.toolbarPanel.revalidate (); + this.toolbarPanel.repaint (); + + } else + { + + this.setToolbarVisible (false); + + } + + } + + private DnDTabbedPane createTabbedPane () + { + + final AbstractProjectViewer _this = this; + + final DnDTabbedPane p = new DnDTabbedPane (); + + p.setTabLayoutPolicy (JTabbedPane.SCROLL_TAB_LAYOUT); + + p.addChangeListener (new ChangeAdapter () + { + + public void stateChanged (ChangeEvent ev) + { + + _this.updateToolbarForPanel (_this.getCurrentlyVisibleTab ()); + + } + + }); + + return p; + + } + + public abstract String getViewerTitle (); + + public abstract void reloadTreeForObjectType (String objType); + + public abstract void reloadTreeForObjectType (NamedObject obj); + + public abstract void showObjectInTree (String treeObjType, + NamedObject obj); + + public abstract AbstractSideBar getMainSideBar (); + + public abstract String getChapterObjectName (); + + public abstract void fillFullScreenTitleToolbar (JToolBar toolbar); + + public abstract void doSaveState (); + + public abstract void handleOpenProject () + throws Exception; + + public abstract void handleNewProject () + throws Exception; + + public abstract boolean viewObject (DataObject d); + + public abstract boolean viewObject (DataObject d, + ActionListener doAfterView); + + public abstract boolean openPanel (String id); + + public abstract void deleteChapter (Chapter c); + + public abstract void deleteObject (NamedObject o) + throws GeneralException; + + public abstract void deleteObject (NamedObject o, + boolean deleteChildObjects) + throws GeneralException; + + public abstract void updateChapterIndexes (Book b) + throws GeneralException; + + public abstract void handleItemChangedEvent (ItemChangedEvent ev); + + public abstract Set findText (String t); + + public Action getAction (int name) + { + + return this.getAction (name, + null); + + } + + /** + * Get the correct text properties depending on whether the viewer is in full screen or not. + * + * @returns Normal project text properties if we are in normal mode or full screen text properties + * if we are in full screen mode. + */ + public TextProperties getTextProperties () + { + + // TODO return (this.fsf != null ? Environment.getFullScreenTextProperties () : Environment.getProjectTextProperties ()); + return null; + + } + + public void reinitAllChapterEditors () + { + + this.doForPanels (AbstractEditorPanel.class, + new DefaultQuollPanelAction () + { + + public void doAction (QuollPanel qp) + { + + ((AbstractEditorPanel) qp).initEditor (); + + } + + }); + + } + + public void scrollTo (final Chapter c, + final int pos) + { + + final AbstractProjectViewer _this = this; + + this.viewObject (c); + + SwingUtilities.invokeLater (new Runner () + { + + public void run () + { + + try + { + + _this.getEditorForChapter (c).scrollToPosition (pos); + _this.getEditorForChapter (c).scrollToPosition (pos); + + } catch (Exception e) + { + + Environment.logError ("Unable to scroll to position: " + + pos, + e); + + } + + } + + }); + + } + + public AbstractEditorPanel getEditorForChapter (Chapter c) + { + + return (AbstractEditorPanel) this.getQuollPanelForObject (c); + + } + + public Action getAction (int name, + final NamedObject other) + { + + final AbstractProjectViewer pv = this; + + if (name == AbstractProjectViewer.EDIT_CHAPTER_ACTION) + { + + return new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + pv.viewObject ((Chapter) other); + + } + + }; + + } + + if (name == AbstractProjectViewer.RENAME_CHAPTER_ACTION) + { + + return new RenameChapterActionHandler ((Chapter) other, + pv); + + } + + if (name == AbstractProjectViewer.WARMUP_EXERCISE_ACTION) + { + + return new ActionAdapter () + { + + public void actionPerformed (final ActionEvent ev) + { + + pv.showWarmupPromptSelect (); + + } + + }; + + } + + if (name == AbstractProjectViewer.DELETE_CHAPTER_ACTION) + { + + return new DeleteChapterActionHandler ((Chapter) other, + pv); + + } + + if (name == AbstractProjectViewer.CREATE_PROJECT_SNAPSHOT_ACTION) + { + + return new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + UIUtils.showCreateBackup (pv.getProject (), + null, + pv); + + } + + }; + + } + + if (name == AbstractProjectViewer.RENAME_PROJECT_ACTION) + { + + return new RenameProjectActionHandler (this); + + } + + if (name == AbstractProjectViewer.OPEN_PROJECT_ACTION) + { + + return new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + try + { + + Environment.showAllProjectsViewer (); + //Environment.showLanding (); + + } catch (Exception e) { + + Environment.logError ("Unable to show landing", + e); + + UIUtils.showErrorMessage (pv, + getUIString (project,actions,openproject)); + //"Unable to show the {projects} window, please contact Quoll Writer support for assistance."); + + } + + } + + }; + + } + + if (name == AbstractProjectViewer.NEW_PROJECT_ACTION) + { + + return new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + UIUtils.showAddNewProject (pv, + null, + null); + + } + + }; + + } + + if (name == AbstractProjectViewer.CLOSE_PROJECT_ACTION) + { + + return new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + pv.close (false, + null); + + } + + }; + + } + + if (name == AbstractProjectViewer.EDIT_PROJECT_PROPERTIES_ACTION) + { + + return new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + pv.showOptions (); + + } + + }; + + } + + if (name == AbstractProjectViewer.DELETE_PROJECT_ACTION) + { + + return new DeleteProjectActionHandler (this, + this.getProject (), + null); + + } + + if (name == AbstractProjectViewer.REPORT_BUG_ACTION) + { + + return new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + pv.showReportProblem (); + + } + + }; + + } + + if (name == AbstractProjectViewer.CONTACT_SUPPORT_ACTION) + { + + return new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + pv.showContactSupport (); + + } + + }; + + } + + if (name == AbstractProjectViewer.ABOUT_ACTION) + { + + return new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + pv.showAbout (); + + } + + }; + + } + + return super.getAction (name); + + } + + public void updateProjectDictionaryForNames (Set oldNames, + NamedObject object) + { + + if (!(object instanceof Asset)) + { + + return; + + } + + if (this.projDict != null) + { + + this.projDict.removeObjectNames (oldNames); + this.projDict.addNamedObject (object); + + } +/* + for (String nn : oldNames) + { + + if (nn == null) + { + + continue; + + } + + if (nn.trim ().length () == 0) + { + + continue; + + } + + try + { + + this.removeWordFromDictionary (nn); + //"project"); + //this.removeWordFromDictionary (nn + "'s"); + //"project"); + + } catch (Exception e) {} + + } + + for (String nn : object.getAllNames ()) + { + + // Add the name. + try + { + + this.addWordToDictionary (nn); + //"project"); + //this.addWordToDictionary (nn + "'s"); + //"project"); + + } catch (Exception e) {} + + } +*/ + } + + public void removeWordFromDictionary (String w) + { + + if (this.projDict != null) + { + + this.projDict.removeWord (w); + + } + + } + + public void addWordToDictionary (String w) + { + + if (this.projDict != null) + { + + this.projDict.addWord (w); + + } + + } + + public void setDictionaryProvider (DictionaryProvider2 dp) + { + + throw new UnsupportedOperationException ("Not supported."); + + } + + public void checkSpelling () + { + + throw new UnsupportedOperationException ("Not supported."); + + } + + public void doForSideBars (final Class type, + final QuollSideBarAction act, + final boolean doOnEventThread) + { + + Set ps = new LinkedHashSet (this.sideBars.values ()); + + for (AbstractSideBar sb : ps) + { + + if (type.isAssignableFrom (sb.getClass ())) + { + + final AbstractSideBar _sb = sb; + + if (doOnEventThread) + { + + UIUtils.doLater (new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + act.doAction (_sb); + + } + + }); + + } else { + + try + { + + act.doAction (sb); + + } catch (Exception e) { + + Environment.logError ("Unable to perform action: " + + act, + e); + + } + + } + + } + + } + + } + + public void doForSideBars (final Class type, + final QuollSideBarAction act) + { + + this.doForSideBars (type, + act, + true); + + } + + public void doForPanels (final Class type, + final QuollPanelAction act, + final boolean doOnEventThread) + { + + Set ps = new LinkedHashSet (this.panels.values ()); + + for (QuollPanel p : ps) + { + + if (type.isAssignableFrom (p.getClass ())) + { + + final QuollPanel _p = p; + + if (doOnEventThread) + { + + UIUtils.doLater (new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + act.doAction (_p); + + } + + }); + + } else { + + try + { + + act.doAction (p); + + } catch (Exception e) { + + Environment.logError ("Unable to perform action: " + + act, + e); + + } + + } + + } + + } + + } + + public void doForPanels (final Class type, + final QuollPanelAction act) + { + + this.doForPanels (type, + act, + true); + + } + + public boolean isHighlightWritingLine () + { + + return this.proj.getPropertyAsBoolean (Constants.EDITOR_HIGHLIGHT_WRITING_LINE_PROPERTY_NAME); + + } + + public void setHighlightWritingLine (final boolean s) + { + + this.doForPanels (AbstractEditorPanel.class, + new DefaultQuollPanelAction () + { + + public void doAction (QuollPanel p) + { + + ((AbstractEditorPanel) p).getEditor ().setHighlightWritingLine (s); + + } + + }); + + } + + /** + * Set the spell check language for the project. Note: this DOES NOT affect the project property: + * {@link Constants.SPELL_CHECK_LANGUAGE_PROPERTY_NAME}. Also this does not affect the spell check enabled + * flag. + * + * @param lang The language to use, set to null to switch off spell checking. + * @param updateEditors Set to true to tell all the editor panels about the change. + * @throws Exception If something goes wrong. + */ + public void setSpellCheckLanguage (String lang, + boolean updateEditors) + throws Exception + { + + if ((this.projectLanguage != null) + && + (this.projectLanguage.equals (lang)) + ) + { + + // Not changing. + return; + + } + + this.projectLanguage = lang; + + if (lang == null) + { + + // Basically turning off spellchecking. + this.projDict = null; + + this.doForPanels (SpellCheckSupported.class, + new DefaultQuollPanelAction () + { + + public void doAction (QuollPanel panel) + { + + AbstractEditorPanel s = (AbstractEditorPanel) panel; + + s.setDictionaryProvider (null); + + s.setSynonymProvider (null); + + } + + }); + + return; + + } + + java.util.List names = new ArrayList (); + + boolean isEnglish = UILanguageStrings.isEnglish (lang); + + // Get the names from the assets. + Set objs = this.proj.getAllNamedChildObjects (Asset.class); + + for (NamedObject o : objs) + { + + Set onames = o.getAllNames (); + + for (String n : onames) + { + + // Get the name, add it. + names.add (n); + + if (isEnglish) + { + + names.add (n + "'s"); + + } + + } + + } + + this.projDict = new ProjectDictionaryProvider (names, + new UserDictionaryProvider (this.projectLanguage)); + + final AbstractProjectViewer _this = this; + + if (updateEditors) + { + + this.doForPanels (AbstractEditorPanel.class, + new DefaultQuollPanelAction () + { + + public void doAction (QuollPanel panel) + { + + AbstractEditorPanel s = (AbstractEditorPanel) panel; + + s.setDictionaryProvider (_this.projDict); + + try + { + + s.setSynonymProvider (_this.getSynonymProvider ()); + + } catch (Exception e) { + + Environment.logError ("Unable to set synonym provider", + e); + + } + + } + + }); + + } + + } + + public ReadabilityIndices getReadabilityIndices (String text) + { + + ReadabilityIndices ri = new ReadabilityIndices (); + + if (text != null) + { + + ri.add (text); + + } + + return ri; + + + } + + public String getWordTypes (String word) + throws GeneralException + { + + if (this.synProv != null) + { + + return this.synProv.getWordTypes (word); + + } + + return null; + + } + + public Synonyms getSynonyms (String word) + throws GeneralException + { + + if (this.synProv != null) + { + + return this.synProv.getSynonyms (word); + + } + + return null; + + } + + public boolean synonymLookupsSupported () + { + + return this.synProv != null; + + } + + public SynonymProvider getSynonymProvider () + throws Exception + { + + if (this.synProv != null) + { + + return this.synProv; + + } + + this.synProv = Environment.getSynonymProvider (this.getSpellCheckLanguage ()); + + return this.synProv; + + } + + public boolean isLanguageFunctionAvailable () + { + + if (!this.isLanguageEnglish ()) + { + + this.showNotificationPopup (getUIString (functionunavailable,title), + //"Function unavailable", + getUIString (functionunavailable,text), + //"Sorry, this function is only available when your spellchecker language is English.

    Click here to contact me to help add support for your language", + 20); + + return false; + + } + + return true; + + } + + public boolean isLanguageEnglish () + { + + return UILanguageStrings.isEnglish (this.getSpellCheckLanguage ()); + + } + + public String getSpellCheckLanguage () + { + + String c = this.proj.getProperty (Constants.SPELL_CHECK_LANGUAGE_PROPERTY_NAME); + + // Get the property. + if (c == null) + { + + c = UserProperties.get (Constants.SPELL_CHECK_LANGUAGE_PROPERTY_NAME); + + } + + if (UILanguageStrings.isEnglish (c)) + { + + c = Constants.ENGLISH; + + } + + return c; + + } + + public ProjectDictionaryProvider getDictionaryProvider () + { + + return this.projDict; + + } + + public void setToolbarLocation (String loc) + { + + if (loc == null) + { + + loc = Constants.BOTTOM; + + } + + if (loc.equals (Constants.TOP)) + { + + this.toolbarPanel.setBorder (new CompoundBorder (new MatteBorder (0, 0, 1, 0, UIUtils.getBorderColor ()), + new EmptyBorder (0, + 5, + 0, + 5))); + + this.sideBar.add (this.toolbarPanel, + 0); + + } else + { + + this.toolbarPanel.setBorder (new CompoundBorder (new MatteBorder (1, 0, 0, 0, UIUtils.getBorderColor ()), + new EmptyBorder (0, + 5, + 0, + 5))); + + this.sideBar.add (this.toolbarPanel); + + } + + this.toolbarLocation = loc; + + } + + public void setTabsLocation (String loc) + { + + if (loc == null) + { + + loc = Constants.TOP; + + } + + int p = -1; + + Border b = null; + + if (loc.equals (Constants.TOP)) + { + + p = JTabbedPane.TOP; + + b = new EmptyBorder (7, 0, 0, 0); + + } + + if (loc.equals (Constants.BOTTOM)) + { + + p = JTabbedPane.BOTTOM; + + b = new EmptyBorder (0, 0, 7, 0); + + } + + if (loc.equals (Constants.LEFT)) + { + + p = JTabbedPane.LEFT; + + } + + if (loc.equals (Constants.RIGHT)) + { + + p = JTabbedPane.RIGHT; + + } + + this.tabs.setBorder (b); + + this.tabs.setTabPlacement (p); + + } + + @Override + public AbstractSideBar getActiveOtherSideBar () + { + + if (this.activeSideBars.size () > 0) + { + + return this.activeSideBars.peek (); + + } + + return null; + + } + + private boolean isUILayoutShowSingleSidebar () + { + + String layout = this.getUILayout (); + + if (layout.equals (Constants.LEFT)) + { + + layout = Constants.LAYOUT_PS_CH; + + } + + if (layout.equals (Constants.RIGHT)) + { + + layout = Constants.LAYOUT_CH_PS; + + } + + return (layout.equals (Constants.LAYOUT_PS_CH) + || + layout.equals (Constants.LAYOUT_CH_PS)); + + } + + /** + * The layout is done in terms of preferred sizes and resize weights. + * We then call resetToPreferredSizes on the split panes to resize. + * The resize weights ensure that the tabs get all the extra space (without it one of the sidebars + * could get the space). Weights of 0.98f and 0.02f are used to ensure that the sidebars aren't shrunk below + * their current size (can't work out why it does that...) + * + * @{link splitpane2} is nested within the right half of {@link splitpane}. + * + * A zero sized filler is used to when a "half" isn't used to ensure that the relevant splitpane + * doesn't freak out. See {@link createLayoutFiller()}. + */ + public void setUILayout (String layout) + { + + if (this.proj == null) + { + + return; + + } + + final AbstractProjectViewer _this = this; + final AbstractSideBar other = this.currentOtherSideBar; + + final Dimension min = this.sideBar.getMinimumSize (); + + int ww = this.splitPane.getSize ().width; + + if (ww == 0) + { + + ww = this.proj.getPropertyAsInt (Constants.WINDOW_WIDTH_PROPERTY_NAME); + + } + + int sbw = this.savedSideBarWidth; + + if (sbw == 0) + { + + sbw = this.sideBar.getSize ().width; + + } else { + + this.savedSideBarWidth = 0; + + } + + if (sbw == 0) + { + + sbw = this.proj.getPropertyAsInt (Constants.PROJECT_SIDE_BAR_WIDTH_PROPERTY_NAME); + + if (sbw <= 0) + { + + // Legacy, pre-v2.3 + int spd = this.proj.getPropertyAsInt (Constants.SPLIT_PANE_DIVIDER_LOCATION_PROPERTY_NAME); + + if (spd > 0) + { + + sbw = spd; + + this.proj.removeProperty (Constants.PROJECT_SIDE_BAR_WIDTH_PROPERTY_NAME); + + } else { + + sbw = this.proj.getPropertyAsInt (Constants.PROJECT_SIDE_BAR_WIDTH_PROPERTY_NAME); + + } + + } + + if (sbw == 0) + { + + sbw = min.width; + + } + + } + + if (min.width > sbw) + { + + sbw = min.width; + + } + + int h = this.splitPane.getSize ().height; + + if (h == 0) + { + + h = 200; + + } + + int w = ww - sbw - INTERNAL_SPLIT_PANE_DIVIDER_WIDTH; + int ow = 0; + + if (other != null) + { + + ow = this.savedOtherSideBarWidth; + + if (ow == 0) + { + + ow = other.getMinimumSize ().width - INTERNAL_SPLIT_PANE_DIVIDER_WIDTH; + + } else { + + this.savedOtherSideBarWidth = 0; + + } + + w -= ow; + + other.setPreferredSize (new Dimension (ow, + h)); + + } + + //this.tabs.setPreferredSize (new Dimension (w, 100)); + + //this.sideBar.setPreferredSize (new Dimension (sbw, 200)); + + final int fw = w; + final int fow = ow; + final int fsbw = sbw; + + // Legacy, pre-2.3 + if (layout.equals (Constants.LEFT)) + { + + layout = Constants.LAYOUT_PS_CH; + + } + + if (layout.equals (Constants.RIGHT)) + { + + layout = Constants.LAYOUT_CH_PS; + + } + + if (layout.equals (Constants.LAYOUT_PS_CH_OS)) + { + + this.splitPane.setLeftComponent (this.sideBar); + this.splitPane.setDividerSize (INTERNAL_SPLIT_PANE_DIVIDER_WIDTH); + this.splitPane.setResizeWeight (0f); + this.splitPane.setDividerLocation (this.sideBar.getPreferredSize ().width); + + this.splitPane2.setLeftComponent (this.tabs); + this.splitPane2.setRightComponent (this.createLayoutFiller ()); + this.splitPane2.setDividerSize (0); + + this.sideBarWrapper.removeAll (); + this.sideBarWrapper.add (this.mainSideBar); + + this.splitPane.setDividerLocation (fsbw);//this.sideBar.getPreferredSize ().width); + + // Is a non-main sidebar visible? + if (other != null) + { + + this.splitPane2.setResizeWeight (1f); + this.splitPane2.setRightComponent (other); + this.splitPane2.setDividerSize (INTERNAL_SPLIT_PANE_DIVIDER_WIDTH); + this.splitPane2.setDividerLocation (fw); + + UIUtils.doLater (new ActionListener () + { + + public void actionPerformed (ActionEvent ev) + { + + // For reasons best known to swing this has to be done separately otherwise when + // you exit full screen it will have the other sidebar as taking up all the space. + _this.splitPane.setDividerLocation (fsbw); + _this.splitPane2.setDividerLocation (fw); + + _this.validate (); + _this.repaint (); + + } + + }); + + } + + } + + if (layout.equals (Constants.LAYOUT_OS_CH_PS)) + { + + this.splitPane.setLeftComponent (this.tabs); + this.splitPane.setResizeWeight (1f); + this.splitPane.setDividerSize (INTERNAL_SPLIT_PANE_DIVIDER_WIDTH); + + this.splitPane2.setLeftComponent (this.createLayoutFiller ()); + this.splitPane2.setRightComponent (this.sideBar); + this.splitPane2.setDividerSize (0); + + this.sideBarWrapper.removeAll (); + this.sideBarWrapper.add (this.mainSideBar); + + this.splitPane.setDividerLocation (fw); + + // Is a non-main sidebar visible? + if (other != null) + { + + this.splitPane.setResizeWeight (0); + this.splitPane2.setResizeWeight (1f); + + this.splitPane.setLeftComponent (other); + this.splitPane.setResizeWeight (0); + + this.splitPane2.setLeftComponent (this.tabs); + this.splitPane2.setDividerSize (INTERNAL_SPLIT_PANE_DIVIDER_WIDTH); + this.splitPane.setDividerLocation (fow); + this.splitPane2.setDividerLocation (fw); + + UIUtils.doLater (new ActionListener () + { + + public void actionPerformed (ActionEvent ev) + { + + // For reasons best known to swing this has to be done separately otherwise when + // you exit full screen it will have the other sidebar as taking up all the space. + _this.splitPane.setDividerLocation (fow); + _this.splitPane2.setDividerLocation (fw); + + _this.validate (); + _this.repaint (); + + } + + }); + + } + + } + + if (layout.equals (Constants.LAYOUT_PS_OS_CH)) + { + + this.splitPane.setLeftComponent (this.sideBar); + this.splitPane.setDividerSize (INTERNAL_SPLIT_PANE_DIVIDER_WIDTH); + this.splitPane.setResizeWeight (0f); + + this.splitPane2.setLeftComponent (this.createLayoutFiller ()); + this.splitPane2.setRightComponent (this.tabs); + //this.splitPane2.setResizeWeight (0.02f); + this.splitPane2.setDividerSize (0); + + this.sideBarWrapper.removeAll (); + this.sideBarWrapper.add (this.mainSideBar); + + this.splitPane.setDividerLocation (fsbw); + + // Is a non-main sidebar visible? + if (other != null) + { + + //this.splitPane.setResizeWeight (0.5f); + + this.splitPane2.setLeftComponent (other); + this.splitPane2.setDividerSize (INTERNAL_SPLIT_PANE_DIVIDER_WIDTH); + this.splitPane2.setResizeWeight (0f); + + this.splitPane2.setDividerLocation (fow); + this.splitPane.setDividerLocation (fsbw); + + UIUtils.doLater (new ActionListener () + { + + public void actionPerformed (ActionEvent ev) + { + + // For reasons best known to swing this has to be done separately otherwise when + // you exit full screen it will have the other sidebar as taking up all the space. + _this.splitPane2.setDividerLocation (fow); + _this.splitPane.setDividerLocation (fsbw); + + _this.validate (); + _this.repaint (); + + } + + }); + + } + + } + + if (layout.equals (Constants.LAYOUT_CH_OS_PS)) + { + + this.splitPane.setLeftComponent (this.tabs); + this.splitPane.setDividerSize (INTERNAL_SPLIT_PANE_DIVIDER_WIDTH); + + this.splitPane2.setLeftComponent (this.createLayoutFiller ()); + this.splitPane2.setRightComponent (this.sideBar); + this.splitPane2.setDividerSize (0); + + this.sideBarWrapper.removeAll (); + this.sideBarWrapper.add (this.mainSideBar); + + this.splitPane.setDividerLocation (fw); + + // Is a non-main sidebar visible? + if (other != null) + { + + this.splitPane.setResizeWeight (1f); + + this.splitPane2.setLeftComponent (other); + this.splitPane2.setDividerSize (INTERNAL_SPLIT_PANE_DIVIDER_WIDTH); + + this.splitPane2.setDividerLocation (fow); + this.splitPane.setDividerLocation (fw); + + UIUtils.doLater (new ActionListener () + { + + public void actionPerformed (ActionEvent ev) + { + + // For reasons best known to swing this has to be done separately otherwise when + // you exit full screen it will have the other sidebar as taking up all the space. + _this.splitPane2.setDividerLocation (fow); + _this.splitPane.setDividerLocation (fw); + + _this.validate (); + _this.repaint (); + + } + + }); + + } + + } + + if (layout.equals (Constants.LAYOUT_PS_CH)) + { + + this.splitPane.setLeftComponent (this.sideBar); + this.splitPane.setDividerSize (INTERNAL_SPLIT_PANE_DIVIDER_WIDTH); + this.splitPane.setResizeWeight (0f); + + this.splitPane2.setLeftComponent (this.tabs); + this.splitPane2.setResizeWeight (1f); + this.splitPane2.setRightComponent (this.createLayoutFiller ()); + this.splitPane2.setDividerSize (0); + + if (other != null) + { + + if (other.getMinimumSize ().width > sbw) + { + + sbw = other.getMinimumSize ().width; + + } + + this.sideBarWrapper.removeAll (); + this.sideBarWrapper.add (other); + + } else { + + if (this.mainSideBar != null) + { + + if (this.mainSideBar.getMinimumSize ().width > sbw) + { + + sbw = this.mainSideBar.getMinimumSize ().width; + + } + + this.sideBarWrapper.removeAll (); + this.sideBarWrapper.add (this.mainSideBar); + + } + + } + + final int fsbw2 = sbw; + + this.splitPane.setDividerLocation (sbw); + + UIUtils.doLater (new ActionListener () + { + + public void actionPerformed (ActionEvent ev) + { + + // For reasons best known to swing this has to be done separately otherwise when + // you exit full screen it will have the other sidebar as taking up all the space. + _this.splitPane.setDividerLocation (fsbw2); + + if (_this.isShowing ()) + { + + _this.validate (); + _this.repaint (); + + } + + } + + }); + + } + + if (layout.equals (Constants.LAYOUT_CH_PS)) + { + + w += ow; + + this.splitPane.setLeftComponent (this.tabs); + this.splitPane.setDividerSize (INTERNAL_SPLIT_PANE_DIVIDER_WIDTH); + this.splitPane.setResizeWeight (1f); + + this.splitPane2.setLeftComponent (this.sideBar); + this.splitPane2.setRightComponent (this.createLayoutFiller ()); + this.splitPane2.setDividerSize (0); + + if (other != null) + { + + if (other.getMinimumSize ().width > sbw) + { + + w = this.splitPane.getSize ().width - other.getMinimumSize ().width; + + } + + this.sideBarWrapper.removeAll (); + this.sideBarWrapper.add (other); + + } else { + + if (this.mainSideBar != null) + { + + if (this.mainSideBar.getMinimumSize ().width > sbw) + { + + w = this.splitPane.getSize ().width - this.mainSideBar.getMinimumSize ().width; + + } + + this.sideBarWrapper.removeAll (); + this.sideBarWrapper.add (this.mainSideBar); + + } + + } + + this.splitPane.setDividerLocation (w); + + final int fw2 = w; + + UIUtils.doLater (new ActionListener () + { + + public void actionPerformed (ActionEvent ev) + { + + // For reasons best known to swing this has to be done separately otherwise when + // you exit full screen it will have the other sidebar as taking up all the space. + _this.splitPane.setDividerLocation (fw2); + + _this.validate (); + _this.repaint (); + + } + + }); + + } + + this.layout = layout; + + } + + private String getUILayout () + { + + String sidebarLoc = UserProperties.get (Constants.SIDEBAR_LOCATION_PROPERTY_NAME); + + String uiLayout = Constants.LAYOUT_CH_PS; + + // Legacy, pre-v2.5 + if (sidebarLoc != null) + { + + if (sidebarLoc.equals (Constants.RIGHT)) + { + + uiLayout = Constants.LAYOUT_CH_PS; + + } + + UserProperties.remove (Constants.SIDEBAR_LOCATION_PROPERTY_NAME); + + } else { + + uiLayout = UserProperties.get (Constants.UI_LAYOUT_PROPERTY_NAME); + + } + + // Legacy, pre-2.5 + if (uiLayout.equals (Constants.LEFT)) + { + + uiLayout = Constants.LAYOUT_PS_CH; + + } + + if (uiLayout.equals (Constants.RIGHT)) + { + + uiLayout = Constants.LAYOUT_CH_PS; + + } + + return uiLayout; + + } + + protected void initWindow () + { + + if (this.proj == null) + { + + return; + + } + + this.setSpellCheckingEnabled (this.proj.getPropertyAsBoolean (Constants.SPELL_CHECKING_ENABLED_PROPERTY_NAME)); + + // Check the height and width and ensure they aren't too big. + // If they overrun the current screen size then reduce them down to 80% either way. + Dimension ss = Toolkit.getDefaultToolkit ().getScreenSize (); + + int wWidth = this.proj.getPropertyAsInt (Constants.WINDOW_WIDTH_PROPERTY_NAME); + + if (wWidth > ss.width) + { + + wWidth = (int) ((float) ss.width * 0.8f); + + } + + int wHeight = this.proj.getPropertyAsInt (Constants.WINDOW_HEIGHT_PROPERTY_NAME); + + if (wHeight > ss.height) + { + + wHeight = (int) ((float) ss.height * 0.8f); + + } + + this.splitPane.setPreferredSize (new Dimension (wWidth, + wHeight)); + + this.setSplitPaneColor (); + + this.setToolbarLocation (this.proj.getProperty (Constants.TOOLBAR_LOCATION_PROPERTY_NAME)); + + String sidebarLoc = UserProperties.get (Constants.SIDEBAR_LOCATION_PROPERTY_NAME); + + String uiLayout = this.getUILayout (); + + this.setUILayout (uiLayout); + + this.setTabsLocation (this.proj.getProperty (Constants.TABS_LOCATION_PROPERTY_NAME)); + + this.setViewerTitle (this.getViewerTitle ()); + + this.setIconImage (Environment.getWindowIcon ().getImage ()); + + //this.updateForDebugMode (); + + //this.pack (); + + // Allow the underlying Windowing manager determine where to put the window. + //this.setLocationByPlatform (true); + + //this.setVisible (true); + + //Environment.doNewsAndVersionCheck (this); + + if (this.isSpellCheckingEnabled ()) + { + + this.doForPanels (SpellCheckSupported.class, + new DefaultQuollPanelAction () + { + + public void doAction (QuollPanel p) + { + + SpellCheckSupported s = (SpellCheckSupported) p; + + s.checkSpelling (); + + } + + }); + + } + + } + + public void newProject (File saveDir, + Project p, + String filePassword) + throws Exception + { + + this.newProject (saveDir, + p, + filePassword, + null); + + } + + public void newProject (File saveDir, + Project p, + String filePassword, + ActionListener onOpen) + throws Exception + { + + + if (p == null) + { + + throw new GeneralException ("No project provided."); + + } + + if (p.getName () == null) + { + + throw new GeneralException ("No project name provided."); + + } + + this.setIgnoreProjectEvents (true); + this.proj.setFilePassword (filePassword); + + this.dBMan = Environment.createProject (saveDir.toPath (), + p); + + this.proj = this.dBMan.getProject (); + + if ((this.proj.getBooks () == null) || + (this.proj.getBooks ().size () == 0) || + (this.proj.getBooks ().get (0).getChapters ().size () == 0)) + { + + Book b = null; + + if ((this.proj.getBooks () != null) + && + (this.proj.getBooks ().size () > 0) + ) + { + + b = this.proj.getBooks ().get (0); + + } else { + + b = new Book (this.proj, + this.proj.getName ()); + + this.proj.addBook (b); + + this.saveObject (b, + true); + + } + + } + + this.proj.addPropertyChangedListener (this); + + this.targets = new TargetsData (this.proj.getProperties ()); + + // TODO REmove Environment.getAchievementsManager ().addProjectViewer (this); + + this.initSideBars (); + + this.initDictionaryProvider (); + + this.handleNewProject (); + + this.initChapterCounts (); + + this.setSpellCheckingEnabled (this.proj.getPropertyAsBoolean (Constants.SPELL_CHECKING_ENABLED_PROPERTY_NAME)); + + this.setSplitPaneColor (); + + this.startAutoBackups (); + + this.initWindow (); + + this.showMainSideBar (); + + //this.handleWhatsNew (); + + //this.handleShowTips (); + + this.setIgnoreProjectEvents (false); + + this.fireProjectEvent (this.proj.getObjectType (), + ProjectEvent.NEW); + + this.showViewer (); + + // Register ourselves with the environment. + try + { + + // TODO Environment.addOpenedProject (this); + + } catch (Exception e) + { + + Environment.logError ("Unable to add opened project (probably an error with the projects file): " + + this.proj, + e); + + } + + this.scheduleA4PageCountUpdate (); + + UIUtils.doLater (onOpen); + + } + + private void scheduleA4PageCountUpdate () + { + + final AbstractProjectViewer _this = this; + + // Generate the A4 page counts. + this.schedule (new Runnable () + { + + @Override + public void run () + { + + Book b = _this.proj.getBooks ().get (0); + + java.util.List chapters = b.getChapters (); + + for (Chapter c : chapters) + { + + String t = _this.getCurrentChapterText (c); + + ChapterCounts cc = _this.getChapterCounts (c); + + try + { + + cc.setStandardPageCount (UIUtils.getA4PageCountForChapter (c, + t)); + + } catch (Exception e) { + + // Just ignore any errors, it's next to impossible to stop them. + + } + + } + + } + + }, + 1, + 0); + + } + + public void setToolbarVisible (boolean v) + { + + this.toolbarPanel.setVisible (v); + + } + + public void openProject (ProjectInfo p, + String filePassword) + throws Exception + { + + this.openProject (p, + filePassword, + null); + + } + + public void openProject (ProjectInfo p, + String filePassword, + ActionListener onOpen) + throws Exception + { + + this.setIgnoreProjectEvents (true); + + // Get the username and password. + String username = UserProperties.get (Constants.DB_USERNAME_PROPERTY_NAME); + String password = UserProperties.get (Constants.DB_PASSWORD_PROPERTY_NAME); + + if (p.isNoCredentials ()) + { + + username = null; + password = null; + filePassword = null; + + } + + if (!p.isEncrypted ()) + { + + filePassword = null; + + } + + this.dBMan = new ObjectManager (); + + this.dBMan.init (new File (p.getProjectDirectory ().toFile ().getPath (), Constants.PROJECT_DB_FILE_NAME_PREFIX), + username, + password, + filePassword, + Environment.getSchemaVersion ()); + + Environment.incrStartupProgress (); + + // Get the project. + + try + { + + this.proj = this.dBMan.getProject (); + + } catch (Exception e) { + + // This means we can't open the project and something is wrong, close the dbman to prevent + // it locking the project open but unusable. + this.dBMan.closeConnectionPool (); + + throw e; + + } + + Environment.incrStartupProgress (); + + this.proj.setFilePassword (filePassword); + this.proj.setProjectDirectory (p.getProjectDirectory ().toFile ()); + this.proj.setBackupDirectory (p.getBackupDirPath ().toFile ()); + // TODO getBackupDirectory ()); + //this.proj.setFilePassword (filePassword); + this.proj.setEncrypted (p.isEncrypted ()); + this.proj.setNoCredentials (p.isNoCredentials ()); + + this.proj.addPropertyChangedListener (this); + + this.initChapterCounts (); + + this.targets = new TargetsData (this.proj.getProperties ()); + + Environment.incrStartupProgress (); + + // TODO Remove Environment.getAchievementsManager ().addProjectViewer (this); + + this.initSideBars (); + + this.initDictionaryProvider (); + + this.handleOpenProject (); + + Environment.incrStartupProgress (); + + final java.util.List inits = new ArrayList (); + + this.restoreTabs (); + + Environment.incrStartupProgress (); + + this.initWindow (); + + this.setSplitPaneColor (); + + // Init all the panels. + for (QuollPanel qp : this.panels.values ()) + { + + Runner r = this.getInitPanelStateRunner (qp, + (qp == this.getCurrentlyVisibleTab ())); + //lastOpen.equals (qp.getPanelId ())); + + // The init for the panel should have set it as ready for use so switch that off. + qp.setReadyForUse (false); + + if (r != null) + { + + inits.add (r); + + } + + } + + UIUtils.doLater (new ActionListener () + { + + public void actionPerformed (ActionEvent ev) + { + + for (Runner r : inits) + { + + r.run (); + + } + + } + + }); + + Environment.incrStartupProgress (); + + this.startAutoBackups (); + + this.scheduleAutoSaveForAllEditors (); + + Environment.incrStartupProgress (); + + this.dBMan.createActionLogEntry (this.proj, + "Opened project", + null, + null); + + final AbstractProjectViewer _this = this; + + // Check the font used for the project and inform the user if we don't have it. + // We do it here so it's done once. + String f = this.proj.getProperty (Constants.EDITOR_FONT_PROPERTY_NAME); + + if (f != null) + { + + Font ft = new Font (f, + Font.PLAIN, + 12); + + if (!ft.getFamily ().equalsIgnoreCase (f)) + { + + UIUtils.showMessage (this, + String.format (getUIString (fontunavailable,text), + f)); + //"The font " + f + " selected for use in {chapters} is not available on this computer.

    To select a new font, switch to a chapter tab then click here to change the text properties."); + + } + + } + + //this.handleWhatsNew (); + + //this.handleShowTips (); + + this.setIgnoreProjectEvents (false); + + this.fireProjectEvent (this.proj.getObjectType (), + ProjectEvent.OPEN); + + this.showViewer (); + + // Register ourselves with the environment. + try + { + + // TODO Environment.addOpenedProject (this); + + } catch (Exception e) + { + + Environment.logError ("Unable to add opened project: " + + this.proj, + e); + + } + + this.scheduleA4PageCountUpdate (); + + UIUtils.doLater (onOpen); + + // Check to see if any chapters have overrun the target. + UIUtils.doLater (new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + try + { + + int wc = _this.getProjectTargets ().getMaxChapterCount (); + + Set chaps = _this.getChaptersOverWordTarget (); + + int s = chaps.size (); + + if ((wc > 0) + && + (s > 0) + ) + { + + for (Chapter c : chaps) + { + + _this.chapterWordCountTargetWarned.put (c, + new Date ()); + + } + + final JLabel l = UIUtils.createLabel (null, + null, + null); + + String t = LanguageStrings.single; + + if (s > 1) + { + + t = LanguageStrings.multiple; + + } + + String text = String.format (getUIString (LanguageStrings.targets, chaptersoverwcmaximum, + t), + Environment.formatNumber (chaps.size ()), + //"%s {chapter}%s over the word count maximum of %s words, click to view the {chapter}%s.", + Environment.formatNumber (wc)); + + l.setText (text); + + final Notification n = _this.addNotification (l, + Constants.WORDCOUNT_ICON_NAME, + 90); + + UIUtils.makeClickable (l, + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + Targets.showChaptersOverWordTarget (_this, + n); + + n.removeNotification (); + + } + + }); + + } + + chaps = _this.getChaptersOverReadabilityTarget (); + + s = chaps.size (); + + if (s > 0) + { + + String t = LanguageStrings.single; + + if (s > 1) + { + + t = LanguageStrings.multiple; + + } + + final JLabel l = UIUtils.createLabel (null, + null, + null); + + String text = String.format (getUIString (LanguageStrings.targets, chaptersoverreadabilitymaximum,t), + //"%s {chapter}%s over one of the readability targets, click to view the {chapter}%s.", + Environment.formatNumber (chaps.size ())); + //(s == 1 ? " is" : "s are"), + //(s == 1 ? "" : "s")); + + l.setText (text); + + final Notification n = _this.addNotification (l, + Constants.READABILITY_ICON_NAME, + 90); + + UIUtils.makeClickable (l, + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + Targets.showChaptersOverReadabilityTarget (_this, + n); + + n.removeNotification (); + + } + + }); + + } + + } catch (Exception e) { + + Environment.logError ("Unable to display chapters over target notification", + e); + + } + + } + + }); + + this.schedule (new Runnable () + { + + @Override + public void run () + { + + try + { + + int wc = _this.getProjectTargets ().getMaxChapterCount (); + + if ((wc > 0) + && + (_this.getProjectTargets ().isShowMessageWhenMaxChapterCountExceeded ()) + ) + { + + Book b = _this.proj.getBooks ().get (0); + + final Set over = new LinkedHashSet (); + + java.util.List chapters = b.getChapters (); + + Date d = new Date (); + + // 15 minutes ago. + long last = System.currentTimeMillis () - 15 * 60 * 1000; + + for (Chapter c : chapters) + { + + ChapterCounts cc = _this.getChapterCounts (c); + + final Chapter _c = c; + + if (cc.getWordCount () > wc) + { + + if (!_this.chapterWordCountTargetWarned.containsKey (c)) + { + + _this.chapterWordCountTargetWarned.put (c, + new Date ()); + + over.add (c); + + } + + } else { + + Date od = _this.chapterWordCountTargetWarned.get (c); + + // Only remove if it's been 15 minutes since we last warned the user. + // This provides a buffer so that they aren't constantly nagged about + // it going over, for example if they've deleted/edited a sentence, removed + // a word or two to go below the target then added some back in. + if ((od != null) + && + (od.getTime () < last) + ) + { + + _this.chapterWordCountTargetWarned.remove (c); + + } + + } + + } + + if (over.size () > 0) + { + + // Show a message. + UIUtils.doLater (new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + final int s = over.size (); + + final QPopup popup = UIUtils.createClosablePopup (getUIString (LanguageStrings.targets, LanguageStrings.popup,title), + //String.format ("{Chapter}%s over word count target", + //(s == 1 ? "" : "s")), + Environment.getIcon (Constants.WORDCOUNT_ICON_NAME, + Constants.ICON_POPUP), + null); +/* + String text = String.format ("%s {chapter}%s over the target word count, click to view them.", + Environment.formatNumber (s), + (s == 1 ? " is" : "s are")); +*/ + String text = null; + + if (s == 1) + { + + Chapter c = over.iterator ().next (); + + text = String.format (getUIString (LanguageStrings.targets, LanguageStrings.popup,singleoverlimit), + c.getName ()); + + //text = String.format ("{Chapter} %s is over the target word count, click to view it.", + // c.getName ()); + + } else { + + text = String.format (getUIString (LanguageStrings.targets, LanguageStrings.popup,multipleoverlimit), + Environment.formatNumber (s)); + + } + + Box content = new Box (BoxLayout.Y_AXIS); + + ActionListener showChapter = new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + Targets.showChaptersOverWordTarget (_this, + null); + + popup.removeFromParent (); + + } + + }; + + JLabel l = UIUtils.createLabel (text, + null, + showChapter); + + l.setBorder (UIUtils.createPadding (0, 0, 10, 0)); + + content.setBorder (UIUtils.createPadding (10, 10, 10, 10)); + + content.add (l); + + JButton cb = UIUtils.createButton (getUIString (buttons,close)); + + JButton sb = UIUtils.createButton (getUIString (buttons,showdetail), + //"Show detail", + showChapter); + + JButton[] buts = { sb, cb }; + + JComponent bs = UIUtils.createButtonBar2 (buts, + Component.CENTER_ALIGNMENT); + bs.setAlignmentX (Component.LEFT_ALIGNMENT); + + content.add (bs); + + cb.addActionListener (popup.getCloseAction ()); + popup.setRemoveOnClose (true); + + popup.setContent (content); + + popup.setDraggable (_this); + + popup.resize (); + + _this.showPopupAt (popup, + new Point (10, 10), + false); + + } + + }); + + } + + } + + } catch (Exception e) { + + Environment.logError ("Unable to determine chapters that are over target", + e); + + } + + } + + }, + 30 * 1000, + 5 * 1000); + + } + + public void saveProjectTargets () + { + + try + { + + this.saveObject (this.proj, + false); + + } catch (Exception e) { + + Environment.logError ("Unable to update project targets", + e); + + } + + } + + public TargetsData getProjectTargets () + { + + return this.targets; + + } + + private void startAutoBackups () + { + + final AbstractProjectViewer _this = this; + + this.schedule (new Runnable () + { + + public void run () + { + + try + { + + // Get references first so that they can't change further on. + Project proj = _this.proj; + ObjectManager dBMan = _this.dBMan; + + if ((proj == null) + || + (dBMan == null) + ) + { + + return; + + } + + if (proj.getPropertyAsBoolean (Constants.AUTO_SNAPSHOTS_ENABLED_PROPERTY_NAME)) + { + + // Get the last backup. + Path last = dBMan.getLastBackupFile (proj); + + long lastDate = (last != null ? last.toFile ().lastModified () : proj.getDateCreated ().getTime ()); + + if ((System.currentTimeMillis () - lastDate) > Utils.getTimeAsMillis (proj.getProperty (Constants.AUTO_SNAPSHOTS_TIME_PROPERTY_NAME))) + { + +/* +TODO Moved to new BackupsManager. + Environment.createBackupForProject (proj, + false); +*/ + UIUtils.doLater (new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + try + { + + _this.addNotification (String.format (getUIString (backups,autobackupnotification), + //"An automatic backup has been created. Click to view the backups.", + Constants.ACTION_PROTOCOL, + Constants.BACKUPS_HTML_PANEL_ACTION), + Constants.INFO_ICON_NAME, + 30); + + } catch (Exception e) { + + // Sigh... + + } + + } + + }); + + } + + } + + } catch (Exception e) { + + if (_this.proj == null) + { + + // Means we have shutdown. + return; + + } + + Environment.logError ("Unable to create backup for project: " + + _this.proj, + e); + + } + + } + + }, + // Start straight away. + 0, + // Run every 10 mins. + 10 * 60 * 1000); + + } + + /** + * Given a list of comma separated object ids, open the panels for the objects (if available). + * So an example ids might be: chapter-1,character-2,chapter-3. + * This will be parsed into 3 values and then the relevant objects searched for in the project. + * If there is an associated object then it will be opened for viewing. + * + * @param ids The object ids, comma separated. + */ + public void openPanelsFromObjectIdList (String ids) + { + + if ((ids == null) + || + (ids.trim ().equals ("")) + ) + { + + return; + + } + + java.util.List objIds = new ArrayList (); + + // Split on : + StringTokenizer t = new StringTokenizer (ids, + ","); + + while (t.hasMoreTokens ()) + { + + String tok = t.nextToken ().trim (); + + objIds.add (tok); + + } + + Collections.reverse (objIds); + + for (String panelId : objIds) + { + + ObjectReference r = null; + + try + { + + r = ObjectReference.parseObjectReference (panelId); + + } catch (Exception e) + { + + Environment.logError ("Unable to parse: " + + panelId, + e); + + continue; + + } + + // Pass it to the project. + final DataObject d = this.proj.getObjectForReference (r); + + if (d == null) + { + + if (!this.openPanelInt (panelId)) + { + + Environment.logError ("Unable to open panel for id: " + + panelId); + + continue; + + } + + } else + { + + if (!this.viewObject (d)) + { + + continue; + + } + + } + + } + + + } + + public String getOpenTabsProperty () + { + + ProjectVersion pv = this.proj.getProjectVersion (); + + String suffix = ""; + + // See if we have a project version. + if (pv != null) + { + + suffix = ":" + pv.getKey (); + + } + + // Setup the tabs. + String openTabs = this.proj.getProperty (Constants.OPEN_TABS_PROPERTY_NAME + suffix); + + return openTabs; + + } + + /** + * Responsible for setting up the panels that should be open when the project is opened. + * If you override this method ensure that you do: + * * Open the necessary panels. + * * Call this.initWindow to restore the window state. + * * Set the last opened tab (after opening it). + */ + protected void restoreTabs () + { + + ProjectVersion pv = this.proj.getProjectVersion (); + + String suffix = ""; + + // See if we have a project version. + if (pv != null) + { + + suffix = ":" + pv.getKey (); + + } + + // Setup the tabs. + String openTabs = this.getOpenTabsProperty (); + + this.openPanelsFromObjectIdList (openTabs); + + String lastOpen = this.proj.getProperty (Constants.LAST_OPEN_TAB_PROPERTY_NAME + suffix); + + if (lastOpen != null) + { + + final QuollPanel qp = this.getQuollPanel (lastOpen); + + if (qp != null) + { + + this.setPanelVisible (qp); + + } + + } + + } + + private void initDictionaryProvider () + { + + final String lang = this.getSpellCheckLanguage (); + + try + { + + if (!DictionaryProvider.isLanguageInstalled (lang)) + { + + final AbstractProjectViewer _this = this; + + // Turn off spell checking until the download is complete. + this.setSpellCheckLanguage (null, + true); + + // Download them. + this.downloadDictionaryFiles (this.getSpellCheckLanguage (), + new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + try + { + + _this.setSpellCheckLanguage (null, + true); + + _this.setSpellCheckLanguage (lang, + true); + + } catch (Exception e) { + + Environment.logError ("Unable to set spell check language to: " + + lang, + e); + + UIUtils.showErrorMessage (_this, + String.format (getUIString (spellchecker,unabletosetlanguage), + lang)); + //"Unable to set spell check language to " + + //lang + + //".

    Please contact Quoll Writer support for assistance."); + + } + + } + + }); + + } else { + + this.setSpellCheckLanguage (lang, + true); + + } + + } catch (Exception e) { + + Environment.logError ("Unable to check for spell check language", + e); + + } + + } + + public void downloadDictionaryFiles (String lang, + final ActionListener onComplete) + { + + UIUtils.downloadDictionaryFiles (lang, + this, + onComplete); + + } + + private void initPanelState (QuollPanel qp) + { + + Runner r = this.getInitPanelStateRunner (qp, + true); + + if (r != null) + { + + try + { + + r.run (); + + } catch (Exception e) { + + Environment.logError ("Unable to init panel: " + + qp.getPanelId (), + e); + + } + + } + + } + + private Runner getInitPanelStateRunner (final QuollPanel qp, + final boolean visible) + { + + final String panelId = qp.getPanelId (); + + final String state = this.proj.getProperty (panelId + "-state"); + + if (state != null) + { + + final AbstractProjectViewer _this = this; + + // Need to "do later" since it won't always set the state correctly for + // none visible tabs. + return new Runner () + { + + public void run () + { + + qp.setState (UIUtils.parseState (state), + visible); + + qp.setReadyForUse (true); + + } + + }; + + } + + return null; + + } + + public void handleHTMLPanelAction (String v) + { + + try + { + + if (v.equals (Constants.BACKUPS_HTML_PANEL_ACTION)) + { + + UIUtils.showManageBackups (Environment.getProjectInfo (this.proj), + this); + + return; + + } + + if (v.equals ("textproperties")) + { + + QuollPanel qp = this.getCurrentlyVisibleTab (); + + if (qp instanceof AbstractEditorPanel) + { + + ((AbstractEditorPanel) qp).showTextProperties (); + + } + + return; + + } + + if (v.equals ("find")) + { + + this.showFind (null); + + return; + + } + + if (v.equals ("spellcheckoff")) + { + + this.setSpellCheckingEnabled (false); + + return; + + } + + if (v.equals ("spellcheckon")) + { + + this.setSpellCheckingEnabled (true); + + return; + + } + + if (v.equals ("statistics")) + { + + this.viewStatistics (); + + return; + + } + + if (v.equals ("wordcounts")) + { + + this.viewWordCounts (); + + return; + + } + + if (v.equals ("wordcounthistory")) + { + + this.viewStatistics (); + + return; + + } + + if (v.equals ("projectoptions")) + { + + this.showOptions ("project"); + + return; + + } + + if (v.equals ("dictionarymanager")) + { + + this.showDictionaryManager (); + + return; + + } + + if (v.equals ("enabletypewritersound")) + { +/* +TODO Use property. + boolean old = Environment.isPlaySoundOnKeyStroke (); + + Environment.setPlaySoundOnKeyStroke (true); + + Environment.playKeyStrokeSound (); + + Environment.setPlaySoundOnKeyStroke (old); +*/ + return; + + } + + if (v.equals ("fullscreen")) + { + + try + { + + this.enterFullScreen (); + + } catch (Exception e) { + + Environment.logError ("Unable to show in full screen mode", + e); + + } + + return; + + } + + if (v.equals ("projectsidebar")) + { + + this.showMainSideBar (); + + return; + + } + + super.handleHTMLPanelAction (v); + + } catch (Exception e) { + + Environment.logError ("Unable to perform action: " + + v, + e); + + } + + } + + public boolean viewAchievements () + { + + // Check our tabs to see if we are already viewing the word counts, if so then just switch to it instead. + AchievementsPanel ap = (AchievementsPanel) this.getQuollPanel (AchievementsPanel.PANEL_ID); + + if (ap != null) + { + + this.setPanelVisible (ap); + + this.fireProjectEvent (ProjectEvent.ACHIEVEMENTS, + ProjectEvent.SHOW); + + return true; + + } + + try + { + + ap = new AchievementsPanel (this); + + ap.init (); + + } catch (Exception e) + { + + Environment.logError ("Unable to view achievements: " + + this.proj, + e); + + UIUtils.showErrorMessage (this, + getUIString (achievementspanel,actionerror)); + //"Unable to view achievements"); + + return false; + + } + + this.addPanel (ap); + + // Open the tab :) + return this.viewAchievements (); + + } + + private boolean openPanelInt (String id) + { + + if (id.equals (OptionsPanel.PANEL_ID)) + { + + return this.showOptions (); + + } + + if (id.equals (StatisticsPanel.PANEL_ID)) + { + + return this.viewStatistics (); + + } + + if (id.equals (StatisticsPanel.OLD_WORD_COUNT_PANEL_ID)) + { + + return this.viewStatistics (); + + } + + if (id.equals (AchievementsPanel.PANEL_ID)) + { + + return this.viewAchievements (); + + } + + return this.openPanel (id); + + } + + public Project getProject () + { + + return this.proj; + + } + + protected JScrollPane createTreeScroll (JTree tree) + { + + return UIUtils.createTreeScroll (tree); + + } + + protected JTree createTree () + { + + return UIUtils.createTree (); + + } + + protected void closeAllTabs (boolean saveState) + { + + if (saveState) + { + + try + { + + this.saveState (); + + } catch (Exception e) { + + Environment.logError ("Unable to save state", + e); + + } + + } + + // Regardless of whether it should be saved call the close method + // for the panel to allow it to close itself nicely. + // Close after state so we can keep track of what is open. + + // Duplicate the values so we don't get a modification error for this.panels. + Set qpps = new LinkedHashSet (this.panels.values ()); + + for (QuollPanel qp : qpps) + { + + this.closePanel (qp); + + } + + } + + private boolean closeInternal (boolean saveUnsavedChanges, + ActionListener afterClose) + { + + if (saveUnsavedChanges) + { + + // Save all. + for (QuollPanel qp : this.panels.values ()) + { + + if (qp instanceof ProjectObjectQuollPanel) + { + + ProjectObjectQuollPanel pqp = (ProjectObjectQuollPanel) qp; + + if (pqp.hasUnsavedChanges ()) + { + + boolean showError = true; + + try + { + + showError = !pqp.saveUnsavedChanges (); + + } catch (Exception e) + { + + Environment.logError ("Unable to save unsaved changes for: " + + pqp.getForObject (), + e); + + } + + if (showError) + { + + UIUtils.showErrorMessage (this, + String.format (getUIString (closeproject,actionerror), + pqp.getTitle ())); + //"Unable to save: " + + //pqp.getTitle () + + //", aborting exit."); + + // Switch to the tab. + this.viewObject (pqp.getForObject ()); + + return false; + + } + + } + + } + + } + + } + + //this.notifications.setVisible (false); + + this.removeAllNotifications (); + + this.closeAllTabs (true); + + // Close all sidebars. + // TODO: Fix this up + for (AbstractSideBar sb : new ArrayList (this.activeSideBars)) + { + + this.removeSideBar (sb); + + } + + this.proj.setLastEdited (new Date ()); + + try + { + + this.saveProject (); + + } catch (Exception e) + { + + Environment.logError ("Unable to save project: " + + this.proj, + e); + + return false; + + } + + this.proj.removePropertyChangedListener (this); + + ChapterDataHandler ch = (ChapterDataHandler) this.dBMan.getHandler (Chapter.class); + + ch.saveWordCounts (this.proj, + this.sessionStart, + new Date ()); + + this.dBMan.createActionLogEntry (this.proj, + "Closed project", + null, + null); + + // Fire our last event. + this.fireProjectEvent (this.proj.getObjectType (), + ProjectEvent.CLOSE); + + // TODO Environment.getAchievementsManager ().removeViewer (this); + + // Close all the db connections. + this.dBMan.closeConnectionPool (); + + try + { +/* +TODO + Environment.projectClosed (this, + !(afterClose != null)); +*/ + } catch (Exception e) + { + + Environment.logError ("Unable to close project", + e); + + Environment.showAllProjectsViewer (); + //Environment.showLanding (); + + return false; + + } + + super.close (false, + afterClose); + + return true; + + } + + @Override + public boolean close (boolean noConfirm, + final ActionListener afterClose) + { + + final StringBuilder b = new StringBuilder (); + + this.exitFullScreen (); + + boolean save = false; + + if (noConfirm) + { + + save = true; + + } + + if (!noConfirm) + { + + boolean hasChanges = false; + + for (QuollPanel qp : this.panels.values ()) + { + + if (qp instanceof ProjectObjectQuollPanel) + { + + ProjectObjectQuollPanel pqp = (ProjectObjectQuollPanel) qp; + + if (pqp.hasUnsavedChanges ()) + { + + hasChanges = true; + + if (pqp.getForObject () instanceof NamedObject) + { + + b.append ("
  • " + pqp.getTitle () + "
  • "); + + } + + } + + } + + } + + if (hasChanges) + { + + final AbstractProjectViewer _this = this; + + Map buttons = new LinkedHashMap (); + + buttons.put (getUIString (LanguageStrings.buttons,savechanges), + //"Yes, save the changes", + new ActionListener () + { + + public void actionPerformed (ActionEvent ev) + { + + _this.closeInternal (true, + afterClose); + + } + + }); + + buttons.put (getUIString (LanguageStrings.buttons,discardchanges), + //"No, discard the changes", + new ActionListener () + { + + public void actionPerformed (ActionEvent ev) + { + + _this.closeInternal (false, + afterClose); + + } + + }); + + buttons.put (getUIString (LanguageStrings.buttons,cancel), + null); + + UIUtils.createQuestionPopup (this, + getUIString (closeproject,confirmpopup,title), + //"Save changes before exiting?", + Constants.SAVE_ICON_NAME, + String.format (getUIString (closeproject,confirmpopup,text), + //"The following items have unsaved changes (click on an item to go to the relevant tab):
      %s
    Do you wish to save the changes before exiting?", + b.toString ()), + buttons, + null, + null); + + return false; + + } + + } + + return this.closeInternal (true, + afterClose); + + } + + public FullScreenFrame getFullScreenFrame () + { + + return this.fsf; + + } + + public boolean isCurrentSideBarTextProperties () + { + + if (this.currentOtherSideBar != null) + { + + return this.currentOtherSideBar.getId ().equals (TextPropertiesSideBar.ID); + + } + + return false; + + } + + public void showTextProperties () + throws GeneralException + { + + if (!this.sideBars.containsKey (TextPropertiesSideBar.ID)) + { +/* +TODO + this.addSideBar (new TextPropertiesSideBar (this, + this, + Environment.getProjectTextProperties ())); +*/ + } + + this.showSideBar (TextPropertiesSideBar.ID); + + } + + public QuollPanel getCurrentlyVisibleTab () + { + + if (this.isInFullScreen ()) + { + + // Return the panel being displayed. + return this.fsf.getPanel ().getChild (); + + } + + Component sel = this.tabs.getSelectedComponent (); + + if (sel instanceof QuollPanel) + { + + return (QuollPanel) sel; + + } + + return null; + + } + + /** + * Return the name of the property that is used to save the open tabs, this is needed because is the project + * has a project version object then the name of the property will change. + * + * @return The open tabs property name in the form {@link Constants.OPENS_TAB_PROPERTY_NAME} + [":" + project version key]. + */ + public String getOpenTabsPropertyName () + { + + // See if we have a project version. + ProjectVersion pv = this.proj.getProjectVersion (); + + String suffix = ""; + + if (pv != null) + { + + suffix = ":" + pv.getKey (); + + } + + return Constants.OPEN_TABS_PROPERTY_NAME + suffix; + + } + + private void saveState () + throws GeneralException + { + + if (this.proj == null) + { + + return; + + } + + // Get the state from the sidebars. + for (AbstractSideBar sb : this.sideBars.values ()) + { + + String id = sb.getId (); + + if (id == null) + { + + continue; + + } + + try + { + + this.proj.setProperty ("sidebarState-" + id, + sb.getSaveState ()); + + } catch (Exception e) { + + Environment.logError ("Unable to save state for sidebar: " + + id, + e); + + } + + } + + // Set the open tab ids. + + QuollPanel vqp = this.getCurrentlyVisibleTab (); + + String panelId = null; + + if (vqp != null) + { + + panelId = vqp.getPanelId (); + + } + + // See if we have a project version. + ProjectVersion pv = this.proj.getProjectVersion (); + + String suffix = ""; + + if (pv != null) + { + + suffix = ":" + pv.getKey (); + + } + + // Save it. + try + { + + this.proj.setProperty (Constants.LAST_OPEN_TAB_PROPERTY_NAME + suffix, + panelId); + + } catch (Exception e) + { + + throw new GeneralException ("Unable to save open tab id for project: " + + this.proj, + e); + + } + + StringBuilder openTabs = new StringBuilder (); + + for (int i = 0; i < this.tabs.getTabCount (); i++) + { + + Component p = this.tabs.getComponentAt (i); + + if (p instanceof QuollPanel) + { + + // TODO: Change to add a flag in the QuollPanel of whether it should be persisted. + if (p instanceof HelpTextPanel) + { + + continue; + + } + + QuollPanel qp = (QuollPanel) p; + + panelId = qp.getPanelId (); + + if (openTabs.length () > 0) + { + + openTabs.append (","); + + } + + openTabs.append (panelId); + + } + + } + + try + { + + this.proj.setProperty (this.getOpenTabsPropertyName (), + openTabs.toString ()); + + } catch (Exception e) + { + + throw new GeneralException ("Unable to save open tab ids for project: " + + this.proj, + e); + + } + + // We've drastically changed the size of things due to closing tabs and potentially the + // notifications so validate to ensure the sizes have changed. + this.validate (); + + // Save the size of the window (more specifically the size of the split pane. + try + { + + this.proj.setProperty (Constants.WINDOW_HEIGHT_PROPERTY_NAME, + this.splitPane.getSize ().height); + + this.proj.setProperty (Constants.WINDOW_WIDTH_PROPERTY_NAME, + this.splitPane.getSize ().width); + + this.proj.setProperty (Constants.PROJECT_SIDE_BAR_WIDTH_PROPERTY_NAME, + this.sideBar.getSize ().width); + this.proj.setProperty (Constants.SPELL_CHECKING_ENABLED_PROPERTY_NAME, + this.spellCheckingEnabled); + + } catch (Exception e) + { + + throw new GeneralException ("Unable to save open tab ids for project: " + + this.proj, + e); + + } + + this.doSaveState (); + + this.saveProject (); + + } + + public java.util.List getObjectsForReferences (String objRefs) + { + + java.util.List objs = new ArrayList (); + + StringTokenizer t = new StringTokenizer (objRefs, + ","); + + while (t.hasMoreTokens ()) + { + + String tok = t.nextToken ().trim (); + + ObjectReference r = null; + + try + { + + r = ObjectReference.parseObjectReference (tok); + + } catch (Exception e) + { + + Environment.logError ("Unable to parse: " + + tok, + e); + + continue; + + } + + // Pass it to the project. + DataObject d = this.proj.getObjectForReference (r); + + if (d == null) + { + + continue; + + } + + objs.add (d); + + } + + return objs; + + } + + public Component getVisiblePanel () + { + + return this.tabs.getSelectedComponent (); + + } + + public void enterFullScreen () + { + + try + { + + this.showInFullScreen (this.getCurrentlyVisibleTab ()); + + } catch (Exception e) { + + Environment.logError ("Unable to show in full screen", + e); + + UIUtils.showErrorMessage (this, + getUIString (fullscreen,actionerror)); + //"Unable to enter full screen mode"); + + } + + } + + public void fullScreenClosed (QuollPanel vis) + { + + this.fsf = null; + + this.fullScreenOverlay.setVisible (false); + + DnDTabbedPane p = this.createTabbedPane (); + + // Have to rebuild the tabbed pane because otherwise it behaves weirdly. + for (int i = this.tabs.getTabCount () - 1; i > -1; i--) + { + + Component title = this.tabs.getTabComponentAt (i); + Component body = this.tabs.getComponentAt (i); + + this.tabs.remove (i); + + this.tabs.add (body, + i); + this.tabs.setTabComponentAt (i, + title); + + } + + try + { + + this.tabs.setSelectedComponent (vis); + + } catch (Exception e) { + + // May not exist, don't care. + + } + + this.tabs.setVisible (true); + + if (vis instanceof AbstractEditorPanel) + { + + AbstractEditorPanel edPanel = (AbstractEditorPanel) vis; + + QTextEditor ed = edPanel.getEditor (); + + edPanel.scrollCaretIntoView (); + + ed.grabFocus (); + + } + + // xxx + this.setExtendedState (NORMAL); + + this.setVisible (true); + this.setUILayout (this.layout); + this.validate (); + this.repaint (); + + this.fireFullScreenExitedEvent (); + + } + + public void restoreFromFullScreen (FullScreenQuollPanel qp) + { + + for (int i = 0; i < this.tabs.getTabCount (); i++) + { + + Component comp = this.tabs.getComponentAt (i); + + if (comp == qp) + { + + this.tabs.setComponentAt (i, + qp.getChild ()); + + qp.getChild ().setVisible (true); + + this.tabs.revalidate (); + this.tabs.repaint (); + this.validate (); + this.repaint (); + + return; + + } + + } + + this.tabs.setVisible (true); + + } + + public boolean isInFullScreen () + { + + return this.fsf != null; + + } + + public void showInFullScreen (QuollPanel qep) + throws GeneralException + { + + if (this.fsf == null) + { + + // Need to get the divider location. + this.lastDividerLocation = this.splitPane.getDividerLocation (); + + } + + if (this.fullScreenOverlay == null) + { + + this.fullScreenOverlay = new FullScreenOverlay (this); + + this.setGlassPane (this.fullScreenOverlay); + + } + + this.fullScreenOverlay.setVisible (true); + + if (this.fsf != null) + { + + if (this.fsf.getPanel ().getChild () == qep) + { + + // Nothing to do, it's already showing, maybe bring to front. + this.fsf.toFront (); + + return; + + } + + } + + if (qep == null) + { + + qep = new BlankQuollPanel (this, + "fullscreen-blank"); + + qep.init (); + + } + + if (this.currentOtherSideBar != null) + { + + this.savedOtherSideBarWidth = this.currentOtherSideBar.getSize ().width; + + } + + if (this.mainSideBar != null) + { + + this.savedSideBarWidth = this.mainSideBar.getSize ().width; + + } + + FullScreenQuollPanel fs = new FullScreenQuollPanel (qep); + + int tabInd = this.getTabIndexForPanelId (qep.getPanelId ()); + + if (tabInd > -1) + { + + // Need to set the component, otherwise it will be removed. + this.tabs.setComponentAt (tabInd, + fs); + + } + + if (this.fsf != null) + { + + this.fsf.switchTo (fs); + + } else + { + + this.fsf = new FullScreenFrame (fs, + this); + + this.fsf.init (); + + // Need to set the tabs hidden otherwise the parent qw window will flash in front + // or show up in front of the fsf. + this.tabs.setVisible (false); + + } + + //this.fsf.toFront (); + + this.tabs.revalidate (); + this.tabs.repaint (); + this.validate (); + this.repaint (); + + this.setVisible (false); + + this.fireFullScreenEnteredEvent (); + + final AbstractProjectViewer _this = this; + + UIUtils.doLater (new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + if (_this.fsf != null) + { + + _this.fsf.toFront (); + + } + + } + + }); + + } + + public void showInFullScreen (DataObject n) + throws GeneralException + { + + // Are we already in fs mode? + if (this.fsf != null) + { + + if (this.fsf.getCurrentForObject () == n) + { + + // Nothing to do, it's already showing, maybe bring to front. + this.fsf.toFront (); + + return; + + } else + { + + this.viewObject (n); + + } + + } + + if (this.fullScreenOverlay == null) + { + + this.fullScreenOverlay = new FullScreenOverlay (this); + + this.setGlassPane (this.fullScreenOverlay); + + } + + this.fullScreenOverlay.setVisible (true); + + this.lastDividerLocation = this.splitPane.getDividerLocation (); + + AbstractEditorPanel qep = this.getEditorForChapter ((Chapter) n); + + if (qep != null) + { + + FullScreenQuollPanel fs = new FullScreenQuollPanel (qep); + + // Need to set the component, otherwise it will be removed. + this.tabs.setComponentAt (this.getTabIndexForPanelId (qep.getPanelId ()), + fs); + + if (this.fsf != null) + { + + this.fsf.switchTo (fs); + + } else + { + + this.fsf = new FullScreenFrame (fs, + this); + + this.fsf.init (); + + } + + //this.fsf.toFront (); + + this.tabs.revalidate (); + this.tabs.repaint (); + this.validate (); + this.repaint (); + + } + + this.setVisible (false); + + this.fireFullScreenEnteredEvent (); + + } + + public ProjectObjectQuollPanel getQuollPanelForObject (DataObject n) + { + + for (QuollPanel qp : this.panels.values ()) + { + + ProjectObjectQuollPanel pqp = null; + + if (qp instanceof FullScreenQuollPanel) + { + + FullScreenQuollPanel fqp = (FullScreenQuollPanel) qp; + + if (fqp.getChild () instanceof ProjectObjectQuollPanel) + { + + pqp = (ProjectObjectQuollPanel) fqp.getChild (); + + } + + } + + // This is getting silly... + // TODO: Fix this up. + if (qp instanceof ProjectObjectQuollPanel) + { + + pqp = (ProjectObjectQuollPanel) qp; + + } + + if ((pqp != null) + && + (pqp.getForObject () == n) + ) + { + + return pqp; + + } + + } + + return null; + + } + + public java.util.List getAllQuollPanelsForObject (DataObject n) + { + + java.util.List ret = new ArrayList (); + + for (QuollPanel qp : this.panels.values ()) + { + + if (qp instanceof ProjectObjectQuollPanel) + { + + ProjectObjectQuollPanel pqp = (ProjectObjectQuollPanel) qp; + + if (pqp.getForObject () == n) + { + + ret.add (pqp); + + } + + } + + } + + return ret; + + } + + public QuollPanel getQuollPanel (String panelId) + { + + return this.panels.get (panelId); + + } + + protected void setPanelVisible (QuollPanel qp) + { + + this.updateToolbarForPanel (qp); + + if (!this.inFullScreen ()) + { + + this.tabs.setSelectedComponent (qp); + this.tabs.revalidate (); + this.tabs.repaint (); + + } else { + + try + { + + this.showInFullScreen (qp); + + } catch (Exception e) { + + Environment.logError ("Unable to show panel: " + qp + + " in full screen", + e); + + UIUtils.showErrorMessage (this, + getUIString (fullscreen,showpanelactionerror)); + //"Unable to show in full screen"); + + } + + } + + this.fireMainPanelShownEvent (qp); + + } + + protected int getTabIndexForObject (NamedObject n) + { + + return this.getTabIndexForPanelId (n.getObjectReference ().asString ()); + + } + + protected int getTabIndexForPanelId (String panelId) + { + + for (int i = 0; i < this.tabs.getTabCount (); i++) + { + + Component comp = this.tabs.getComponentAt (i); + + if (comp instanceof QuollPanel) + { + + QuollPanel qp = (QuollPanel) comp; + + if (qp.getPanelId ().equals (panelId)) + { + + return i; + + } + + } + + } + + return -1; + + } + + public void setTabHeaderTitle (QuollPanel qp, + String title) + { + + int ind = this.getTabIndexForPanelId (qp.getPanelId ()); + + if (ind < 0) + { + + // No current tab for this panel. + return; + + } + + TabHeader th = (TabHeader) this.tabs.getTabComponentAt (ind); + + if (th != null) + { + + th.setTitle (title); + + } + + } + + public TabHeader addPanel (final QuollPanel qp) + { + + final AbstractProjectViewer _this = this; + + final TabHeader th = new TabHeader (this.tabs, + Environment.getIcon (Constants.CANCEL_ICON_NAME, + Constants.ICON_TAB_HEADER), + Environment.getTransparentImage (), + qp.getTitle ()); + + th.setIcon (qp.getIcon (Constants.ICON_TAB_HEADER)); + + final String panelId = qp.getPanelId (); + + this.panels.put (panelId, + qp); + + th.addActionListener (new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + if (ev.getID () == TabHeader.TAB_CLOSING) + { + + if (!_this.closePanel (qp)) + { + + VetoableActionEvent vev = (VetoableActionEvent) ev; + + vev.cancel (); + + } + + } + + } + + }); + + if (qp instanceof ProjectObjectQuollPanel) + { + + qp.addActionListener (new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + if (ev.getID () == ProjectObjectQuollPanel.UNSAVED_CHANGES_ACTION_EVENT) + { + + if (ev.getActionCommand ().equals (ProjectObjectQuollPanel.HAS_CHANGES_COMMAND)) + { + + th.setComponentChanged (true); + + } + + if (ev.getActionCommand ().equals (ProjectObjectQuollPanel.NO_CHANGES_COMMAND)) + { + + th.setComponentChanged (false); + + } + + } + + if (ev.getID () == ProjectObjectQuollPanel.SAVED) + { + + th.setComponentChanged (false); + + } + + } + + }); + + } + + this.tabs.add (qp, + 0); + this.tabs.setTabComponentAt (0, + th); + + this.initPanelState (qp); + + return th; + + } + + public boolean closePanel (NamedObject n) + { + + QuollPanel qp = this.getQuollPanel (n.getObjectReference ().asString ()); + + if (qp == null) + { + + return false; + + } + + return this.closePanel (qp); + + } + + public boolean closePanel (QuollPanel qp) + { + + // Get the state. + Map m = new LinkedHashMap (); + + qp.getState (m); + + String panelId = qp.getPanelId (); + + if (m.size () > 0) + { + + try + { + + this.proj.setProperty (panelId + "-state", + UIUtils.createState (m)); + + } catch (Exception e) + { + + Environment.logError ("Unable to save state for panel: " + + panelId, + e); + + } + + } + + final AbstractProjectViewer _this = this; + + if (qp instanceof ProjectObjectQuollPanel) + { + + final ProjectObjectQuollPanel p = (ProjectObjectQuollPanel) qp; + + final ActionListener remove = new ActionListener () + { + + public void actionPerformed (ActionEvent ev) + { + + NamedObject n = p.getForObject (); + + if (p != null) + { + + if ((_this.fsf != null) + && + (p == _this.fsf.getPanel ().getChild ()) + ) + { + + // In full screen, restore first. + _this.restoreFromFullScreen (_this.fsf.getPanel ()); + + // Add a blank instead. + _this.fsf.showBlankPanel (); + + } + + _this.removePanel (p); + + // Remove all the property changed listeners. + java.util.List l = p.getObjectPropertyChangedListeners (); + + if (l != null) + { + + for (PropertyChangedListener c : l) + { + + n.removePropertyChangedListener (c); + + } + + } + + } + + } + + }; + + // Object already deleted, don't ask the question. + if ((p.getForObject ().getKey () != null) + && + (!this.proj.hasObject (p.getForObject ())) + ) + { + + remove.actionPerformed (new ActionEvent (this, + 0, + "deleted")); + + return true; + + } + + if (p.hasUnsavedChanges ()) + { + + UIUtils.createQuestionPopup (this, + getUIString (closepanel,confirmpopup,title), + //"Save before closing?", + Constants.SAVE_ICON_NAME, + String.format (getUIString (closepanel,confirmpopup,text), + p.getTitle ()), + //"The %s has unsaved changes. Save before closing?", + //Environment.getObjectTypeName (p.getForObject ())), + getUIString (closepanel,confirmpopup,buttons,save), + //"Yes, save the changes", + getUIString (closepanel,confirmpopup,buttons,discard), + //"No, discard the changes", + new ActionListener () + { + + public void actionPerformed (ActionEvent ev) + { + + try + { + + if (!p.saveUnsavedChanges ()) + { + + return; + + } + + } catch (Exception e) + { + + // What the hell to do here??? + Environment.logError ("Unable to save: " + + p.getForObject (), + e); + + UIUtils.showErrorMessage (_this, + getUIString (closepanel,actionerror)); + //"Unable to save " + + //Environment.getObjectTypeName (p.getForObject ())); + + return; + + } + + remove.actionPerformed (ev); + + } + + }, + new ActionListener () + { + + public void actionPerformed (ActionEvent ev) + { + + remove.actionPerformed (ev); + + } + + }, + new ActionListener () + { + + public void actionPerformed (ActionEvent ev) + { + + if (!p.hasUnsavedChanges ()) + { + + remove.actionPerformed (ev); + + } + + } + + }, + null); + + return false; + + } + + remove.actionPerformed (new ActionEvent (this, + 0, + "deleted")); + + return true; + + } + + return this.removePanel (qp); + + } + + protected void informTreeOfNodeChange (NamedObject n, + JTree tree) + { + + DefaultTreeModel model = (DefaultTreeModel) tree.getModel (); + + DefaultMutableTreeNode node = (DefaultMutableTreeNode) UIUtils.getTreePathForUserObject ((DefaultMutableTreeNode) model.getRoot (), + n).getLastPathComponent (); + + model.nodeChanged (node); + + tree.validate (); + tree.repaint (); + + } + + @Override + public void addPopup (Component c, + boolean hideOnClick, + boolean hideViaVisibility) + { + + if (this.fsf != null) + { + + this.fsf.addPopup (c, + hideOnClick, + hideViaVisibility); + + return; + + } + + super.addPopup (c, + hideOnClick, + hideViaVisibility); + + } + + @Override + public void removePopup (Component c) + { + + if (this.fsf != null) + { + + this.fsf.removePopup (c); + + return; + + } + + super.removePopup (c); + + } + + @Override + public void showAchievement (AchievementRule ar) + { + + if (this.fsf != null) + { + + this.fsf.showAchievement (ar); + + return; + + } + + super.showAchievement (ar); + + } + + @Override + public QPopup getPopupByName (String name) + { + + if (this.fsf != null) + { + + return this.fsf.getPopupByName (name); + + } + + return super.getPopupByName (name); + + } + + @Override + public void showPopupAt (Component popup, + Component showAt, + boolean hideOnParentClick) + { + + if (this.fsf != null) + { + + this.fsf.showPopupAt (popup, + showAt, + hideOnParentClick); + + return; + + } + + super.showPopupAt (popup, + showAt, + hideOnParentClick); + + } + + @Override + public void showPopupAt (Component c, + Point p, + boolean hideOnParentClick) + { + + if (this.fsf != null) + { + + this.fsf.showPopupAt (c, + p, + hideOnParentClick); + + return; + + } + + super.showPopupAt (c, + p, + hideOnParentClick); + + } + + public boolean removePanel (NamedObject n) + { + + return this.removePanel (n.getObjectReference ().asString ()); + + } + + public void removeAllSideBarsForObject (NamedObject n) + { + + Set sbs = new HashSet<> (); + + sbs.addAll (this.sideBars.values ()); + + for (AbstractSideBar s : sbs) + { + + if (n == s.getForObject ()) + { + + this.removeSideBar (s); + + } + + } + + } + + public void removeAllPanelsForObject (NamedObject n) + { + + for (ProjectObjectQuollPanel p : this.getAllQuollPanelsForObject (n)) + { + + this.removePanel (p); + + } + + } + + private boolean removePanel (String panelId) + { + + QuollPanel p = this.getQuollPanel (panelId); + + if (p == null) + { + + return false; + + } + + return this.removePanel (p); + + } + + public boolean removePanel (final QuollPanel p) + { + + p.close (); + + String panelId = p.getPanelId (); + + int tInd = this.getTabIndexForPanelId (panelId); + + if (tInd > -1) + { + + this.tabs.removeTabAt (tInd); + + } + + this.panels.remove (panelId); + + return true; + + } + + public ObjectManager getObjectManager () + { + + return this.dBMan; + + } + + public DataHandler getDataHandler (Class clazz) + throws GeneralException + { + + if (this.dBMan == null) + { + + return null; + + } + + return this.dBMan.getHandler (clazz); + + } + + public void refreshViewPanel (NamedObject n) + { + + ProjectObjectQuollPanel p = this.getQuollPanelForObject (n); + + if (p != null) + { + + p.refresh (); + + } + + } + + public void refreshObjectPanels (final Set objs) + { + + final AbstractProjectViewer _this = this; + + if ((objs != null) && + (objs.size () > 0)) + { + + UIUtils.doLater (new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + // For each one determine if it is visible. + for (NamedObject n : objs) + { + + ProjectObjectQuollPanel qp = _this.getQuollPanelForObject (n); + + if (qp != null) + { + + qp.refresh (); + + } + + } + + } + + }); + + } + + } + + public void deleteLinks (NamedObject o, + boolean doInTransaction) + throws GeneralException + { + + java.util.Set otherObjects = o.getOtherObjectsInLinks (); +/* + this.dBMan.deleteLinks (o, + null); +*/ + this.refreshObjectPanels (otherObjects); + + } + + public void saveLinks (NamedObject o, + Set newLinks) + throws GeneralException + { + +/* +TODO + // Do it here to get all the links that may be removed. + java.util.Set otherObjects = o.getOtherObjectsInLinks (); + + this.dBMan.updateLinks (o, + newLinks); + + // Do it here to get all the links that may be added. + otherObjects.addAll (o.getOtherObjectsInLinks ()); + + this.refreshObjectPanels (otherObjects); +*/ + } + + public void saveObject (NamedObject o, + boolean doInTransaction) + throws GeneralException + { + + if (o == null) + { + + return; + + } + + java.util.Set otherObjects = o.getOtherObjectsInLinks (); + + if (this.dBMan == null) + { + + throw new IllegalStateException ("No object manager available."); + + } + + this.dBMan.saveObject (o, + null); + + this.refreshObjectPanels (otherObjects); + + } + + public void saveObjects (java.util.List objs, + boolean doInTransaction) + throws GeneralException + { + + this.dBMan.saveObjects (objs, + null); + + } + + public void saveProject () + throws GeneralException + { + + this.dBMan.saveObject (this.proj, + null); + + } + + public void setLinks (NamedObject o) + { + + try + { + + this.dBMan.getLinks (o); + + } catch (Exception e) + { + + Environment.logError ("Unable to set links for: " + + o, + e); + + } + + } + + public void propertyChanged (PropertyChangedEvent ev) + { + + DataObject d = (DataObject) ev.getSource (); + + if (d instanceof Project) + { + + Project p = (Project) d; + + try + { + + this.saveObject (p, + true); + + } catch (Exception e) + { + + Environment.logError ("Unable to save project: " + + p, + e); + + } + + } + + } + + public boolean isSpellCheckingEnabled () + { + + return this.spellCheckingEnabled; + + } + + public void setSpellCheckingEnabled (final boolean v) + { + + this.spellCheckingEnabled = v; + + this.doForPanels (SpellCheckSupported.class, + new DefaultQuollPanelAction () + { + + public void doAction (QuollPanel qp) + { + + SpellCheckSupported s = (SpellCheckSupported) qp; + + s.setSpellCheckingEnabled (v); + + } + + }); + + this.fireProjectEvent (ProjectEvent.SPELL_CHECK, + (v ? ProjectEvent.ON : ProjectEvent.OFF)); + + } + + public void createActionLogEntry (NamedObject n, + String m) + { + + this.dBMan.createActionLogEntry (n, + m, + null, + null); + + } + + public boolean inFullScreen () + { + + return this.fsf != null; + + } + + public ReadabilityIndices getReadabilityIndices (Chapter c) + { + + AbstractEditorPanel qep = this.getEditorForChapter (c); + + ReadabilityIndices ri = null; + + if (qep != null) + { + + ri = qep.getReadabilityIndices (); + + if (ri != null) + { + + this.noEditorReadabilityIndices.remove (c); + + return ri; + + } + + } + + ri = this.noEditorReadabilityIndices.get (c); + + if (ri == null) + { + + // Cache the value. + ri = this.getReadabilityIndices (c.getChapterText ()); + + this.noEditorReadabilityIndices.put (c, + ri); + + } + + return ri; + + } + + public ChapterCounts getChapterCounts (Chapter c) + { + + return this.chapterCounts.get (c); + + } + + public ReadabilityIndices getAllReadabilityIndices () + { + + if (this.proj == null) + { + + return null; + + } + + Book b = this.proj.getBooks ().get (0); + + java.util.List chapters = b.getChapters (); + + ReadabilityIndices ri = new ReadabilityIndices (); + + for (Chapter c : chapters) + { + + ri.add (this.getReadabilityIndices (c)); + + } + + return ri; + + } + + private void initChapterCounts () + { + + if (this.proj == null) + { + + return; + + } + + if (this.proj.getBooks ().size () == 0) + { + + return; + + } + + Book b = this.proj.getBooks ().get (0); + + java.util.List chapters = b.getChapters (); + + for (Chapter c : chapters) + { + + this.updateChapterCounts (c); + + } + + this.startWordCounts = this.getAllChapterCounts (); + + } + + public String getCurrentChapterText (Chapter c) + { + + AbstractEditorPanel qep = this.getEditorForChapter (c); + + String t = null; + + if (qep != null) + { + + t = qep.getEditor ().getText (); + + } else { + + t = (c.getText () != null ? c.getText ().getText () : null); + + } + + return t; + + } + + public void updateChapterCounts (final Chapter c) + { + + final AbstractProjectViewer _this = this; + + final String t = this.getCurrentChapterText (c); + + final ChapterCounts cc = new ChapterCounts (t); + + ChapterCounts _cc = this.getChapterCounts (c); + + if (_cc != null) + { + + cc.setStandardPageCount (_cc.getStandardPageCount ()); + + } + + this.chapterCounts.put (c, + cc); + + if (!Environment.startupCompleteProperty ().getValue ()) + { + + return; + + } + + // Don't try and calculate the a4 page count before the window is ready otherwise + // strange errors result. The initChapterCounts and scheduleA4PageCountUpdate will handle the initial counts. + this.unschedule (this.chapterCountsUpdater); + + Runnable r = new Runnable () + { + + @Override + public void run () + { + + try + { + + cc.setStandardPageCount (UIUtils.getA4PageCountForChapter (c, + t)); + + } catch (Exception e) { + + Environment.logError ("Unable to get a4 page count for chapter: " + + c, + e); + + } + + } + + }; + + this.chapterCountsUpdater = _this.schedule (r, + // Start in 2 seconds + 2 * Constants.SEC_IN_MILLIS, + // Do it once. + 0); + + } + + public int getChapterA4PageCount (Chapter c) + { + + return UIUtils.getA4PageCountForChapter (c, + this.getCurrentChapterText (c)); + + } + + public ChapterCounts getAllChapterCounts () + { + + ChapterCounts all = new ChapterCounts (); + + for (ChapterCounts cc : this.chapterCounts.values ()) + { + + all.add (cc); + + } + + return all; + + } + + public Set getAllChapterCountsAsSet () + { + + return new LinkedHashSet (this.chapterCounts.values ()); + + } + + private Book getBookCurrentlyEdited () + { + + Chapter c = this.getChapterCurrentlyEdited (); + + if (c != null) + { + + return c.getBook (); + + } + + return this.proj.getBook (0); + + } + + public Chapter getChapterCurrentlyEdited () + { + + Component sel = this.getCurrentlyVisibleTab (); + + if (sel instanceof AbstractEditorPanel) + { + + // Get the id. + AbstractEditorPanel qep = (AbstractEditorPanel) sel; + + // Get the chapter. + return qep.getChapter (); + + } + + return null; + + } + + public boolean showOptions () + { + + return this.showOptions (null); + + } + + public boolean showOptions (final String section) + { + + OptionsPanel p = (OptionsPanel) this.getQuollPanel (OptionsPanel.PANEL_ID); + + if (p == null) + { + + try + { + + p = new OptionsPanel (this, + Options.Section.project, + Options.Section.look, + Options.Section.naming, + Options.Section.editing, + Options.Section.assets, + Options.Section.start, + Options.Section.editors, + Options.Section.itemsAndRules, + Options.Section.warmups, + Options.Section.achievements, + Options.Section.problems, + Options.Section.betas, + Options.Section.website); + + p.init (); + + } catch (Exception e) + { + + Environment.logError ("Unable to view the options", + e); + + UIUtils.showErrorMessage (this, + getUIString (options,actionerror)); + //"Unable to view the options"); + + return false; + + } + + this.addPanel (p); + + } + + this.setPanelVisible (p); + + final OptionsPanel pp = p; + + if (section != null) + { + + UIUtils.doActionWhenPanelIsReady (p, + new ActionListener () + { + + public void actionPerformed (ActionEvent ev) + { + + pp.showSection (section); + + } + + }, + null, + null); + + } + + return true; + + } + + @Override + public boolean showChart (String chartType) + throws GeneralException + { + + if (this.viewStatistics ()) + { + + StatisticsPanel sp = (StatisticsPanel) this.getQuollPanel (StatisticsPanel.PANEL_ID); + + sp.showChart (chartType); + + return true; + + } + + return false; + + } + + /** + * This is a top-level action so it can handle showing the user a message, it returns a boolean to indicate + * whether the word count history is viewed. + */ + public boolean viewStatistics () + { + + // Check our tabs to see if we are already viewing the word counts, if so then just switch to it instead. + StatisticsPanel wcp = (StatisticsPanel) this.getQuollPanel (StatisticsPanel.PANEL_ID); + + if (wcp != null) + { + + this.setPanelVisible (wcp); + + this.fireProjectEvent (ProjectEvent.STATISTICS, + ProjectEvent.SHOW); + + return true; + + } + + try + { + + wcp = new StatisticsPanel (this, + new PerChapterWordCountsChart (this), + new AllWordCountsChart (this), + new ReadabilityIndicesChart (this), + new SessionWordCountChart (this), + new SessionTimeChart (this)); + + wcp.init (); + + wcp.showChart (PerChapterWordCountsChart.CHART_TYPE); + + } catch (Exception e) + { + + Environment.logError ("Unable to view word counts: " + + this.proj, + e); + + UIUtils.showErrorMessage (this, + getUIString (statistics,actionerror)); + //"Unable to view statistics panel."); + + return false; + + } + + this.addPanel (wcp); + + // Open the tab :) + return this.viewStatistics (); + + } + + /** + * Determine the number of words written for this project during this session. + * + * @return The current word count - the start word count. + */ + public int getSessionWordCount () + { + + return this.getAllChapterCounts ().getWordCount () - this.startWordCounts.getWordCount (); + + } + + public ChapterCounts getStartWordCounts () + { + + return this.startWordCounts; + + } + + public Set snapshotChapters (Set chapters, + ProjectVersion pv) + throws Exception + { + + ChapterDataHandler ch = (ChapterDataHandler) this.dBMan.getHandler (Chapter.class); + + return ch.snapshot (chapters, + pv); + + } + + @Override + public void sendMessageToEditor (final EditorEditor ed) + throws GeneralException + { + + this.viewEditors (); + + final AbstractProjectViewer _this = this; + + UIUtils.doLater (new ActionListener () + { + + public void actionPerformed (ActionEvent ev) + { +/* +TODO Remove + EditorsSideBar sb = (EditorsSideBar) _this.sideBars.get (EditorsSideBar.ID); + + if (sb == null) + { + + Environment.logError ("Cant get editors sidebar?"); + + return; + + } + + try + { + + sb.showChatBox (ed); + + } catch (Exception e) { + + Environment.logError ("Unable to show editor: " + + ed, + e); + + UIUtils.showErrorMessage (_this, + getUIString (editors,vieweditorerror)); + //"Unable to show Editor"); + + } +*/ + } + + }); + + } + + @Override + public void viewEditor (final EditorEditor ed) + throws GeneralException + { + + this.viewEditors (); + + final AbstractProjectViewer _this = this; + + UIUtils.doLater (new ActionListener () + { + + public void actionPerformed (ActionEvent ev) + { +/* +TODO Remove + EditorsSideBar sb = (EditorsSideBar) _this.sideBars.get (EditorsSideBar.ID); + + if (sb == null) + { + + Environment.logError ("Cant get editors sidebar?"); + + return; + + } + + try + { + + sb.showEditor (ed); + + } catch (Exception e) { + + Environment.logError ("Unable to show editor: " + + ed, + e); + + UIUtils.showErrorMessage (_this, + getUIString (editors,vieweditorerror)); + //"Unable to show Editor"); + + } +*/ + } + + }); + + } + + @Override + public boolean viewEditors () + throws GeneralException + { + + // See if the user has an account or has already registered, if so show the sidebar + // otherwise show the register. + if (!EditorsEnvironment.hasRegistered ()) + { + + try + { + + // TODO Remove EditorsUIUtils.showRegister (this); + + } catch (Exception e) { + + Environment.logError ("Unable to show editor register", + e); + + UIUtils.showErrorMessage (this, + getUIString (editors,showregistererror)); + //"Unable to show the editors register panel, please contact Quoll Writer support for assistance."); + + return false; + + } + + return true; + + } +/* +TODO remove + AbstractSideBar sb = this.sideBars.get (EditorsSideBar.SIDEBAR_ID); + + if (sb == null) + { + + sb = new EditorsSideBar (this); + + this.addSideBar (sb); + + } + + this.showSideBar (EditorsSideBar.SIDEBAR_ID); +*/ + return true; + + } + + /** + * Set a chapter as edit complete. + * + * Note: this is NOT the right place for this method however there isn't currently a better + * place. It is here because the editor panel may need to use the function and the chapter + * tree might, however the editor panel may not actually exist and putting it in the chapter + * tree means that the chapter tree needs knowledge of panels which isn't correct either (but is worse). + * + * @param chapter The chapter to mark as edit complete. + * @param editComplete Whether the chapter is edit complete or not. + */ + public void setChapterEditComplete (Chapter chapter, + boolean editComplete) + { + + try + { + + chapter.setEditComplete (editComplete); + + AbstractEditorPanel p = (AbstractEditorPanel) this.getEditorForChapter (chapter); + + int pos = 0; + + if (p != null) + { + + pos = Utils.stripEnd (p.getEditor ().getText ()).length (); + + } else { + + String t = (chapter.getText () != null ? chapter.getText ().getText () : ""); + + pos = Utils.stripEnd (t).length (); + + } + + chapter.setEditPosition (pos); + + this.saveObject (chapter, + false); + + this.reloadTreeForObjectType (Chapter.OBJECT_TYPE); + + } catch (Exception e) { + + Environment.logError ("Unable to set chapter edit complete: " + + chapter, + e); + + java.util.List prefix = Arrays.asList (project,editorpanel,actions); + + UIUtils.showErrorMessage (this, + getUIString (prefix,seteditcomplete,actionerror)); + + } + + } + + public void setChapterEditPosition (Chapter chapter, + int textPos) + throws Exception + { + + AbstractEditorPanel p = (AbstractEditorPanel) this.getEditorForChapter (chapter); + + int l = 0; + + if (p != null) + { + + l = Utils.stripEnd (p.getEditor ().getText ()).length (); + + textPos = Math.min (textPos, l); + + // See if we are on the last line (it may be that the user is in the icon + // column). + Rectangle pp = p.getEditor ().modelToView (textPos); + + if (UserProperties.getAsBoolean (Constants.SET_CHAPTER_AS_EDIT_COMPLETE_WHEN_EDIT_POSITION_IS_AT_END_OF_CHAPTER_PROPERTY_NAME)) + { + + if (textPos <= l) + { + + Rectangle ep = p.getEditor ().modelToView (l); + + chapter.setEditComplete ((ep.y == pp.y)); + + } + + } + + } else { + + String t = (chapter.getText () != null ? chapter.getText ().getText () : ""); + + l = Utils.stripEnd (t).length (); + + } + + textPos = Math.min (textPos, l); + + chapter.setEditPosition (textPos); + + this.saveObject (chapter, + false); + + this.reloadTreeForObjectType (Chapter.OBJECT_TYPE); + + } + + public void removeChapterEditPosition (Chapter chapter) + { + + try + { + + chapter.setEditComplete (false); + chapter.setEditPosition (-1); + + this.saveObject (chapter, + false); + + this.reloadTreeForObjectType (Chapter.OBJECT_TYPE); + + } catch (Exception e) { + + Environment.logError ("Unable to remove edit position for chapter: " + + chapter, + e); + + java.util.List prefix = Arrays.asList (project,editorpanel,actions); + + UIUtils.showErrorMessage (this, + getUIString (prefix,removeeditposition,actionerror)); + + } + + } + + @Override + public boolean isEditorsVisible () + { + + return this.isEditorsSideBarVisible (); + + } + + public boolean isEditorsSideBarVisible () + { +/* +TODO REmove + EditorsSideBar sb = (EditorsSideBar) this.sideBars.get (EditorsSideBar.ID); + + if (sb != null) + { + + return sb.isShowing (); + + } +*/ + return false; + + } + + public ProjectVersion getProjectVersion (String name) + throws GeneralException + { + + java.util.List pvs = (java.util.List) this.dBMan.getObjects (ProjectVersion.class, + null, + null, + false); + + for (ProjectVersion pv : pvs) + { + + if (pv.getName ().equalsIgnoreCase (name)) + { + + return pv; + + } + + } + + return null; + + } + + public Set getNotesForVersion (ProjectVersion pv) + throws GeneralException + { + + NoteDataHandler ndh = (NoteDataHandler) this.dBMan.getHandler (Note.class); + + return ndh.getNotesForVersion (pv, + null); + + } + + public Set getDealtWithNotes (ProjectVersion pv, + boolean isDealtWith) + throws GeneralException + { + + NoteDataHandler ndh = (NoteDataHandler) this.dBMan.getHandler (Note.class); + + return ndh.getDealtWith (pv, + isDealtWith, + null); + + } + + @Override + public void showHelpText (String title, + String text, + String iconType, + String helpTextId) + { + + this.addHelpTextTab (title, + text, + iconType, + helpTextId); + + } + + public void addHelpTextTab (String title, + String text, + String iconType, + String panelId) + { + + HelpTextPanel p = new HelpTextPanel (this, + title, + text, + iconType, + panelId); + + p.init (); + + this.addPanel (p); + + this.setPanelVisible (p); + + } + + @Override + public JComponent getTitleHeaderControl (String id) + { + + if (id == null) + { + + return null; + + } + + java.util.List prefix = Arrays.asList (project,title,toolbar,buttons); + + final AbstractProjectViewer _this = this; + + JComponent c = null; + + if (id.equals (FIND_HEADER_CONTROL_ID)) + { + + return UIUtils.createButton (Constants.FIND_ICON_NAME, + Constants.ICON_TITLE_ACTION, + getUIString (prefix,find,tooltip), + //"Click to open the find", + new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + _this.showFind (null); + + } + + }); + + } + + if (id.equals (CLOSE_HEADER_CONTROL_ID)) + { + + return UIUtils.createButton (Constants.CLOSE_ICON_NAME, + Constants.ICON_TITLE_ACTION, + getUIString (prefix,close,tooltip), + //"Click to close", + new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + _this.close (false, + null); + + } + + }); + + } + + if (id.equals (FULL_SCREEN_HEADER_CONTROL_ID)) + { + + return UIUtils.createButton (Constants.FULLSCREEN_ICON_NAME, + Constants.ICON_TITLE_ACTION, + getUIString (prefix,fullscreen,tooltip), + //"Click to work in full screen mode", + new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + _this.enterFullScreen (); + + } + + }); + + } + + return super.getTitleHeaderControl (id); + + } + + @Override + public Set getTitleHeaderControlIds () + { + + Set ids = new LinkedHashSet (); + + ids.add (CONTACTS_HEADER_CONTROL_ID); + ids.add (FIND_HEADER_CONTROL_ID); + ids.add (FULL_SCREEN_HEADER_CONTROL_ID); + ids.add (SETTINGS_HEADER_CONTROL_ID); + + return ids; + + } + + public void scheduleAutoSaveForAllEditors () + { + + this.unschedule (this.autoSaveTask); + + this.autoSaveTask = null; + + if (this.proj.getPropertyAsBoolean (Constants.CHAPTER_AUTO_SAVE_ENABLED_PROPERTY_NAME)) + { + + Properties props = Environment.getDefaultProperties (Project.OBJECT_TYPE); + + final long autoSaveInt = Utils.getTimeAsMillis (props.getProperty (Constants.CHAPTER_AUTO_SAVE_INTERVAL_PROPERTY_NAME)); + + if (autoSaveInt > 0) + { + + final AbstractProjectViewer _this = this; + + // Create our auto save + Runnable r = new Runnable () + { + + @Override + public void run () + { + + try + { + + _this.doForPanels (AbstractEditableEditorPanel.class, + new QuollPanelAction () + { + + @Override + public void doAction (AbstractEditableEditorPanel p) + { + + if (!p.hasUnsavedChanges ()) + { + + return; + + } + + try + { + + p.saveChapter (); + + } catch (Exception e) + { + + Environment.logError ("Unable to auto save chapter: " + + p.getChapter (), + e); + + } + + } + + }); + + } catch (Exception e) { + + Environment.logError ("Unable update panels", + e); + + } + + } + + }; + + this.autoSaveTask = this.schedule (r, + autoSaveInt, + autoSaveInt); + + } + + } + + } + + /** + * Display the targets for the project. + * + */ + public void viewTargets () + throws GeneralException + { + + TargetsSideBar t = new TargetsSideBar (this); + + this.addSideBar (t); + + this.showSideBar (TargetsSideBar.ID); + + } + + public boolean hasUnsavedChapters () + { + + for (QuollPanel qp : this.panels.values ()) + { + + if (qp instanceof AbstractEditorPanel) + { + + AbstractEditorPanel ep = (AbstractEditorPanel) qp; + + if (ep.hasUnsavedChanges ()) + { + + return true; + + } + + } + + } + + return false; + + } + + public Set getChaptersOverReadabilityTarget () + { + + Set chaps = new LinkedHashSet (); + + if (this.getProject () == null) + { + + // Closing down. + return chaps; + + } + + TargetsData projTargets = this.getProjectTargets (); + + int tFK = projTargets.getReadabilityFK (); + int tGF = projTargets.getReadabilityGF (); + + if ((tFK > 0) + || + (tGF > 0) + ) + { + + for (Book book : this.getProject ().getBooks ()) + { + + for (Chapter c : book.getChapters ()) + { + + ReadabilityIndices ri = this.getReadabilityIndices (c); + + ChapterCounts cc = this.getChapterCounts (c); + + if (cc.getWordCount () < Constants.MIN_READABILITY_WORD_COUNT) + { + + continue; + + } + + float fk = ri.getFleschKincaidGradeLevel (); + float gf = ri.getGunningFogIndex (); + + if ((tFK > 0) + && + (ri.getFleschKincaidGradeLevel () > tFK) + ) + { + + chaps.add (c); + + continue; + + } + + if ((tGF > 0) + && + (ri.getGunningFogIndex () > tGF) + ) + { + + chaps.add (c); + + continue; + + } + + } + + } + + } + + return chaps; + + } + + public Set getChaptersOverWordTarget () + { + + Set chaps = new LinkedHashSet (); + + if (this.getProject () == null) + { + + // Closing down. + return chaps; + + } + + TargetsData projTargets = this.getProjectTargets (); + + int tcc = projTargets.getMaxChapterCount (); + + if (tcc > 0) + { + + for (Book book : this.getProject ().getBooks ()) + { + + for (Chapter c : book.getChapters ()) + { + + ChapterCounts count = this.getChapterCounts (c); + + if (count.getWordCount () > tcc) + { + + chaps.add (c); + + } + + } + + } + + } + + return chaps; + + } + + public Map> getProblemsForAllChapters () + { + + return this.getProblemsForAllChapters (null); + + } + + public Map> getProblemsForAllChapters (Rule limitToRule) + { + + Map> probs = new LinkedHashMap (); + + if (this.getProject () == null) + { + + // Closing down. + return probs; + + } + + for (Book book : this.getProject ().getBooks ()) + { + + for (Chapter c : book.getChapters ()) + { + + Set issues = null; + + if (limitToRule != null) + { + + issues = this.getProblems (c, + limitToRule); + + } else { + + issues = this.getProblems (c); + + } + + if (issues.size () > 0) + { + + probs.put (c, issues); + + } + + } + + } + + return probs; + + } + + public Set getProblems (Chapter c, + Rule r) + { + + Set ret = new LinkedHashSet (); + + String ct = this.getCurrentChapterText (c); + + if (ct != null) + { + + TextBlockIterator ti = new TextBlockIterator (ct); + + TextBlock b = null; + + while ((b = ti.next ()) != null) + { + + java.util.List issues = RuleFactory.getIssues (b, + r, + this.proj.getProperties ()); + + for (Issue i : issues) + { + + ret.add (i); + + i.setChapter (c); + + } + + } + + } + + return ret; + + } + + public Set getProblems (Chapter c) + { + + Set ret = new LinkedHashSet (); + + String ct = this.getCurrentChapterText (c); + + if (ct != null) + { + + TextBlockIterator ti = new TextBlockIterator (ct); + + TextBlock b = null; + + while ((b = ti.next ()) != null) + { + + if (b instanceof Paragraph) + { + + ret.addAll (RuleFactory.getParagraphIssues ((Paragraph) b, + this.proj.getProperties ())); + + } + + if (b instanceof Sentence) + { + + ret.addAll (RuleFactory.getSentenceIssues ((Sentence) b, + this.proj.getProperties ())); + + } + + } + + } + + return ret; + + } + + public Set getSpellingErrors (Chapter c) + { + + Set ret = new LinkedHashSet (); + + String ct = this.getCurrentChapterText (c); + + if (ct != null) + { + + DictionaryProvider2 dp = this.getDictionaryProvider (); + + if (dp != null) + { + + com.quollwriter.ui.fx.SpellChecker sc = dp.getSpellChecker (); + + if (sc != null) + { + + TextIterator ti = new TextIterator (ct); + + for (Word w : ti.getWords ()) + { + + if (!sc.isCorrect (w)) + { + + ret.add (w); + + } + + } + + } + + } + + } + + return ret; + + } + + public File getProjectFile (String fileName) + { + + if (fileName == null) + { + + return null; + + } + + return this.proj.getFile (fileName); + + } + + public File getProjectFilesDirectory () + { + + return this.proj.getFilesDirectory (); + + } + + public void saveToProjectFilesDirectory (File file, + String fileName) + throws GeneralException + { + + this.proj.saveToFilesDirectory (file, + fileName); + + } + + public Map> getTextSnippets (String s) + { + + Map> data = new LinkedHashMap<> (); + + // String name = n.getName ().toLowerCase (); + + java.util.List names = new ArrayList<> (); + names.add (s); + + // Get all the books and chapters. + java.util.List books = this.getProject ().getBooks (); + + for (int i = 0; i < books.size (); i++) + { + + Book b = books.get (i); + + java.util.List chapters = b.getChapters (); + + for (int j = 0; j < chapters.size (); j++) + { + + Chapter c = chapters.get (j); + + AbstractEditorPanel qep = this.getEditorForChapter (c); + + String t = null; + + if (qep != null) + { + + t = qep.getEditor ().getText (); + + } else { + + if (c.getText () != null) + { + + // Get the text. + t = c.getText ().getText (); + + } + + } + + if (t == null) + { + + continue; + + } + + java.util.List snippets = TextUtilities.getTextSnippetsForNames (names, + t); + + if ((snippets != null) && + (snippets.size () > 0)) + { + + data.put (c, + snippets); + + } + + } + + } + + return data; + + } + +} diff --git a/src/main/java/com/quollwriter/ui/AbstractViewer.java b/src/main/java/com/quollwriter/ui/AbstractViewer.java new file mode 100644 index 00000000..d23fac1c --- /dev/null +++ b/src/main/java/com/quollwriter/ui/AbstractViewer.java @@ -0,0 +1,3459 @@ +package com.quollwriter.ui; + +import java.awt.*; +import java.awt.dnd.*; +import java.awt.event.*; + +import java.io.*; + +import java.net.*; + +import java.security.*; + +import java.text.*; + +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Set; +import java.util.StringTokenizer; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.WeakHashMap; +import java.util.Collections; +import java.util.Stack; +import java.util.SortedSet; +import java.util.TimerTask; +import java.util.Arrays; +import java.util.concurrent.*; + +import org.w3c.dom.Element; +import org.w3c.dom.Node; + +import javax.sound.sampled.*; + +import javax.swing.*; +import javax.swing.border.*; +import javax.swing.event.*; +import javax.swing.tree.*; +import javax.swing.text.*; + +import com.gentlyweb.properties.*; + +import com.jgoodies.forms.builder.*; +import com.jgoodies.forms.factories.*; +import com.jgoodies.forms.layout.*; + +import com.quollwriter.*; + +import com.quollwriter.data.*; + +import com.quollwriter.db.*; +import com.quollwriter.ui.sidebars.*; +import com.quollwriter.ui.forms.*; +import com.quollwriter.ui.panels.*; +import com.quollwriter.events.*; +import com.quollwriter.synonyms.*; + +import com.quollwriter.ui.actionHandlers.*; +import com.quollwriter.ui.components.QPopup; +import com.quollwriter.ui.components.Header; +import com.quollwriter.ui.components.PopupAdapter; +import com.quollwriter.ui.components.PopupEvent; +import com.quollwriter.ui.events.*; +import com.quollwriter.ui.renderers.*; + +import com.quollwriter.data.editors.*; +import com.quollwriter.editors.*; +import com.quollwriter.editors.ui.*; +import com.quollwriter.editors.ui.sidebars.*; + +import com.quollwriter.achievements.rules.*; +import com.quollwriter.achievements.ui.*; + +import static com.quollwriter.LanguageStrings.*; +import static com.quollwriter.Environment.getUIString; + +public abstract class AbstractViewer extends JFrame implements PopupsSupported, + SideBarsSupported, + HTMLPanelActionHandler +{ + + public static final int NEW_PROJECT_ACTION = 1; + public static final int ABOUT_ACTION = 9; // "about"; + public static final int REPORT_BUG_ACTION = 10; // "reportBug"; + public static final int CLOSE_PROJECT_ACTION = 12; // "closeProject"; + public static final int DELETE_PROJECT_ACTION = 13; // "deleteProject"; + public static final int WARMUP_EXERCISE_ACTION = 26; + public static final int CONTACT_SUPPORT_ACTION = 28; + public static final int SHOW_TARGETS_ACTION = 29; + public static final int SHOW_STATISTICS_ACTION = 27; + + public static final String REPORT_BUG_HEADER_CONTROL_ID = "reportBug"; + public static final String CONTACTS_HEADER_CONTROL_ID = "contacts"; + public static final String SETTINGS_HEADER_CONTROL_ID = "settings"; + public static final String DO_WARMUP_HEADER_CONTROL_ID = "doWarmup"; + public static final String REPORT_BETA_BUG_HEADER_CONTROL_ID = "reportBetaBug"; + + private Header title = null; + private DropTarget titleDT = null; + private Box content = null; + private Box notifications = null; + private QPopup achievementsPopup = null; + private Map popups = new HashMap (); + + private ScheduledThreadPoolExecutor generalTimer = null; + + private Timer achievementsHideTimer = null; + + private Tips tips = null; + + private Map tempOptions = new HashMap (); + + private Set projectEventListeners = new HashSet (); + private boolean ignoreProjectEvents = false; + + public AbstractViewer() + { + + final AbstractViewer _this = this; + + this.generalTimer = new ScheduledThreadPoolExecutor (2, + new ThreadFactory () + { + + @Override + public Thread newThread (Runnable r) + { + + Thread t = new Thread (r); + + t.setDaemon (true); + t.setPriority (Thread.MIN_PRIORITY); + t.setName ("Viewer-general-" + t.getId ()); + + return t; + + } + + }); + + this.addWindowListener (new WindowAdapter () + { + + public void windowClosing (WindowEvent ev) + { + + _this.close (false, + null); + + } + + }); + + this.getContentPane ().setBackground (UIUtils.getComponentColor ()); + + this.setDefaultCloseOperation (WindowConstants.DO_NOTHING_ON_CLOSE); + + Box b = new Box (BoxLayout.Y_AXIS); + + this.title = new Header (); + this.title.setAlignmentX (Component.LEFT_ALIGNMENT); + + // new + Header h = this.title; + h.setFont (h.getFont ().deriveFont ((float) UIUtils.getScaledFontSize (22)).deriveFont (Font.PLAIN)); + h.setPaintProvider (null); + h.setTitleColor (UIUtils.getTitleColor ()); + h.setIcon (null); + h.setPadding (new Insets (3, 3, 3, 7)); + + Box tb = new Box (BoxLayout.X_AXIS); + tb.setAlignmentX (Component.LEFT_ALIGNMENT); + tb.add (this.title); + + tb.setBorder (new CompoundBorder (new MatteBorder (0, + 0, + 1, + 0, + UIUtils.getBorderColor ()), + new EmptyBorder (0, + 5, + 0, + 0) + )); + + b.add (tb); + + // Create the "notifications" area. + this.notifications = new Box (BoxLayout.Y_AXIS); + + this.notifications.setBorder (new MatteBorder (0, 0, 1, 0, UIUtils.getBorderColor ())); + + this.notifications.setVisible (false); + b.add (this.notifications); + + this.content = new Box (BoxLayout.Y_AXIS); + + b.add (this.content); + + try + { + + this.tips = new Tips (this); + + } catch (Exception e) { + + Environment.logError ("Unable to init tips", + e); + + } + + this.getContentPane ().add (b); + + } + + public void init () + throws Exception + { + + final AbstractViewer _this = this; + + InputMap im = this.getInputMap (JComponent.WHEN_IN_FOCUSED_WINDOW); + + im.put (KeyStroke.getKeyStroke (KeyEvent.VK_F12, + InputEvent.CTRL_MASK | InputEvent.ALT_MASK), + "debug"); + im.put (KeyStroke.getKeyStroke (KeyEvent.VK_F1, + InputEvent.CTRL_MASK | InputEvent.ALT_MASK), + "debug-mode"); + + im.put (KeyStroke.getKeyStroke (KeyEvent.VK_F11, + 0), + "whatsnew"); + + ActionMap am = this.getActionMap (); + + this.initKeyMappings (im); + + this.initActionMappings (am); + + final JToolBar titleC = UIUtils.createButtonBar (new ArrayList ()); + + Set tids = this.getTitleHeaderControlIds (); + + if (tids == null) + { + + tids = new LinkedHashSet (); + + } + + if (Environment.getQuollWriterVersion ().isBeta ()) + { + + Set ntids = new LinkedHashSet (); + + ntids.add (REPORT_BETA_BUG_HEADER_CONTROL_ID); + + ntids.addAll (tids); + + tids = ntids; + + } + + final Set ftids = tids; + + for (String s : tids) + { + + JComponent c = this.getTitleHeaderControl (s); + + if (c != null) + { + + c.setName (s); + + titleC.add (c); + + } + + } + + this.title.setControls (titleC); + + this.setIconImage (Environment.getWindowIcon ().getImage ()); + + this.updateForDebugMode (); + + // TODO Environment.registerViewer (this); + + } + + public void setTitleHeaderControlsVisible (boolean v) + { + + this.title.getControls ().setVisible (v); + + this.validate (); + this.repaint (); + + } + + public void showViewer () + { + + this.pack (); + + // Allow the underlying Windowing manager determine where to put the window. + this.setLocationByPlatform (true); + + this.setVisible (true); + + // TODO Environment.doNewsAndVersionCheck (this); + + this.handleWhatsNew (); + + this.handleShowTips (); + + } + + public JComponent getTitleHeaderControl (String id) + { + + if (id == null) + { + + return null; + + } + + java.util.List prefix = Arrays.asList (project, LanguageStrings.title,toolbar,buttons); + + final AbstractViewer _this = this; + + JComponent c = null; + + if (id.equals (DO_WARMUP_HEADER_CONTROL_ID)) + { + + c = UIUtils.createButton (Constants.WARMUPS_ICON_NAME, + Constants.ICON_TITLE_ACTION, + getUIString (prefix,warmup,tooltip), + //"Click to do a new {Warmup} exercise", + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + _this.showWarmupPromptSelect (); + + } + + }); + + } + + if (id.equals (REPORT_BUG_HEADER_CONTROL_ID)) + { + + c = UIUtils.createButton (Constants.BUG_ICON_NAME, + Constants.ICON_TITLE_ACTION, + getUIString (prefix,bug,tooltip), + //"Click to report a bug/problem", + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + _this.showReportProblem (); + + } + + }); + + } + + if (id.equals (REPORT_BETA_BUG_HEADER_CONTROL_ID)) + { + + c = UIUtils.createButton (Constants.BUG_ICON_NAME, + Constants.ICON_TITLE_ACTION, + getUIString (prefix,betabug,tooltip), + // "Click to report a bug/problem with the beta", + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + _this.showReportProblem (); + + } + + }); + + } + + if (id.equals (CONTACTS_HEADER_CONTROL_ID)) + { + + if (EditorsEnvironment.isEditorsServiceAvailable ()) + { + + String type = LanguageStrings.showcontacts; + + if (!EditorsEnvironment.hasRegistered ()) + { + + type = LanguageStrings.editorsserviceregister; + + } + + //String toolTip = (EditorsEnvironment.hasRegistered () ? "Click to show my {contacts}" : "Click to register for the Editors Service."); + + c = UIUtils.createButton (Constants.EDITORS_ICON_NAME, + Constants.ICON_TITLE_ACTION, + getUIString (prefix,type,tooltip), + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + if ((_this.isEditorsVisible ()) + && + (!EditorsEnvironment.isUserLoggedIn ()) + ) + { + + EditorsEnvironment.goOnline (null, + null, + null, + null); + + return; + + } + + try + { + + _this.viewEditors (); + + } catch (Exception e) { + + Environment.logError ("Unable to view editors", + e); + + UIUtils.showErrorMessage (_this, + getUIString (project,actions,vieweditors,actionerror)); + //"Unable to show the {editors}."); + + } + + } + + }); + + } + + } + + if (id.equals (SETTINGS_HEADER_CONTROL_ID)) + { + + c = UIUtils.createButton (Constants.SETTINGS_ICON_NAME, + Constants.ICON_TITLE_ACTION, + getUIString (prefix,projectmenu,tooltip), + //"Click to view the {Project} menu", + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + final JPopupMenu titlePopup = new JPopupMenu (); + + try + { + + _this.fillSettingsPopup (titlePopup); + + } catch (Exception e) + { + + Environment.logError ("Unable to fill popup", + e); + + } + + titlePopup.addSeparator (); + + JMenuItem mi = null; + + java.util.List prefix = Arrays.asList (project,settingsmenu,items); + + titlePopup.add (_this.createMenuItem (getUIString (prefix,options), + //"Options", + Constants.OPTIONS_ICON_NAME, + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + _this.showOptions (null); + + } + + })); + + titlePopup.add (_this.createMenuItem (getUIString (prefix,achievements), + //"Achievements", + Constants.ACHIEVEMENT_ICON_NAME, + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + _this.viewAchievements (); + + } + + })); + + titlePopup.addSeparator (); + + titlePopup.add (_this.createMenuItem (getUIString (prefix,whatsnew), + //"What's New in this version", + Constants.WHATS_NEW_ICON_NAME, + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + _this.showWhatsNew (true); + + } + + })); + + // Help + JMenu m = new JMenu (getUIString (prefix,help)); + //"Help"); + m.setIcon (Environment.getIcon (Constants.HELP_ICON_NAME, + Constants.ICON_MENU)); + + titlePopup.add (m); + + // Report Bug/Problem + m.add (_this.createMenuItem (getUIString (prefix,reportbug), + Constants.BUG_ICON_NAME, + AbstractProjectViewer.REPORT_BUG_ACTION)); + + // Contact Support + m.add (_this.createMenuItem (getUIString (prefix,contactsupport), + Constants.EMAIL_ICON_NAME, + AbstractProjectViewer.CONTACT_SUPPORT_ACTION)); + + // View the User Guide + m.add (_this.createMenuItem (getUIString (prefix,viewuserguide), + //"View the User Guide", + Constants.HELP_ICON_NAME, + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + UIUtils.openURL (_this, + "help:getting-started"); + + } + + })); + + m.add (_this.createMenuItem (getUIString (prefix,keyboardshortcuts), + //"Keyboard Shortcuts", + null, + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + UIUtils.openURL (_this, + "help:keyboard-shortcuts"); + + } + + })); + + // About Quoll Writer + titlePopup.add (_this.createMenuItem (getUIString (prefix,about), + //"About Quoll Writer", + Constants.ABOUT_ICON_NAME, + AbstractProjectViewer.ABOUT_ACTION)); + + if (Environment.isDebugModeEnabled ()) + { + + // Debug Console + titlePopup.add (_this.createMenuItem ("Debug Console", + Constants.CONSOLE_ICON_NAME, + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + new DebugConsole (_this); + + } + + })); + + } + + JComponent s = (JComponent) ev.getSource (); + + titlePopup.show (s, + s.getWidth () / 2, + s.getHeight ()); + + + } + + }); + + } + + return c; + + } + + public abstract boolean showOptions (String section); + + public abstract Set getTitleHeaderControlIds (); + + public abstract JPopupMenu getShowOtherSideBarsPopupSelector (); + + public abstract int getActiveSideBarCount (); + + public abstract AbstractSideBar getActiveOtherSideBar (); + + public abstract void addSideBarListener (SideBarListener l); + + public abstract void removeSideBarListener (SideBarListener l); + + public abstract void closeSideBar (); + + public abstract boolean viewAchievements (); + + public abstract boolean isEditorsVisible (); + + public abstract void viewTargets () + throws GeneralException; + + public abstract void viewEditor (EditorEditor ed) + throws GeneralException; + + public abstract boolean viewEditors () + throws GeneralException; + + public abstract void sendMessageToEditor (EditorEditor ed) + throws GeneralException; + + public abstract boolean showChart (String chartType) + throws GeneralException; + + public abstract boolean viewStatistics () + throws GeneralException; + + public void setContent (JComponent content) + { + + content.setAlignmentX (Component.LEFT_ALIGNMENT); + + this.content.add (content); + + } + + public void showContactSupport () + { + + final AbstractViewer _this = this; + + java.util.List prefix = Arrays.asList (project,actions,contactsupport); + + String popupName = "contactsupport"; + QPopup popup = this.getNamedPopup (popupName); + + if (popup == null) + { + + popup = UIUtils.createClosablePopup (getUIString (prefix, LanguageStrings.popup, LanguageStrings.title), + //"Contact Support", + Environment.getIcon (Constants.EMAIL_ICON_NAME, + Constants.ICON_POPUP), + null); + + final QPopup qp = popup; + + popup.setPopupName (popupName); + + this.addNamedPopup (popupName, + popup); + + Box content = new Box (BoxLayout.Y_AXIS); + + JTextPane help = UIUtils.createHelpTextPane (getUIString (prefix, LanguageStrings.popup,text), + //"Use the form below to contact Quoll Writer support. If you wish to receive a response then please provide an email address.", + this); + + help.setBorder (null); + + content.add (help); + content.add (Box.createVerticalStrut (10)); + + String errText = getUIString (prefix, LanguageStrings.popup,errorlabel); + + final JLabel error = UIUtils.createErrorLabel (errText); + //"Please enter a message."); + error.setVisible (false); + error.setBorder (UIUtils.createPadding (0, 0, 5, 5)); + + content.add (error); + + final MultiLineTextFormItem desc = new MultiLineTextFormItem (getUIString (prefix, LanguageStrings.popup,message,text), + //"Message", + getUIString (prefix, LanguageStrings.popup,message,tooltip), + //"Enter your message here.", + 10, + 10000, + false, + null); + + final TextFormItem email = new TextFormItem (getUIString (prefix, LanguageStrings.popup, LanguageStrings.email,text), + null); + + Set items = new LinkedHashSet (); + + items.add (desc); + items.add (email); + + ActionListener sendAction = new ActionListener () + { + + public void actionPerformed (ActionEvent ev) + { + + error.setVisible (false); + + String emErr = Utils.checkEmail2 (email.getText ()); + + if (emErr != null) + { + + error.setText (emErr); + + error.setVisible (true); + + qp.resize (); + + return; + + } + + if (desc.getText ().trim ().equals ("")) + { + + error.setText (errText); + error.setVisible (true); + + qp.resize (); + + return; + + } + + qp.resize (); + + // Send the message. + Map details = new HashMap (); + details.put ("details", + "Email: " + email.getText () + "\nDetails: " + desc.getText ()); + details.put ("email", + email.getText ()); + + try + { + + Environment.sendMessageToSupport ("contact", + details, + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + desc.setText (""); + + UIUtils.showMessage ((PopupsSupported) _this, + getUIString (prefix,confirmpopup, LanguageStrings.title), + //"Message sent", + getUIString (prefix,confirmpopup,text)); + //"Your request has been logged with Quoll Writer support. If you provided an email address then you should get a response within 1-2 days. If not feel then free to send the message again."); + + _this.fireProjectEvent (ProjectEvent.CONTACT, + ProjectEvent.SUBMIT); + + } + + }); + + } catch (Exception e) + { + + Environment.logError ("Unable to send message to support", + e); + + UIUtils.showErrorMessage (_this, + getUIString (prefix,actionerror)); + //"Unable to send message."); + + } + + qp.removeFromParent (); + + } + + }; + + UIUtils.addDoActionOnReturnPressed (desc.getTextArea (), + sendAction); + UIUtils.addDoActionOnReturnPressed (email.getTextField (), + sendAction); + + JButton send = UIUtils.createButton (getUIString (prefix, LanguageStrings.popup, LanguageStrings.buttons, LanguageStrings.send), + //"Send", + sendAction); + JButton cancel = UIUtils.createButton (getUIString (prefix, LanguageStrings.popup, LanguageStrings.buttons, LanguageStrings.cancel), + //Constants.CANCEL_BUTTON_LABEL_ID, + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + qp.removeFromParent (); + + } + + }); + + Set buttons = new LinkedHashSet (); + buttons.add (send); + buttons.add (cancel); + + Form f = new Form (Form.Layout.stacked, + items, + buttons); + + content.add (f); + + content.setSize (new Dimension (UIUtils.getPopupWidth () - 20, + content.getPreferredSize ().height)); + content.setBorder (UIUtils.createPadding (10, 10, 10, 10)); + + popup.setContent (content); + + popup.setDraggable (this); + + popup.resize (); + this.showPopupAt (popup, + UIUtils.getCenterShowPosition (this, + popup), + false); + + UIUtils.doLater (new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + desc.grabFocus (); + + } + + }); + + } else { + + popup.setVisible (true); + + + } + } + + public void showReportProblem () + { + + this.showReportProblem (null); + + } + + public void showReportProblem (String bugText) + { + + final AbstractViewer _this = this; + + java.util.List prefix = Arrays.asList (project,actions,reportproblem); + + String popupName = "bugreport"; + QPopup popup = this.getNamedPopup (popupName); + + if (popup == null) + { + + popup = UIUtils.createClosablePopup (getUIString (prefix, LanguageStrings.popup, LanguageStrings.title), + //"Report a Bug/Problem", + Environment.getIcon (Constants.BUG_ICON_NAME, + Constants.ICON_POPUP), + null); + + Box content = new Box (BoxLayout.Y_AXIS); + + JTextPane help = UIUtils.createHelpTextPane (getUIString (prefix, LanguageStrings.popup,text), + //"Complete the form below to report a bug/problem. The email address is optional, only provide it if you would like a response.

    The operating system you are using and the Java version will also be sent (it helps with debugging). No personal information will be sent.

    Please consider checking the box to send a screenshot, it helps a lot.", + this); + + help.setBorder (null); + + content.add (help); + content.add (Box.createVerticalStrut (10)); + + String errLabel = getUIString (prefix, LanguageStrings.popup,errorlabel); + + final JLabel error = UIUtils.createErrorLabel (errLabel); + //"Please enter a description."); + error.setVisible (false); + error.setBorder (UIUtils.createPadding (0, 5, 5, 5)); + + content.add (error); + + final MultiLineTextFormItem desc = new MultiLineTextFormItem (getUIString (prefix, LanguageStrings.popup,description,text), + //"Description", + getUIString (prefix, LanguageStrings.popup,description,tooltip), + //"Enter the bug/problem description here. The more information you can provide the better.", + 10, + 10000, + false, + null); + + if (bugText != null) + { + + desc.setText (bugText); + + } + + final TextFormItem email = new TextFormItem (getUIString (prefix, LanguageStrings.popup, LanguageStrings.email,text), + //"Email", + null); + + Set items = new LinkedHashSet (); + + items.add (desc); + items.add (email); + + final JCheckBox sendLogFiles = UIUtils.createCheckBox (getUIString (prefix, LanguageStrings.popup,sendlogfiles,text)); + //"Send the log files"); + + items.add (new AnyFormItem (null, + sendLogFiles)); + + final JCheckBox sendScreenshot = UIUtils.createCheckBox (getUIString (prefix, LanguageStrings.popup,sendscreenshot,text)); + //"Send a screenshot of current window"); + + sendScreenshot.setToolTipText (getUIString (prefix, LanguageStrings.popup,sendscreenshot,tooltip)); + //"Takes a screenshot of the current window and sends it to support. If you have information you would prefer not to share then please change the tab before sending. Uncheck to not send a screenshot, but please remember a picture is worth 1,000 (and more) words."); + + items.add (new AnyFormItem (null, + sendScreenshot)); + + sendScreenshot.setSelected (false); + sendScreenshot.setOpaque (false); + sendScreenshot.setAlignmentX (java.awt.Component.LEFT_ALIGNMENT); + + if (Environment.getQuollWriterVersion ().isBeta ()) + { + + sendLogFiles.setEnabled (false); + sendLogFiles.setToolTipText ("Log files are always sent for beta versions, it really helps with debugging."); + + } + + sendLogFiles.setSelected (true); + sendLogFiles.setOpaque (false); + sendLogFiles.setAlignmentX (java.awt.Component.LEFT_ALIGNMENT); + + final QPopup qp = popup; + + ActionListener sendAction = new ActionListener () + { + + public void actionPerformed (ActionEvent ev) + { + + error.setVisible (false); + + String emErr = Utils.checkEmail2 (email.getText ()); + + if (emErr != null) + { + + error.setText (emErr); + + error.setVisible (true); + + qp.resize (); + + return; + + } + + if (desc.getText ().trim ().equals ("")) + { + + error.setText (errLabel); + //"Please enter a description of the problem/bug."); + error.setVisible (true); + + qp.resize (); + + return; + + } + + qp.resize (); + + qp.removeFromParent (); + + StringBuilder dets = new StringBuilder ("Email: " + email.getText () + "\nDetails: " + desc.getText ()); + + // TODO: Fix this, have a toString on project viewer instead. + if (_this instanceof AbstractProjectViewer) + { + + Project proj = ((AbstractProjectViewer) _this).getProject (); + + dets.append ("\nCurrent project id: " + proj.getId ()); + + } + + // Send the message. + Map details = new HashMap (); + details.put ("details", + dets.toString ()); + + details.put ("email", + email.getText ()); + + try + { + + // Get the log files? + if (sendLogFiles.isSelected ()) + { + + details.put ("log", + Utils.getFileContentAsString (Environment.getLogPath ())); +/* + details.put ("editorsMessageLog", + Utils.getFileContentAsString (EditorsEnvironment.getMessageLogPath ())); +*/ + } + + if (sendScreenshot.isSelected ()) + { + + details.put ("screenshot", + Base64.encodeBytes (UIUtils.getImageBytes (UIUtils.getImageOfComponent (_this, + _this.getSize ().width, + _this.getSize ().height)))); + + } + + Environment.sendMessageToSupport ("bug", + details, + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + desc.setText (""); + + UIUtils.showMessage ((PopupsSupported) _this, + getUIString (prefix,confirmpopup, LanguageStrings.title), + //"Problem/Bug reported", + getUIString (prefix,confirmpopup,text)); + //"Thank you, the problem has been logged with Quoll Writer support. If you provided an email address then you should get a response within 1-2 days. If not feel then free to send the message again."); + + _this.fireProjectEvent (ProjectEvent.BUG_REPORT, + ProjectEvent.SUBMIT); + + } + + }); + + } catch (Exception e) + { + + Environment.logError ("Unable to send message to support", + e); + + UIUtils.showErrorMessage (_this, + getUIString (prefix,actionerror)); + //"Unable to send message."); + + } + + } + + }; + + UIUtils.addDoActionOnReturnPressed (desc.getTextArea (), + sendAction); + UIUtils.addDoActionOnReturnPressed (email.getTextField (), + sendAction); + + JButton send = UIUtils.createButton (getUIString (prefix, LanguageStrings.popup, LanguageStrings.buttons, LanguageStrings.send), + //"Send", + sendAction); + JButton cancel = UIUtils.createButton (getUIString (prefix, LanguageStrings.popup, LanguageStrings.buttons, LanguageStrings.cancel), + //Constants.CANCEL_BUTTON_LABEL_ID, + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + qp.removeFromParent (); + + } + + }); + + Set buttons = new LinkedHashSet (); + buttons.add (send); + buttons.add (cancel); + + Form f = new Form (Form.Layout.stacked, + items, + buttons); + + content.add (f); + + content.setSize (new Dimension (UIUtils.getPopupWidth () - 20, + content.getPreferredSize ().height)); + content.setBorder (UIUtils.createPadding (10, 10, 10, 10)); + + popup.setContent (content); + + popup.setDraggable (this); + + popup.setPopupName (popupName); + + this.addNamedPopup (popupName, + popup); + + popup.resize (); + this.showPopupAt (popup, + UIUtils.getCenterShowPosition (this, + popup), + false); + + UIUtils.doLater (new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + desc.grabFocus (); + + } + + }); + + } else { + + popup.setVisible (true); + + } + + } + + public void initActionMappings (ActionMap am) + { + + final AbstractViewer _this = this; + + am.put ("show-options", + new AbstractAction () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + _this.showOptions (null); + + } + + }); + + am.put ("do-warmup", + new AbstractAction () + { + + public void actionPerformed (ActionEvent ev) + { + + _this.getAction (AbstractViewer.WARMUP_EXERCISE_ACTION).actionPerformed (ev); + + } + + }); + + am.put ("debug", + new AbstractAction () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + new DebugConsole (_this); + + } + + }); + + am.put ("debug-mode", + new AbstractAction () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + Environment.setDebugModeEnabled (!Environment.isDebugModeEnabled ()); + + _this.updateForDebugMode (); + + // Add a notification. + _this.addNotification ((Environment.isDebugModeEnabled () ? getUIString (debugmode, LanguageStrings.enabled) : getUIString (debugmode,disabled)), + Constants.BUG_ICON_NAME, + 10); + + } + + }); + + am.put ("whatsnew", + new AbstractAction () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + UserProperties.set (Constants.WHATS_NEW_VERSION_VIEWED_PROPERTY_NAME, + "0"); + + _this.showWhatsNew (true); + + } + + }); + + am.put ("contact", + new AbstractAction () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + _this.showContactSupport (); + + } + + }); + + am.put ("editobjectnames", + new AbstractAction () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + _this.showObjectTypeNameChanger (); + + } + + }); + + am.put ("vieweditors", + new AbstractAction () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + try + { + + _this.viewEditors (); + + } catch (Exception e) { + + Environment.logError ("Unable to show editors", + e); + + UIUtils.showErrorMessage (_this, + getUIString (editors,vieweditorserror)); + + } + + } + + }); + + } + + private void updateForDebugMode () + { + + String iconName = this.getViewerIcon (); + + if (Environment.isDebugModeEnabled ()) + { + + iconName = Constants.BUG_ICON_NAME; + + } + + this.title.setIcon (Environment.getIcon (iconName, + Constants.ICON_TITLE)); + + } + + public void initKeyMappings (InputMap im) + { + + im.put (KeyStroke.getKeyStroke (KeyEvent.VK_F3, + 0), + "show-options"); + + im.put (KeyStroke.getKeyStroke (KeyEvent.VK_F7, + 0), + "vieweditors"); + im.put (KeyStroke.getKeyStroke (KeyEvent.VK_F10, + 0), + "do-warmup"); + + } + + protected JMenuItem createMenuItem (String label, + String icon, + int action) + { + + return UIUtils.createMenuItem (label, + icon, + this.getAction (action)); + + } + + protected JMenuItem createMenuItem (String label, + String icon, + ActionListener action) + { + + return UIUtils.createMenuItem (label, + icon, + action); + + } + + public Map getTempOptions () + { + + return this.tempOptions; + + } + + public boolean hasTempOption (String name) + { + + return this.getTempOption (name) != null; + + } + + public boolean isTempOption (String name) + { + + Object o = this.getTempOption (name); + + if (o == null) + { + + return false; + + } + + if (o instanceof Boolean) + { + + return ((Boolean) o).booleanValue (); + + } + + return false; + + } + + public Object getTempOption (String name) + { + + return this.tempOptions.get (name); + + } + + public void setTempOption (String name, + Object value) + { + + this.tempOptions.put (name, + value); + + } + + public abstract void showHelpText (String title, + String text, + String iconType, + String helpTextId); + + //public abstract String getViewerTitle (); + + public abstract String getViewerIcon (); + + public abstract void fillSettingsPopup (JPopupMenu popup); + + public abstract void doSaveState (); + + public ActionMap getActionMap () + { + + return this.content.getActionMap (); + + } + + public InputMap getInputMap (int m) + { + + return this.content.getInputMap (m); + + } + + public Notification addNotification (JComponent comp, + String iconType, + int duration) + { + + return this.addNotification (comp, + iconType, + duration, + null); + + } + + /** + * Adds a notification to the notification area, the action listener can be used + * to remove the notification, it can be safely called with a null event. + * + * @param comp The component to add to the notification. + * @param iconType The type of notification, supported values are "information" and "notify". + * @param duration The time, in seconds, that the notification should be shown for, if less than 1 then + * the notification won't be auto removed. + * @return An action listener that can be called to remove the notification. + */ + public Notification addNotification (JComponent comp, + String iconType, + int duration, + java.util.List buttons) + { + + final AbstractViewer _this = this; + + Notification n = new Notification (comp, + iconType, + duration, + buttons, + new ActionListener () + { + + public void actionPerformed (ActionEvent ev) + { + + Notification n = (Notification) ev.getSource (); + + _this.removeNotification (n); + + } + + }); + + this.addNotification (n); + + return n; + + } + + public void removeAllNotifications () + { + + for (int i = 0; i < this.notifications.getComponentCount (); i++) + { + + Notification n = (Notification) this.notifications.getComponent (i); + + this.removeNotification (n); + + } + + } + + public void removeNotification (Notification n) + { + + // Remove the box. + this.notifications.remove (n); + + if (this.notifications.getComponentCount () == 0) + { + + this.notifications.setVisible (false); + + } else { + + int c = this.notifications.getComponentCount (); + + JComponent jc = (JComponent) this.notifications.getComponent (c - 1); + + Border b = jc.getBorder (); + + // Eek, not good but ok for now. + // TODO: Fix this nasty. + if (b instanceof CompoundBorder) + { + + CompoundBorder cb = (CompoundBorder) b; + + jc.setBorder (cb.getInsideBorder ()); + + } + + } + + this.notifications.getParent ().validate (); + this.notifications.getParent ().repaint (); + + } + + public void addNotification (Notification n) + { + + if (this.notifications.getComponentCount () > 0) + { + + n.setBorder (new CompoundBorder (UIUtils.createBottomLineWithPadding (0, 0, 1, 0), + n.getBorder ())); + + } + + this.notifications.add (n, + 0); + + this.notifications.setVisible (true); + + n.init (); + + this.notifications.setMaximumSize (new Dimension (Short.MAX_VALUE, + this.notifications.getPreferredSize ().height)); + + } + + public Notification addNotification (String text, + String type, + int duration) + { + + return this.addNotification (text, + type, + duration, + null); + + } + + public Notification addNotification (String text, + String type, + int duration, + HyperlinkListener clickListener) + { + + JTextPane p = UIUtils.createHelpTextPane (text, + this); + + p.setMaximumSize (new Dimension (Short.MAX_VALUE, + Short.MAX_VALUE)); + p.setBorder (null); + + if (clickListener != null) + { + + p.addHyperlinkListener (clickListener); + + } + + return this.addNotification (p, + type, + duration); + + } + + public Action getAction (int name) + { + + final AbstractViewer _this = this; + + if (name == AbstractViewer.SHOW_STATISTICS_ACTION) + { + + return new AbstractAction () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + try + { + + _this.viewStatistics (); + + } catch (Exception e) { + + Environment.logError ("Unable to view the statistics", + e); + + UIUtils.showErrorMessage (_this, + getUIString (statistics,actionerror)); + //"Unable to view the statistics"); + + } + + } + + }; + + } + + if (name == AbstractViewer.WARMUP_EXERCISE_ACTION) + { + + return new AbstractAction () + { + + @Override + public void actionPerformed (final ActionEvent ev) + { + + _this.showWarmupPromptSelect (); + + } + + }; + + } + + if (name == AbstractViewer.REPORT_BUG_ACTION) + { + + return new AbstractAction () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + _this.showReportProblem (); + + } + + }; + + } + + if (name == AbstractViewer.CONTACT_SUPPORT_ACTION) + { + + return new AbstractAction () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + _this.showContactSupport (); + + } + + }; + + } + + if (name == AbstractViewer.ABOUT_ACTION) + { + + return new AbstractAction () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + _this.showAbout (); + + } + + }; + + } + + if (name == AbstractViewer.SHOW_TARGETS_ACTION) + { + + return new AbstractAction () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + try + { + + _this.viewTargets (); + + } catch (Exception e) { + + Environment.logError ("Unable to view targets", + e); + + UIUtils.showErrorMessage (_this, + getUIString (targets,actionerror)); + //"Unable to view targets."); + + } + + } + + }; + + } + + return null; + + } + + public void showWarmupPromptSelect () + { + + final QPopup qp = UIUtils.createClosablePopup (getUIString (dowarmup,popup, LanguageStrings.title), + //"Do a {Warmup} Exercise", + Environment.getIcon (Warmup.OBJECT_TYPE, + Constants.ICON_POPUP), + null); + + WarmupPromptSelect w = new WarmupPromptSelect (this); + + w.init (); + + w.setSize (new Dimension (UIUtils.getPopupWidth () - 20, + qp.getPreferredSize ().height)); + + w.setBorder (UIUtils.createPadding (10, 10, 10, 10)); + + qp.setContent (w); + + qp.setDraggable (this); + + qp.resize (); + + this.addNamedPopup ("warmup", + qp); + + this.showPopupAt (qp, + UIUtils.getCenterShowPosition (this, + qp), + false); + + UIUtils.doLater (new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + qp.resize (); + + } + + }); + + } + + public void setViewerTitle (String t) + { + + //t = Environment.replaceObjectNames (t); + + this.title.setTitle (t); + + UIUtils.setFrameTitle (this, + t); + + } + + private void handleWhatsNew () + { + + boolean showWhatsNew = false; + + String whatsNewVersion = UserProperties.get (Constants.WHATS_NEW_VERSION_VIEWED_PROPERTY_NAME); + //Environment.getProperty (Constants.WHATS_NEW_VERSION_VIEWED_PROPERTY_NAME); + + if (whatsNewVersion != null) + { + + Version lastViewed = new Version (whatsNewVersion); + + if (lastViewed.isNewer (Environment.getQuollWriterVersion ())) + { + + showWhatsNew = true; + + } + + } + + if (showWhatsNew) + { + + this.showWhatsNew (false); + + } + + } + + public void addNamedPopup (String name, + QPopup popup) + { + + QPopup qp = this.popups.get (name); + + if (qp != null) + { + + qp.removeFromParent (); + + } + + this.popups.put (name, + popup); + + } + + public void removeNamedPopup (String name) + { + + QPopup qp = this.popups.remove (name); + + if (qp != null) + { + + qp.removeFromParent (); + + } + + } + + public QPopup getNamedPopup (String name) + { + + return this.popups.get (name); + + } + + public void showAbout () + { + + final AbstractViewer _this = this; + + java.util.List prefix = Arrays.asList (about,popup); + + String popupName = "about"; + + QPopup popup = this.getNamedPopup (popupName); + + if (popup == null) + { + + final QPopup qp = UIUtils.createClosablePopup (getUIString (prefix, LanguageStrings.title), + Environment.getIcon (Constants.ABOUT_ICON_NAME, + Constants.ICON_POPUP), + null); + + qp.addPopupListener (new PopupAdapter () + { + + @Override + public void popupHidden (PopupEvent ev) + { + + _this.removeNamedPopup ("about"); + + } + + }); + + Box content = new Box (BoxLayout.Y_AXIS); + + FormLayout pfl = new FormLayout ("5px, right:p, 6px, fill:p:grow", + "p, 6px, p, 6px, p, 6px, p, 6px, p, 6px, p, 6px, p, 6px, p, 6px, p, 6px, p"); /*, 6px, p");*/ + + PanelBuilder pbuilder = new PanelBuilder (pfl); + + CellConstraints cc = new CellConstraints (); + + int y = 1; + + pbuilder.addLabel (getUIString (prefix,qwversion), + //"Version", + cc.xy (2, + y)); + + pbuilder.addLabel (Environment.getQuollWriterVersion ().getVersion (), + cc.xy (4, + y)); + + y += 2; + + pbuilder.addLabel (getUIString (prefix,copyright), + //"Copyright", + cc.xy (2, + y)); + + Date d = new Date (); + + SimpleDateFormat sdf = new SimpleDateFormat ("yyyy"); + + String year = sdf.format (d); + + pbuilder.addLabel (String.format (UserProperties.get (Constants.COPYRIGHT_PROPERTY_NAME), + year), + cc.xy (4, + y)); + + y += 2; + + pbuilder.addLabel (getUIString (prefix,website), + //"Website", + cc.xy (2, + y)); + + pbuilder.add (UIUtils.createWebsiteLabel (Environment.getQuollWriterWebsite (), + null, + false), + cc.xy (4, + y)); + + y += 2; + + pbuilder.addLabel (getUIString (prefix,sourcecode), + //"Source Code", + cc.xy (2, + y)); + + pbuilder.add (UIUtils.createWebsiteLabel (UserProperties.get (Constants.SOURCE_CODE_WEBSITE_PROPERTY_NAME), + //"https://github.com/garybentley/quollwriter", + null, + false), + cc.xy (4, + y)); + + y += 2; + + String relNotesUrl = UserProperties.get (Constants.QUOLL_WRITER_RELEASE_NOTES_URL_PROPERTY_NAME); + + relNotesUrl = Utils.replaceString (relNotesUrl, + "[[VERSION]]", + Environment.getQuollWriterVersion ().getVersion ().replace ('.', + '_')); + + pbuilder.add (UIUtils.createWebsiteLabel (relNotesUrl, + getUIString (prefix,releasenotes), + //"Release Notes", + false), + cc.xy (4, + y)); + + y += 2; + + pbuilder.add (UIUtils.createWebsiteLabel (UserProperties.get (Constants.PATREON_WEBSITE_PROPERTY_NAME), + //"https://www.patreon.com/quollwriter?ty=h", + "Patreon", + false), + cc.xy (4, + y)); + + y += 2; + + pbuilder.add (UIUtils.createWebsiteLabel (UserProperties.get (Constants.GOFUNDME_WEBSITE_PROPERTY_NAME), + //"https://www.gofundme.com/quollwriter", + getUIString (prefix,makeadonation), + //"Make a donation", + false), + cc.xy (4, + y)); + + y += 2; + + pbuilder.add (UIUtils.createWebsiteLabel (UserProperties.get (Constants.QUOLL_WRITER_ACKNOWLEDGMENTS_URL_PROPERTY_NAME), + getUIString (prefix,acknowledgments), + //"Acknowledgments", + false), + cc.xy (4, + y)); + + y += 2; + + JButton closeBut = UIUtils.createButton (getUIString (buttons,close)); + //closeBut.setText ("Close"); + + closeBut.addActionListener (new ActionListener () + { + + public void actionPerformed (ActionEvent ev) + { + + qp.removeFromParent (); + + } + + }); + + JButton[] buts = { closeBut }; + + JPanel bp = UIUtils.createButtonBar2 (buts, + Component.LEFT_ALIGNMENT); + bp.setOpaque (false); + + JPanel p = pbuilder.getPanel (); + p.setOpaque (false); + p.setAlignmentX (JComponent.LEFT_ALIGNMENT); + + content.add (p); + + content.add (Box.createVerticalStrut (10)); + content.add (bp); + + content.setSize (new Dimension (UIUtils.getPopupWidth () - 20, + content.getPreferredSize ().height)); + content.setBorder (UIUtils.createPadding (10, 10, 10, 10)); + + qp.setContent (content); + + qp.setDraggable (this); + + qp.resize (); + + popup = qp; + + this.addNamedPopup (popupName, + popup); + + this.showPopupAt (popup, + UIUtils.getCenterShowPosition (this, + popup), + false); + + } else { + + popup.setVisible (true); + + } + + this.fireProjectEvent (ProjectEvent.ABOUT, + ProjectEvent.SHOW); + + } + + public void showWhatsNew (boolean onlyShowCurrentVersion) + { + + String popupName = "whatsnew"; + + QPopup popup = this.getNamedPopup (popupName); + + if (popup == null) + { + + try + { + + popup = UIUtils.createWizardPopup (String.format (getUIString (whatsnew, LanguageStrings.popup, LanguageStrings.title), + Environment.getQuollWriterVersion ()), + //"What's new in version " + Environment.getQuollWriterVersion (), + Constants.WHATS_NEW_ICON_NAME, + null, + new WhatsNew (this, + onlyShowCurrentVersion)); + + popup.setPopupName (popupName); + + } catch (Exception e) { + + // Not good but not the end of the world but shouldn't stop things from going on. + Environment.logError ("Unable to init whats new", + e); + + UIUtils.showErrorMessage (this, + getUIString (whatsnew,actionerror)); + //"Unable to show What's New, please contact Quoll Writer support for assistance."); + + return; + + } + + this.addNamedPopup (popupName, + popup); + + popup.setDraggable (this); + + popup.resize (); + this.showPopupAt (popup, + UIUtils.getCenterShowPosition (this, + popup), + false); + + } else { + + popup.setVisible (true); + + } + + this.fireProjectEvent (ProjectEvent.WHATS_NEW, + ProjectEvent.SHOW); + + } + + private void handleShowTips () + { + + if (Environment.isFirstUse ()) + { + + return; + + } + + if ((this.tips != null) + && + (UserProperties.getAsBoolean (Constants.SHOW_TIPS_PROPERTY_NAME)) + ) + { + + final AbstractViewer _this = this; + + try + { + + String tipText = this.tips.getNextTip (); + + final JTextPane htmlP = UIUtils.createHelpTextPane (tipText, + this); + + htmlP.setBorder (null); + htmlP.setSize (new Dimension (500, + 500)); + + JButton nextBut = UIUtils.createButton ("next", + Constants.ICON_MENU, + getUIString (tipspanel,next,tooltip), + //"Click to view the next tip", + null); + + java.util.List buts = new ArrayList (); + buts.add (nextBut); + + JButton offBut = UIUtils.createButton (Constants.STOP_ICON_NAME, + Constants.ICON_MENU, + getUIString (tipspanel,stop,tooltip), + //"Click to stop showing tips when Quoll Writer starts", + null); + + buts.add (offBut); + + // Show a tip. + final Notification n = this.addNotification (htmlP, + Constants.HELP_ICON_NAME, + 90, + buts); + + nextBut.addActionListener (new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + String t = _this.tips.getNextTip (); + + if (t != null) + { + + htmlP.setText (t); + + htmlP.validate (); + + n.setMinimumSize (n.getPreferredSize ()); + + _this.repaint (); + + n.restartTimer (); + + _this.fireProjectEvent (ProjectEvent.TIPS, + ProjectEvent.SHOW); + + } + + } + + }); + + offBut.addActionListener (new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + JButton but = (JButton) ev.getSource (); + + Point p = SwingUtilities.convertPoint (but, + 0, + 0, + _this); + + java.util.List prefix = Arrays.asList (tipspanel,stop,popup); + + UIUtils.createQuestionPopup (_this, + getUIString (prefix, LanguageStrings.title), + //"Stop showing tips?", + Constants.STOP_ICON_NAME, + getUIString (prefix,text), + //"Stop showing tips when Quoll Writer starts?

    They can enabled at any time in the Options panel.", + getUIString (prefix,buttons,confirm), + //"Yes, stop showing them", + getUIString (prefix,buttons,cancel), + //"No, keep them", + new ActionListener () + { + + public void actionPerformed (ActionEvent ev) + { + + _this.fireProjectEvent (ProjectEvent.TIPS, + ProjectEvent.OFF); + + UserProperties.set (Constants.SHOW_TIPS_PROPERTY_NAME, + false); + + n.removeNotification (); + + } + + }, + null, + null, + p); + + } + + }); + + } catch (Exception e) { + + Environment.logError ("Unable to show tips", + e); + + } + + } + + } + + public void handleHTMLPanelAction (String v) + { + + StringTokenizer t = new StringTokenizer (v, + ",;"); + + if (t.countTokens () > 1) + { + + while (t.hasMoreTokens ()) + { + + this.handleHTMLPanelAction (t.nextToken ().trim ()); + + } + + return; + + } + + try + { + + if (v.equals ("showundealtwitheditormessages")) + { + + this.viewEditors (); + + return; + + } + + if (v.startsWith ("options")) + { + + String section = null; + + int dot = v.indexOf ('.'); + + if (dot > 1) + { + + section = v.substring (dot + 1); + + } + + this.showOptions (section); + + return; + + } + + if (v.equals ("whatsnew")) + { + + this.showWhatsNew (true); + + return; + + } + + if (v.equals ("achievements")) + { + + this.viewAchievements (); + + return; + + } + + if (v.equals ("warmup")) + { + + this.showWarmupPromptSelect (); + + return; + + } + + if (v.equals ("showinviteeditor")) + { + + // TODO EditorsUIUtils.showInviteEditor (this); + + return; + + } + + if (v.equals ("editobjectnames")) + { + + this.showObjectTypeNameChanger (); + + return; + + } + + if (v.equals ("contact")) + { + + this.showContactSupport (); + + return; + + } + + if (v.equals ("reportbug")) + { + + this.showReportProblem (); + + return; + + } + + if (v.equals ("dictionarymanager")) + { + + this.showDictionaryManager (); + + return; + + } + + if (v.equals ("editors")) + { + + this.viewEditors (); + + return; + + } + + if (v.equals ("targets")) + { + + this.viewTargets (); + + return; + + } + + if (v.equals ("statistics")) + { + + this.viewStatistics (); + + return; + + } + + if (v.equals ("charts")) + { + + this.viewStatistics (); + + return; + + } + + } catch (Exception e) { + + Environment.logError ("Unable to perform action: " + + v, + e); + + } + + } + + public void showObjectTypeNameChanger () + { + + String popupName = "editobjectnames"; + QPopup popup = this.getNamedPopup (popupName); + + if (popup == null) + { + + popup = UIUtils.createClosablePopup (getUIString (objectnames,changer, LanguageStrings.popup, LanguageStrings.title), + //"Edit Object Names", + Environment.getIcon (Constants.CONFIG_ICON_NAME, + Constants.ICON_POPUP), + null); + + popup.setPopupName (popupName); + + ObjectTypeNameChanger c = new ObjectTypeNameChanger (this); + + c.init (); + + popup.setContent (c); + + c.setSize (new Dimension (UIUtils.getPopupWidth () - 20, + c.getPreferredSize ().height)); + c.setBorder (UIUtils.createPadding (10, 10, 10, 10)); + + popup.setContent (c); + + popup.setDraggable (this); + + popup.resize (); + + this.addNamedPopup (popupName, + popup); + + this.showPopupAt (popup, + UIUtils.getCenterShowPosition (this, + popup), + false); + + } else { + + popup.setVisible (true); + + } + + } + + private boolean closeInternal (ActionListener afterClose) + { + + this.notifications.setVisible (false); + + this.dispose (); + + this.generalTimer.shutdown (); +/* +TODO + Environment.unregisterViewer (this, + afterClose); +*/ + return true; + + } + + public boolean close (boolean noConfirm, + final ActionListener afterClose) + { + + return this.closeInternal (afterClose); + + } + + public void bringPopupToFront (Component c) + { + + this.getLayeredPane ().setPosition (c, + 0); + + } + + public void addPopup (Component c) + { + + this.addPopup (c, + false, + false); + + } + + public void addPopup (Component c, + boolean hideOnClick, + boolean hideViaVisibility) + { + + this.getLayeredPane ().add (c, + JLayeredPane.POPUP_LAYER); + + this.getLayeredPane ().moveToFront (c); + + } + + @Override + public void removePopup (Component c) + { + + this.getLayeredPane ().remove (c); + + this.getLayeredPane ().validate (); + + this.getLayeredPane ().repaint (); + + } + + public void showAchievement (AchievementRule ar) + { + + try + { + + Box b = null; + + if (this.achievementsPopup == null) + { + + b = new Box (BoxLayout.Y_AXIS); + b.setBackground (UIUtils.getComponentColor ()); + b.setOpaque (true); + + this.achievementsPopup = UIUtils.createPopup (getUIString (achievementreached, LanguageStrings.title), + //"You've got an Achievement", + Constants.ACHIEVEMENT_ICON_NAME, + b, + true, + null); + + this.achievementsPopup.getHeader ().setPreferredSize (new Dimension (250, + this.achievementsPopup.getHeader ().getPreferredSize ().height)); + + final AbstractViewer _this = this; + final Box content = b; + + this.achievementsPopup.getHeader ().addMouseListener (new MouseAdapter () + { + + public void mouseReleased (MouseEvent ev) + { + + _this.achievementsPopup.setVisible (false); + + content.removeAll (); + + } + + }); + + this.achievementsPopup.addMouseListener (new ComponentShowHide (new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + _this.achievementsHideTimer.stop (); + + } + + }, + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + _this.achievementsHideTimer.start (); + + } + + })); + + } else { + + b = (Box) this.achievementsPopup.getContent (); + + } + + JComponent arBox = new AchievementBox (ar, + false, + true); + + if (b.getComponentCount () > 0) + { + + arBox.setBorder (new CompoundBorder (new MatteBorder (0, 0, 1, 0, UIUtils.getBorderColor ()), + arBox.getBorder ())); + + } + + b.add (arBox, + 0); + + if (this.achievementsPopup.getParent () != null) + { + + this.achievementsPopup.getParent ().remove (this.achievementsPopup); + + } + + this.showPopupAt (this.achievementsPopup, + new Point (10, 10), + true); + + this.achievementsPopup.setVisible (true); + + final AbstractViewer _this = this; + final Box content = b; + + if (this.achievementsHideTimer == null) + { + + this.achievementsHideTimer = new Timer (10000, + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + _this.achievementsPopup.setVisible (false); + + content.removeAll (); + + } + + }); + + this.achievementsHideTimer.setRepeats (false); + + } + + this.achievementsHideTimer.stop (); + + this.achievementsHideTimer.start (); + + } catch (Exception e) { + + Environment.logError ("Unable to display achievement: " + + ar, + e); + + } + + } + + public void showNotificationPopup (String title, + String message, + int showFor) + { + + JComponent c = null; + JTextPane m = null; + + if (message != null) + { + + m = UIUtils.createHelpTextPane (message, + this); + + m.setSize (new Dimension (350 - 20, + m.getPreferredSize ().height)); + + Box b = new Box (BoxLayout.Y_AXIS); + b.setBackground (UIUtils.getComponentColor ()); + b.setOpaque (true); + b.add (m); + b.setBorder (UIUtils.createPadding (10, 10, 10, 10)); + b.setPreferredSize (new Dimension (350, + b.getPreferredSize ().height)); + + c = b; + + } + + final QPopup popup = UIUtils.createPopup (title, + Constants.INFO_ICON_NAME, + null, + true, + null); + + popup.setContent (c); + + if (m != null) + { + + m.addHyperlinkListener (new HyperlinkListener () + { + + @Override + public void hyperlinkUpdate (HyperlinkEvent ev) + { + + if (ev.getEventType () == HyperlinkEvent.EventType.ACTIVATED) + { + + popup.removeFromParent (); + + } + + } + + }); + + } + + this.showPopupAt (popup, + new Point (10, 10), + true); + + if (showFor > 0) + { + + final Timer t = new Timer (showFor * 1000, + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + popup.removeFromParent (); + + } + + }); + + popup.addMouseListener (new ComponentShowHide (new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + t.stop (); + + } + + }, + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + t.start (); + + } + + })); + + t.setRepeats (false); + + t.start (); + + } + + } + + public QPopup getPopupByName (String name) + { + + if (name == null) + { + + return null; + + } + + Component[] children = this.getLayeredPane ().getComponentsInLayer (JLayeredPane.POPUP_LAYER); + + if (children == null) + { + + return null; + + } + + for (int i = 0; i < children.length; i++) + { + + Component c = children[i]; + + if (name.equals (c.getName ())) + { + + if (c instanceof QPopup) + { + + return (QPopup) c; + + } + + } + + } + + return null; + + } + + public void showPopupAt (JComponent c, + Rectangle r, + String where, + boolean hideOnParentClick) + { + + Dimension s = c.getPreferredSize (); + + int x = r.x; + int y = r.y - c.getInsets ().top;// - c.getInsets ().bottom; + + if (where == null) + { + + where = "below"; + + } + + if (where.equals ("below")) + { + + y = y + r.height; + + } + + if (where.equals ("above")) + { + + y = y - s.height - c.getInsets ().bottom; + + } + + if (y < 0) + { + + y = r.y; // + r.height; + + } + + if ((x + s.width) > (this.getWidth ())) + { + + x = this.getWidth () - 20 - s.width; + + } + + if (x < 0) + { + + x = 5; + + } + + this.showPopupAt (c, + new Point (x, + y), + hideOnParentClick); + + } + + @Override + public void showPopupAt (Component popup, + Component showAt, + boolean hideOnParentClick) + { + + Point po = SwingUtilities.convertPoint (showAt, + 0, + 0, + this.getContentPane ()); + + this.showPopupAt (popup, + po, + hideOnParentClick); + + + } + + @Override + public void showPopupAt (Component c, + Point p, + boolean hideOnParentClick) + { + + Insets ins = this.getInsets (); + + if ((c.getParent () == null) + && + (c.getParent () != this.getLayeredPane ()) + ) + { + + this.addPopup (c, + hideOnParentClick, + false); + + } + + Dimension cp = c.getPreferredSize (); + + if ((p.y + cp.height) > (this.getBounds ().height - ins.top - ins.bottom)) + { + + p = new Point (p.x, + p.y); + + // See if the child is changing height. + if (c.getBounds ().height != cp.height) + { + + p.y = p.y - (cp.height - c.getBounds ().height); + + } else { + + p.y = p.y - cp.height; + + } + + } + + if (p.y < 0) + { + + p = new Point (p.x, + p.y); + + p.y = 10; + + } + + if ((p.x + cp.width) > (this.getBounds ().width - ins.left - ins.right)) + { + + p = new Point (p.x, + p.y); + + p.x = p.x - cp.width; + + } + + if (p.x < 0) + { + + p = new Point (p.x, + p.y); + + p.x = 10; + + } + + c.setBounds (p.x, + p.y, + c.getPreferredSize ().width, + c.getPreferredSize ().height); + + c.setVisible (true); + this.validate (); + this.repaint (); + + } + + public void showPopup (Component c, + boolean hideOnParentClick) + { + + Point p = this.getMousePosition (); + + if (p != null) + { + + SwingUtilities.convertPointToScreen (p, + this); + + } else + { + + p = new Point (300, + 300); + + } + + this.showPopupAt (c, + p, + hideOnParentClick); + + } + + public Point convertPoint (Component c, + Point p) + { + + Component o = this.getContentPane (); + + return SwingUtilities.convertPoint (c, + p, + o); + + } + + public void setViewerControls (JComponent c) + { + + this.title.setControls (c); + + } + + public void removeProjectEventListener (ProjectEventListener l) + { + + this.projectEventListeners.remove (l); + + } + + public void addProjectEventListener (ProjectEventListener l) + { + + this.projectEventListeners.add (l); + + } + + public void fireProjectEventLater (final String type, + final String action) + { + + final AbstractViewer _this = this; + + UIUtils.doLater (new ActionListener () + { + + public void actionPerformed (ActionEvent ev) + { + + _this.fireProjectEvent (type, + action); + + } + + }); + + } + + public void fireProjectEvent (String type, + String action, + Object contextObject) + { + + this.fireProjectEvent (new ProjectEvent (this, + type, + action, + contextObject)); + + } + + public void fireProjectEvent (String type, + String action) + { + + this.fireProjectEvent (new ProjectEvent (this, + type, + action)); + + } + + public void setIgnoreProjectEvents (boolean v) + { + + this.ignoreProjectEvents = v; + + } + + public void fireProjectEvent (ProjectEvent ev) + { + + if (this.ignoreProjectEvents) + { + + return; + + } + + for (ProjectEventListener l : this.projectEventListeners) + { + + l.eventOccurred (ev); + + } + + } + + public void showDictionaryManager () + { + + String popupName = "dictman"; + QPopup popup = this.getNamedPopup (popupName); + + if (popup == null) + { + + DictionaryManager dictMan = null; + + try + { + + dictMan = new DictionaryManager (this); + + } catch (Exception e) { + + Environment.logError ("Unable to create dictionary maanger.", + e); + + UIUtils.showErrorMessage (this, + getUIString (dictionary,manage,actionerror)); + //"Unable to show personal dictionary."); + + return; + + } + + dictMan.init (); + + popup = UIUtils.createClosablePopup (getUIString (dictionary,manage, LanguageStrings.title), + //"Manage your personal Dictionary", + Environment.getIcon (Constants.DICTIONARY_ICON_NAME, + Constants.ICON_POPUP), + null); + + popup.setRemoveOnClose (false); + + popup.setPopupName (popupName); + + this.addNamedPopup (popupName, + popup); + + dictMan.setSize (new Dimension (UIUtils.getPopupWidth () - 20, + dictMan.getPreferredSize ().height)); + dictMan.setBorder (UIUtils.createPadding (10, 10, 10, 10)); + + popup.setContent (dictMan); + + popup.setDraggable (this); + + popup.resize (); + this.showPopupAt (popup, + UIUtils.getCenterShowPosition (this, + popup), + false); + + } else { + + popup.setVisible (true); + + } + + this.fireProjectEvent (ProjectEvent.PERSONAL_DICTIONARY, + ProjectEvent.SHOW); + + } + + public void showEditNoteTypes () + { + + String popupName = "editnotetypes"; + QPopup popup = this.getNamedPopup (popupName); + + if (popup == null) + { + + popup = UIUtils.createClosablePopup (getUIString (notetypes,actions,manage, LanguageStrings.title), + //"Manage the {Note} Types", + Environment.getIcon (Constants.EDIT_ICON_NAME, + Constants.ICON_POPUP), + null); + + popup.setRemoveOnClose (false); + + popup.setPopupName (popupName); + + this.addNamedPopup (popupName, + popup); + + EditNoteTypes content = new EditNoteTypes (this); + content.init (); + + content.setSize (new Dimension (UIUtils.getPopupWidth () - 20, + content.getPreferredSize ().height)); + content.setBorder (UIUtils.createPadding (10, 10, 10, 10)); + + popup.setContent (content); + + popup.setDraggable (this); + + popup.resize (); + this.showPopupAt (popup, + UIUtils.getCenterShowPosition (this, + popup), + false); + + } else { + + popup.setVisible (true); + + } + + this.fireProjectEvent (ProjectEvent.NOTE_TYPES, + ProjectEvent.SHOW); + + } + + public void showEditTags () + { + + String popupName = "edittags"; + QPopup popup = this.getNamedPopup (popupName); + + if (popup == null) + { + + popup = UIUtils.createClosablePopup (getUIString (tags,actions,manage, LanguageStrings.title), + //)"Manage the Tags", + Environment.getIcon (Constants.EDIT_ICON_NAME, + Constants.ICON_POPUP), + null); + + popup.setRemoveOnClose (false); + + popup.setPopupName (popupName); + + this.addNamedPopup (popupName, + popup); + + TagsEditor content = new TagsEditor (this); + + content.init (); + + content.setSize (new Dimension (UIUtils.getPopupWidth () - 20, + content.getPreferredSize ().height)); + content.setBorder (UIUtils.createPadding (10, 10, 10, 10)); + + popup.setContent (content); + + popup.setDraggable (this); + + popup.resize (); + this.showPopupAt (popup, + UIUtils.getCenterShowPosition (this, + popup), + false); + + } else { + + popup.setVisible (true); + + } + + this.fireProjectEvent (ProjectEvent.TAGS, + ProjectEvent.EDIT); + + } + + /** + * Un-schedule the scheduledfuture (gained from a call to Environment.schedule). + * + * @param r The scheduledfuture to remove from the executor service. + * @returns Whether it was successfully removed. + */ + public void unschedule (ScheduledFuture f) + { + + if (f == null) + { + + return; + + } + + // Let the task run to completion. + f.cancel (false); + + this.generalTimer.purge (); + + } + + /** + * Schedule the runnable to run after delay and repeat (use -1 or 0 for no repeat). + * + * @param r The runnable to run. + * @param delay The delay, in millis. + * @param repeat The repeat time, in millis. + */ + public ScheduledFuture schedule (final Runnable r, + final long delay, + final long repeat) + { + + if (this.generalTimer == null) + { + + Environment.logError ("Unable to schedule timer is no longer valid."); + + return null; + + } + + if (r == null) + { + + Environment.logError ("Unable to schedule timer, runnable is null."); + + return null; + + } + + if (repeat < 1) + { + + return this.generalTimer.schedule (r, + delay, + TimeUnit.MILLISECONDS); + + } else { + + return this.generalTimer.scheduleAtFixedRate (r, + delay, + repeat, + TimeUnit.MILLISECONDS); + + } + + } + +} diff --git a/src/main/java/com/quollwriter/ui/AccordionItem.java b/src/main/java/com/quollwriter/ui/AccordionItem.java new file mode 100644 index 00000000..ca6487ef --- /dev/null +++ b/src/main/java/com/quollwriter/ui/AccordionItem.java @@ -0,0 +1,324 @@ +package com.quollwriter.ui; + +import java.awt.Component; +import java.awt.Insets; +import java.awt.Cursor; +import java.awt.Color; +import java.awt.Font; +import java.awt.event.*; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.HashMap; + +import javax.swing.*; + +import com.quollwriter.*; +import com.quollwriter.events.*; +import com.quollwriter.ui.components.GradientPainter; +import com.quollwriter.ui.components.Header; + +public abstract class AccordionItem extends Box +{ + + protected Header header = null; + //private List headerMenuItems = new ArrayList (); + private String title = null; + //private JComponent content = null; + private boolean inited = false; + + public AccordionItem (String title) + { + + this (title, + (String) null); + + } + + public AccordionItem (String title, + ImageIcon icon) + { + + super (BoxLayout.Y_AXIS); + + this.initHeader (title, + icon); + + } + + public AccordionItem (String title, + String iconType) + { + + super (BoxLayout.Y_AXIS); + + ImageIcon ii = null; + + if (iconType != null) + { + + ii = Environment.getIcon (iconType, + Constants.ICON_SIDEBAR); + + } + + this.initHeader (title, + ii); + + } + + public abstract JComponent getContent (); + + public void initFromSaveState (String ss) + { + + this.init (); + + Map state = (Map) JSONDecoder.decode (ss); + + Boolean vis = (Boolean) state.get ("contentVisible"); + + this.setContentVisible ((vis != null ? vis : false)); + + } + + public Map getSaveStateAsMap () + { + + Map ss = new HashMap (); + + ss.put ("contentVisible", + this.isContentVisible ()); + + return ss; + + } + + public String getSaveState () + { + + try + { + + return JSONEncoder.encode (this.getSaveStateAsMap ()); + + } catch (Exception e) { + + Environment.logError ("Unable to encode save state: " + + this.getSaveStateAsMap (), + e); + + return ""; + + } + + } + + private void initHeader (String title, + ImageIcon icon) + { + + this.title = Environment.replaceObjectNames (title); + + final Header h = new Header (this.title, + icon, + null); + + h.setFont (h.getFont ().deriveFont ((float) UIUtils.getScaledFontSize (14)).deriveFont (Font.PLAIN)); + + h.setPaintProvider (null); + h.setTitleColor (UIUtils.getTitleColor ()); + h.setPadding (new Insets (5, 0, 0, 0)); + h.setPaintProvider (new GradientPainter (UIUtils.getComponentColor (), + UIUtils.getComponentColor ())); + + // end new + h.setAlignmentX (Component.LEFT_ALIGNMENT); + h.setAlignmentY (Component.TOP_ALIGNMENT); + + this.header = h; + + } + + public String getId () + { + + return null; + + } + + public boolean isContentVisible () + { + + return this.getContent ().isVisible (); + + } + + public void setIconType (String i) + { + + if (i != null) + { + + ImageIcon ii = Environment.getIcon (i, + Constants.ICON_SIDEBAR); + + this.header.setIcon (ii); + + } + + } + + public String getTitle () + { + + return this.title; + + } + + public void setTitle (String s) + { + + this.title = Environment.replaceObjectNames (s); + + this.header.setTitle (s); + + } + + public Header getHeader () + { + + return this.header; + + } + + public void setHeader (Header h) + { + + this.header = h; + + } + + public void setContentVisible (boolean v) + { + + JComponent c = this.getContent (); + + if (c != null) + { + + c.setVisible (v); + + } + + this.validate (); + this.repaint (); + + } + + public void fillHeaderPopupMenu (JPopupMenu m, + MouseEvent ev) + { + + } + + public void setSaveState (String s) + { + + Map m = (Map) JSONDecoder.decode (s); + + this.setContentVisible ((Boolean) m.get ("contentVisible")); + + } + + public void init () + { + + if (this.inited) + { + + return; + + } + + final AccordionItem _this = this; + + this.header.setCursor (Cursor.getPredefinedCursor (Cursor.HAND_CURSOR)); + this.header.setToolTipText (Environment.getUIString (LanguageStrings.project, + LanguageStrings.sidebar, + LanguageStrings.section, + LanguageStrings.title, + LanguageStrings.tooltip)); + //"Click to open/close the items below."); + + this.header.addMouseListener (new MouseEventHandler () + { + + @Override + public void fillPopup (JPopupMenu m, + MouseEvent ev) + { + + _this.fillHeaderPopupMenu (m, + ev); + + } + + @Override + public void handlePress (MouseEvent ev) + { + + JComponent c = _this.getContent (); + + if (c != null) + { + + c.setVisible (!c.isVisible ()); + + _this.revalidate (); + _this.repaint (); + + } + + } + + }); + + JComponent c = this.getContent (); + + if (c != null) + { + + c.setAlignmentX (Component.LEFT_ALIGNMENT); + + } + + this.add (this.header); + + if (c != null) + { + + this.add (c); + + } + + this.inited = true; + + } + + public void setHeaderControls (JComponent c) + { + + this.header.setControls (c); + + } + + public JComponent getHeaderControls () + { + + return (JComponent) this.header.getControls (); + + } + +} diff --git a/src/com/quollwriter/ui/AppearsInChaptersEditPanel.java b/src/main/java/com/quollwriter/ui/AppearsInChaptersEditPanel.java similarity index 100% rename from src/com/quollwriter/ui/AppearsInChaptersEditPanel.java rename to src/main/java/com/quollwriter/ui/AppearsInChaptersEditPanel.java diff --git a/src/com/quollwriter/ui/AssetAccordionItem.java b/src/main/java/com/quollwriter/ui/AssetAccordionItem.java similarity index 97% rename from src/com/quollwriter/ui/AssetAccordionItem.java rename to src/main/java/com/quollwriter/ui/AssetAccordionItem.java index 0f5600f5..7d7078be 100644 --- a/src/com/quollwriter/ui/AssetAccordionItem.java +++ b/src/main/java/com/quollwriter/ui/AssetAccordionItem.java @@ -31,12 +31,12 @@ public AssetAccordionItem (UserConfigurableObjectType objType, { super (objType.getObjectTypeNamePlural (), - objType.getIcon16x16 (), + (ImageIcon) null, // TODO objType.getIcon16x16 (), pv); this.objType = objType; - Environment.addUserProjectEventListener (this); + // TODO Environment.addUserProjectEventListener (this); this.sortField = objType.getPrimaryNameField (); @@ -91,7 +91,7 @@ public void eventOccurred (ProjectEvent ev) public void update () { - this.getHeader ().setIcon (objType.getIcon16x16 ()); + // TODO this.getHeader ().setIcon (objType.getIcon16x16 ()); super.update (); @@ -165,14 +165,14 @@ public int compare (Asset o1, if (nv1 == null) { - nv1 = new Integer (Short.MAX_VALUE); + nv1 = Integer.valueOf (Short.MAX_VALUE); } if (nv2 == null) { - nv2 = new Integer (Short.MAX_VALUE); + nv2 = Integer.valueOf (Short.MAX_VALUE); } @@ -497,14 +497,14 @@ public int compare (Asset o1, if (nv1 == null) { - nv1 = new Integer (Short.MAX_VALUE); + nv1 = Integer.valueOf (Short.MAX_VALUE); } if (nv2 == null) { - nv2 = new Integer (Short.MAX_VALUE); + nv2 = Integer.valueOf (Short.MAX_VALUE); } diff --git a/src/com/quollwriter/ui/AssetDetailsEditPanel.java b/src/main/java/com/quollwriter/ui/AssetDetailsEditPanel.java similarity index 87% rename from src/com/quollwriter/ui/AssetDetailsEditPanel.java rename to src/main/java/com/quollwriter/ui/AssetDetailsEditPanel.java index 75f42b7d..b3ad026e 100644 --- a/src/com/quollwriter/ui/AssetDetailsEditPanel.java +++ b/src/main/java/com/quollwriter/ui/AssetDetailsEditPanel.java @@ -41,7 +41,7 @@ public AssetDetailsEditPanel (Asset a, this.object = a; this.viewer = viewer; - + InputMap im = this.getInputMap (JComponent.WHEN_IN_FOCUSED_WINDOW); im.put (KeyStroke.getKeyStroke (KeyEvent.VK_S, @@ -65,84 +65,84 @@ public void actionPerformed (ActionEvent ev) } }); - + } - + @Override public void refresh () { - + this.showViewPanel (); - + } - + @Override public void refreshViewPanel () { this.refresh (); - + } - + @Override public boolean handleSave () { Set errors = new LinkedHashSet (); - + // Do our error checks. for (UserConfigurableObjectFieldViewEditHandler h : this.editHandlers) - { - + { + Set herrs = h.getInputFormItemErrors (); - + if (herrs != null) { - + errors.addAll (herrs); - + } } - + if (errors.size () > 0) { - + this.showEditError (errors); - + return false; - + } - + Set oldNames = this.object.getAllNames (); - + // Now setup the values. for (UserConfigurableObjectFieldViewEditHandler h : this.editHandlers) - { - + { + try { - + h.updateFieldFromInput (); - + } catch (Exception e) { - + Environment.logError ("Unable to get input save value for: " + h.getTypeField (), e); - + UIUtils.showErrorMessage (this.viewer, Environment.getUIString (LanguageStrings.assets, LanguageStrings.save, LanguageStrings.actionerror)); //"Unable to save."); - + return false; - + } - + } - + try { @@ -188,13 +188,13 @@ public boolean handleCancel () prefix.add (LanguageStrings.save); prefix.add (LanguageStrings.cancel); prefix.add (LanguageStrings.popup); - + final AssetDetailsEditPanel _this = this; boolean changed = false; // Check for any field having changes. - + if (!changed) { @@ -223,29 +223,29 @@ public boolean handleCancel () // On confirm new ActionListener () { - + @Override public void actionPerformed (ActionEvent ev) { - + _this.changeConfirm = true; - + _this.doCancel (); - + } - + }, // On cancel null, null, null); - + return false; } } - + this.changeConfirm = false; return true; @@ -298,9 +298,9 @@ public String getEditTitle () LanguageStrings.edit, LanguageStrings.aboutpanel, LanguageStrings.title); - + } - + @Override public String getTitle () { @@ -312,15 +312,15 @@ public String getTitle () //"About"; } - + @Override public JComponent getSaveButton () { - + final AssetDetailsEditPanel _this = this; - + IconProvider ip = this.getIconProvider (); - + JButton save = UIUtils.createButton (ip.getIcon (Constants.SAVE_ICON_NAME, Constants.ICON_PANEL_SECTION_ACTION), String.format (Environment.getUIString (LanguageStrings.assets, @@ -333,29 +333,29 @@ public JComponent getSaveButton () //"Click to save the details", new ActionListener () { - + @Override public void actionPerformed (ActionEvent ev) { - + _this.doSave (); - + } - + }); return save; - + } - + @Override public JComponent getCancelButton () { - + final AssetDetailsEditPanel _this = this; - - IconProvider ip = this.getIconProvider (); - + + IconProvider ip = this.getIconProvider (); + JButton cancel = UIUtils.createButton (ip.getIcon (Constants.CANCEL_ICON_NAME, Constants.ICON_PANEL_SECTION_ACTION), Environment.getUIString (LanguageStrings.assets, @@ -363,33 +363,33 @@ public JComponent getCancelButton () LanguageStrings.aboutpanel, LanguageStrings.buttons, LanguageStrings.cancel, - LanguageStrings.tooltip), + LanguageStrings.tooltip), //"Click to cancel the editing", new ActionListener () { - + @Override public void actionPerformed (ActionEvent ev) { - + _this.doCancel (); - + } - + }); return cancel; - + } @Override public JComponent getEditButton () { - + final AssetDetailsEditPanel _this = this; - - IconProvider ip = this.getIconProvider (); - + + IconProvider ip = this.getIconProvider (); + return UIUtils.createButton (ip.getIcon (Constants.EDIT_ICON_NAME, Constants.ICON_PANEL_SECTION_ACTION), String.format (Environment.getUIString (LanguageStrings.assets, @@ -402,138 +402,140 @@ public JComponent getEditButton () //"Click to edit this section", new ActionListener () { - + @Override public void actionPerformed (ActionEvent ev) { - + _this.doEdit (); - + } - + }); - + } - + public JComponent getAddPanel () { - + final AssetDetailsEditPanel _this = this; - - this.editHandlers = this.object.getViewEditHandlers (this.viewer); - + + // TODO Remove this.editHandlers = this.object.getViewEditHandlers (this.viewer); + // Build the edit panel. // Get the layout. AssetViewAddEditLayout l = this.getLayout (this.object); - + return l.createEdit (this.editHandlers, new ActionListener () { - + @Override public void actionPerformed (ActionEvent ev) { - + _this.doSave (); - + } - + }); - + } - + @Override public JComponent getEditPanel () { - + final AssetDetailsEditPanel _this = this; - - this.editHandlers = this.object.getViewEditHandlers (this.viewer); - + + // TODO Remove this.editHandlers = this.object.getViewEditHandlers (this.viewer); + // Build the edit panel. // Get the layout. AssetViewAddEditLayout l = this.getLayout (this.object); - + return l.createEdit (this.editHandlers, new ActionListener () { - + @Override public void actionPerformed (ActionEvent ev) { - + _this.doSave (); - + } - + }); - + } @Override public JComponent getViewPanel () { - + // Build the view panel. - + // Get the layout. AssetViewAddEditLayout l = this.getLayout (this.object); - - return l.createView (this.object.getViewEditHandlers (this.viewer)); - + + return null; + + // TODO Remove? l.createView (this.object.getViewEditHandlers (this.viewer)); + } - + @Override public Set getEditItems () { - + return null; - + } @Override public Set getViewItems () { - + return null; - + } - + @Override public void doEdit () { - + ActionListener a = AssetViewPanel.getEditAssetAction (this.viewer, this.object); - + if (a == null) { - + Environment.logError ("Unable to get edit asset action for: " + this.object, null); - + UIUtils.showErrorMessage (this.viewer, String.format (Environment.getUIString (LanguageStrings.assets, LanguageStrings.edit, LanguageStrings.actionerror), //"Unable to edit the {%s}", this.object.getObjectTypeName ())); - + return; - + } - UIUtils.doLater (a); - + UIUtils.doLater (a); + } public AssetViewAddEditLayout getLayout (UserConfigurableObject obj) { - + return new AssetViewAddEditLayout (obj.getUserConfigurableObjectType ().getLayout (), this.viewer); - + } } diff --git a/src/main/java/com/quollwriter/ui/AssetFindResultsBox.java b/src/main/java/com/quollwriter/ui/AssetFindResultsBox.java new file mode 100644 index 00000000..d29dceeb --- /dev/null +++ b/src/main/java/com/quollwriter/ui/AssetFindResultsBox.java @@ -0,0 +1,58 @@ +package com.quollwriter.ui; + +import java.util.Set; + +import javax.swing.*; +import javax.swing.tree.*; + +import com.quollwriter.data.*; + +public class AssetFindResultsBox extends FindResultsBox +{ + + private Set objs = null; + private UserConfigurableObjectType objType = null; + + public AssetFindResultsBox (UserConfigurableObjectType type, + AbstractProjectViewer viewer, + Set objs) + { + + super (type.getObjectTypeNamePlural (), + null, // TODO type.getIcon16x16 (), + viewer); + + this.objs = objs; + + this.count = objs.size (); + + + } + + @Override + public String getId () + { + + return "findasset" + this.objType.getKey (); + + } + + @Override + public void initTree () + { + + // Let subclasses override for their own behaviour. + DefaultMutableTreeNode tn = new DefaultMutableTreeNode (this.viewer.getProject ()); + + UIUtils.createTree (this.objs, + tn); + + ((DefaultTreeModel) this.tree.getModel ()).setRoot (tn); + + this.count = objs.size (); + + this.updateItemCount (this.count); + + } + +} diff --git a/src/com/quollwriter/ui/AssetViewAddEditLayout.java b/src/main/java/com/quollwriter/ui/AssetViewAddEditLayout.java similarity index 100% rename from src/com/quollwriter/ui/AssetViewAddEditLayout.java rename to src/main/java/com/quollwriter/ui/AssetViewAddEditLayout.java diff --git a/src/com/quollwriter/ui/BackgroundChangeEvent.java b/src/main/java/com/quollwriter/ui/BackgroundChangeEvent.java similarity index 100% rename from src/com/quollwriter/ui/BackgroundChangeEvent.java rename to src/main/java/com/quollwriter/ui/BackgroundChangeEvent.java diff --git a/src/com/quollwriter/ui/BackgroundImage.java b/src/main/java/com/quollwriter/ui/BackgroundImage.java similarity index 100% rename from src/com/quollwriter/ui/BackgroundImage.java rename to src/main/java/com/quollwriter/ui/BackgroundImage.java diff --git a/src/com/quollwriter/ui/BackgroundImagePanel.java b/src/main/java/com/quollwriter/ui/BackgroundImagePanel.java similarity index 100% rename from src/com/quollwriter/ui/BackgroundImagePanel.java rename to src/main/java/com/quollwriter/ui/BackgroundImagePanel.java diff --git a/src/com/quollwriter/ui/BackgroundSelector.java b/src/main/java/com/quollwriter/ui/BackgroundSelector.java similarity index 96% rename from src/com/quollwriter/ui/BackgroundSelector.java rename to src/main/java/com/quollwriter/ui/BackgroundSelector.java index 50c80303..3d47775c 100644 --- a/src/com/quollwriter/ui/BackgroundSelector.java +++ b/src/main/java/com/quollwriter/ui/BackgroundSelector.java @@ -17,9 +17,8 @@ import javax.swing.border.*; import javax.swing.event.*; -import org.jdom.*; - -import com.gentlyweb.xml.*; +import org.dom4j.*; +import org.dom4j.tree.*; import com.quollwriter.*; @@ -286,18 +285,12 @@ private void initFiles () } // Will be xml. - Element root = JDOMUtils.getStringAsElement (bgFiles); - - List els = JDOMUtils.getChildElements (root, - "f", - false); + Element root = DOM4JUtils.stringAsElement (bgFiles); - for (int i = 0; i < els.size (); i++) + for (Element el : root.elements ("f")) { - Element el = (Element) els.get (i); - - File f = new File (JDOMUtils.getChildContent (el)); + File f = new File (el.getTextTrim ()); if ((!f.exists ()) || @@ -328,20 +321,20 @@ private void updateFiles () try { - Element root = new Element ("files"); + Element root = new DefaultElement ("files"); for (File f : this.files) { - Element el = new Element ("f"); - el.addContent (f.getPath ()); + Element el = new DefaultElement ("f"); + el.add (new DefaultCDATA (f.getPath ())); - root.addContent (el); + root.add (el); } // Get as a string. - String data = JDOMUtils.getElementAsString (root); + String data = DOM4JUtils.elementAsString (root); UserProperties.set (Constants.BG_IMAGE_FILES_PROPERTY_NAME, data); diff --git a/src/main/java/com/quollwriter/ui/BackupsManager.java b/src/main/java/com/quollwriter/ui/BackupsManager.java new file mode 100644 index 00000000..c4782e4c --- /dev/null +++ b/src/main/java/com/quollwriter/ui/BackupsManager.java @@ -0,0 +1,639 @@ +package com.quollwriter.ui; + +import java.awt.*; +import java.awt.event.*; + +import java.io.File; + +import java.net.*; + +import java.text.*; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.StringTokenizer; +import java.util.Vector; +import java.util.Date; +import java.util.Arrays; +import java.util.Set; +import java.util.LinkedHashSet; + +import javax.swing.*; +import javax.swing.border.*; +import javax.swing.filechooser.*; +import javax.swing.table.*; +import javax.swing.tree.*; + +import org.josql.*; + +import com.jgoodies.forms.builder.*; +import com.jgoodies.forms.factories.*; +import com.jgoodies.forms.layout.*; + +import com.quollwriter.*; + +import com.quollwriter.data.*; +import com.quollwriter.data.comparators.*; + +import com.quollwriter.exporter.*; + +import com.quollwriter.ui.components.*; +import com.quollwriter.ui.renderers.*; +import com.quollwriter.ui.fx.ProjectEvent; +import com.quollwriter.ui.fx.ProjectEventListener; + +import static com.quollwriter.LanguageStrings.*; +import static com.quollwriter.uistrings.UILanguageStringsManager.getUIString; + +public class BackupsManager extends Box implements ProjectEventListener +{ + + private AbstractViewer viewer = null; + private ProjectInfo proj = null; + private Box backupsBox = null; + private JLabel noBackups = null; + private JLabel backupsDir = null; + private JScrollPane scrollPane = null; + + public BackupsManager (AbstractViewer pv, + ProjectInfo pi) + { + + super (BoxLayout.Y_AXIS); + + this.viewer = pv; + this.proj = pi; + + Environment.addUserProjectEventListener (this); + + } + + public void eventOccurred (ProjectEvent ev) + { + + if (!ev.getType ().equals (ProjectEvent.Type.backups)) + { + + return; + + } + + Object c = ev.getContextObject (); + + if ((c != null) + && + (c instanceof Project) + ) + { + + Project p = (Project) c; + + if (Environment.getProjectInfo (p) != this.proj) + { + + // Not interested in this project. + return; + + } + + } + + this.update (); + + } + + private void update () + { + + try + { + + final BackupsManager _this = this; + + this.noBackups.setVisible (true); + + this.backupsDir.setVisible (this.proj.getBackupDirPath ().toFile ().exists ()); + + this.backupsBox.removeAll (); + + File[] _files = this.proj.getBackupDirPath ().toFile ().listFiles (); + + if ((_files != null) + && + (_files.length > 0) + ) + { + + java.util.List files = (java.util.List) Arrays.asList (_files); + + Query q = new Query (); + + q.parse (String.format ("SELECT * FROM %s WHERE fileExtension(:_currobj) = 'zip' ORDER BY lastModified DESC", + File.class.getName ())); + + QueryResults qr = q.execute (files); + + files = (java.util.List) qr.getResults (); + + for (File f : files) + { + + Backup b = new Backup (f, + this.proj); + + b.init (); + + this.backupsBox.add (b); + + } + + this.noBackups.setVisible (files.size () == 0); + + UIUtils.doLater (new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + _this.scrollPane.getVerticalScrollBar ().setValue (0); + + } + + }); + + } + + } catch (Exception e) { + + Environment.logError ("Unable to build list of backups", + e); + + UIUtils.showErrorMessage (this.viewer, + getUIString (backups,show,actionerror)); + //"Unable to show list of backups, please contact Quoll Writer support for assistance."); + + } + + } + + public void init () + throws Exception + { + + final BackupsManager _this = this; + + JTextPane tp = UIUtils.createHelpTextPane (String.format (getUIString (backups,text), + //"Listed below are the backups you have for {project} %s.", + this.proj.getName ()), + this.viewer); + + tp.setBorder (UIUtils.createPadding (0, 0, 10, 0)); + + this.add (tp); + + this.backupsDir = UIUtils.createClickableLabel (getUIString (backups,viewbackupsdir), + //"Click to view the backups directory", + Environment.getIcon (Constants.VIEW_ICON_NAME, + Constants.ICON_MENU)); + + UIUtils.makeClickable (this.backupsDir, + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + try + { + + UIUtils.openURL (_this.viewer, + _this.proj.getBackupDirPath ().toUri ().toURL ()); + + } catch (Exception e) { + + // Can ignore. + + } + + } + + }); + + this.backupsDir.setBorder (UIUtils.createPadding (0, 0, 10, 0)); + + this.add (this.backupsDir); + + this.noBackups = UIUtils.createLabel (getUIString (backups,nobackups)); + //"You currently have no backups for this {project}."); + this.noBackups.setIcon (Environment.getIcon (Constants.INFO_ICON_NAME, + Constants.ICON_MENU)); + + this.noBackups.setBorder (UIUtils.createPadding (0, 0, 10, 0)); + + this.add (this.noBackups); + + this.backupsBox = new ScrollableBox (BoxLayout.Y_AXIS); + this.backupsBox.setAlignmentX (Component.LEFT_ALIGNMENT); + this.backupsBox.setOpaque (false); + + this.scrollPane = UIUtils.createScrollPane (backupsBox); + this.scrollPane.getVerticalScrollBar ().setUnitIncrement (20); + this.scrollPane.getViewport ().setPreferredSize (new Dimension (450, + 300)); + + Box wspsp = new Box (BoxLayout.Y_AXIS); + wspsp.add (this.scrollPane); + wspsp.setBorder (UIUtils.createPadding (0, 0, 0, 0)); + this.add (wspsp); + + this.update (); + + this.add (Box.createVerticalStrut (10)); + + JButton create = UIUtils.createButton (getUIString (backups,show,buttons,createbackup), + //Constants.CREATE_BACKUP_BUTTON_LABEL_ID, + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + UIUtils.showCreateBackup (proj, + null, + _this.viewer); + + } + + }); + + JButton finish = UIUtils.createButton (getUIString (backups,show,buttons, LanguageStrings.finish), + //Constants.FINISH_BUTTON_LABEL_ID, + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + UIUtils.closePopupParent (_this.getParent ()); + + } + + }); + + JButton[] buts = new JButton[] { create, finish }; + + JPanel bp = UIUtils.createButtonBar2 (buts, + Component.CENTER_ALIGNMENT); + bp.setOpaque (false); + + this.add (bp); + + UIUtils.doLater (new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + _this.scrollPane.getVerticalScrollBar ().setValue (0); + + } + + }); + + } + + private class Backup extends Box + { + + private File file = null; + private ProjectInfo proj = null; + + public Backup (File b, + ProjectInfo proj) + { + + super (BoxLayout.Y_AXIS); + + this.file = b; + this.proj = proj; + + this.setBorder (new CompoundBorder (new MatteBorder (0, + 0, + 1, + 0, + UIUtils.getInnerBorderColor ()), + new EmptyBorder (5, + 5, + 5, + 5))); + + } + + public void restore () + { + + java.util.List prefix = Arrays.asList (backups,restore,popup); + + final Backup _this = this; + + UIUtils.createQuestionPopup ((AbstractViewer) BackupsManager.this.viewer, + getUIString (prefix,title), + //"Confirm restore", + Constants.RESTORE_ICON_NAME, + String.format (getUIString (prefix,text), + //"Please confirm you wish to restore {project} %s using the backup file %s.

    A backup of the {project} will be created before the restore occurs.", + this.proj.getName (), + this.file.getName ()), + getUIString (prefix,buttons,confirm), + //"Yes, restore it", + getUIString (prefix,buttons,cancel), + //Constants.CANCEL_BUTTON_LABEL_ID, + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + final AbstractProjectViewer pv = null; // TODO Environment.getProjectViewer (_this.proj); + + ActionListener doRestore = new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + UIUtils.closePopupParent (BackupsManager.this); + + ActionListener doRestore = new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + try + { + + // Create a backup. + /* + TODO Moved to new BackupsManager. + File f = Environment.createBackupForProject (_this.proj, + true); +*/ + } catch (Exception e) { + + Environment.logError ("Unable to create backup for project: " + + _this.proj, + e); + + UIUtils.showErrorMessage (BackupsManager.this.viewer, + getUIString (backups,_new,actionerror)); + //"Unable to create a backup of the {project} in its current state."); + + } + + // Restore using our file. + try + { +/* +TODO + Environment.restoreBackupForProject (_this.proj, + _this.file); +*/ + } catch (Exception e) { + + Environment.logError ("Unable to restore project with file: " + + _this.file + + ", project: " + + _this.proj, + e); + + UIUtils.showErrorMessage (BackupsManager.this.viewer, + getUIString (backups,restore,actionerror)); + //"Unable to restore backup"); + + return; + + } + + java.util.List prefix = Arrays.asList (backups,restore,confirmpopup); + + if (pv != null) + { + + try + { + + // Reopen the project. + Environment.openProject (_this.proj); + + AbstractProjectViewer p = null; // TODO Environment.getProjectViewer (_this.proj); + + // Show confirmation. + UIUtils.showMessage ((PopupsSupported) p, + getUIString (prefix,title), + //"{Project} restored", + String.format (getUIString (prefix,text), + //"The {project} has been restored from file %s.", + _this.file.getName ())); +/* +TODO + p.fireProjectEventLater (ProjectEvent.Type.backups, + ProjectEvent.Action.restore); +*/ + } catch (Exception e) { + + Environment.logError ("Unable to reopen project: " + + _this.proj, + e); + + UIUtils.showErrorMessage (BackupsManager.this.viewer, + getUIString (prefix,actionerror)); + //"Unable to re-open backup"); + + return; + + } + + return; + + } + + // Show confirmation. + UIUtils.showMessage ((PopupsSupported) BackupsManager.this.viewer, + getUIString (prefix,title), + //"{Project} restored", + String.format (getUIString (prefix,text), + //"{Project} %s has been restored using file %s.", + _this.proj.getName (), + _this.file.getName ())); + + } + + }; + + UIUtils.askForPasswordForProject (proj, + null, + doRestore, + BackupsManager.this.viewer); + + } + + }; + + if (pv != null) + { + + // Close the project. + pv.close (false, + doRestore); + + } else { + + doRestore.actionPerformed (new ActionEvent ("restore", 1, "restore")); + + } + + // Create a backup of the project first. + + // Close the project viewer, if open. + + // Unzip to the current dir. + + // Open the project, if already open. + + } + + }, + null, + null, + null); + + } + + public void delete () + { + + java.util.List prefix = Arrays.asList (backups,delete,confirmpopup); + + final Backup _this = this; + + UIUtils.createQuestionPopup ((AbstractViewer) BackupsManager.this.viewer, + getUIString (prefix,title), + //"Confirm delete", + Constants.DELETE_ICON_NAME, + String.format (getUIString (prefix,text), + //"Please confirm you wish to delete backup file %s.", + this.file.getName ()), + getUIString (prefix,buttons,confirm), + //"Yes, delete it", + getUIString (prefix,buttons,cancel), + //"No, keep it", + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + _this.file.delete (); + + Container p = _this.getParent (); + + p.remove (_this); + + p.validate (); + p.repaint (); +/* +TODO + BackupsManager.this.viewer.fireProjectEventLater (ProjectEvent.Type.backups, + ProjectEvent.Action.delete); +*/ + BackupsManager.this.update (); + + } + + }, + null, + null, + null); + + } + + public void init () + { + + final Backup _this = this; + + this.setBorder (UIUtils.createBottomLineWithPadding (5, 5, 5, 5)); + + final Box main = new Box (BoxLayout.X_AXIS); + + this.add (main); + + this.setAlignmentX (Component.LEFT_ALIGNMENT); + this.setOpaque (false); + main.setAlignmentX (Component.LEFT_ALIGNMENT); + main.setOpaque (false); + + JComponent name = UIUtils.createHelpTextPane (String.format ("%s (%s)", + Environment.formatDateTime (new Date (this.file.lastModified ())), + this.file.getName ()), + BackupsManager.this.viewer); + + main.add (name); + main.add (Box.createHorizontalGlue ()); + + java.util.List buttons = new ArrayList (); + + buttons.add (UIUtils.createButton (Constants.RESTORE_ICON_NAME, + Constants.ICON_MENU, + getUIString (backups,restore,tooltip), + //"Restore the {project} using this backup", + new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + _this.restore (); + + } + + })); + + buttons.add (UIUtils.createButton (Constants.DELETE_ICON_NAME, + Constants.ICON_MENU, + getUIString (backups,delete,tooltip), + //"Click to delete this backup", + new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + _this.delete (); + + } + + })); + + JComponent bbar = UIUtils.createButtonBar (buttons); + + //this.buttons.setVisible (false); + bbar.setAlignmentX (Component.LEFT_ALIGNMENT); + + main.add (bbar); + + } + + } + +} diff --git a/src/com/quollwriter/ui/ChapterDescriptionAccordionItem.java b/src/main/java/com/quollwriter/ui/ChapterDescriptionAccordionItem.java similarity index 100% rename from src/com/quollwriter/ui/ChapterDescriptionAccordionItem.java rename to src/main/java/com/quollwriter/ui/ChapterDescriptionAccordionItem.java diff --git a/src/com/quollwriter/ui/ChapterFieldAccordionItem.java b/src/main/java/com/quollwriter/ui/ChapterFieldAccordionItem.java similarity index 99% rename from src/com/quollwriter/ui/ChapterFieldAccordionItem.java rename to src/main/java/com/quollwriter/ui/ChapterFieldAccordionItem.java index 47fbda44..6d29f596 100644 --- a/src/com/quollwriter/ui/ChapterFieldAccordionItem.java +++ b/src/main/java/com/quollwriter/ui/ChapterFieldAccordionItem.java @@ -25,7 +25,6 @@ import com.quollwriter.ui.actionHandlers.*; import com.quollwriter.ui.components.ActionAdapter; import com.quollwriter.ui.components.Header; -import com.quollwriter.ui.components.Markup; import com.quollwriter.ui.renderers.*; import com.quollwriter.text.*; diff --git a/src/main/java/com/quollwriter/ui/ChapterFindResultsBox.java b/src/main/java/com/quollwriter/ui/ChapterFindResultsBox.java new file mode 100644 index 00000000..772f104b --- /dev/null +++ b/src/main/java/com/quollwriter/ui/ChapterFindResultsBox.java @@ -0,0 +1,210 @@ +package com.quollwriter.ui; + +import java.util.List; +import java.util.Map; + +import java.awt.event.*; +import javax.swing.*; +import javax.swing.tree.*; +import javax.swing.text.*; + +import com.quollwriter.*; +import com.quollwriter.data.*; +import com.quollwriter.ui.renderers.*; +import com.quollwriter.ui.panels.*; +import com.quollwriter.ui.components.QTextEditor; + +public class ChapterFindResultsBox extends FindResultsBox +{ + + private Map> snippets = null; + private Object highlightId = null; + private QTextEditor highlightedEditor = null; + private String forObjType = null; + + public ChapterFindResultsBox (String title, + String iconType, + String forObjType, + AbstractProjectViewer viewer, + Map> snippets) + { + + super (title, + iconType, + forObjType, + viewer); + + this.forObjType = forObjType; + + this.snippets = snippets; + + } + + @Override + public String getId () + { + + return this.forObjType; + + } + + @Override + public void initTree () + { + + this.tree.setCellRenderer (new ChapterSnippetsTreeCellRenderer ());//new MultiLineTreeCellRenderer (this)); + + DefaultMutableTreeNode tn = new DefaultMutableTreeNode (this.viewer.getProject ()); + + UIUtils.createTree (this.snippets, + tn); + + // Create the tree. + ((DefaultTreeModel) this.tree.getModel ()).setRoot (tn); + + int c = 0; + + for (NamedObject n : this.snippets.keySet ()) + { + + c += this.snippets.get (n).size (); + + } + + this.count = c; + + this.updateItemCount (this.count); + + this.setContentVisible (true); + + } + + @Override + protected void handleViewObject (TreePath tp, + Object o) + { + + if (o instanceof Chapter) + { + + this.toggleTreePath (tp); + + DefaultMutableTreeNode node = (DefaultMutableTreeNode) tp.getLastPathComponent (); + + // Damn son this is fugly. + if ((node.getChildCount () == 1) + && + (this.tree.isExpanded (UIUtils.getTreePathForUserObject ((DefaultMutableTreeNode) this.tree.getModel ().getRoot (), + node.getUserObject ()))) + ) + { + + DefaultMutableTreeNode n = node.getFirstLeaf (); + + TreePath tpp = UIUtils.getTreePathForUserObject ((DefaultMutableTreeNode) this.tree.getModel ().getRoot (), + n.getUserObject ()); + + this.handleViewObject (tpp, + n.getUserObject ()); + + this.tree.setSelectionPath (tpp); + + } + + return; + + } + + if (o instanceof Segment) + { + + DefaultMutableTreeNode node = (DefaultMutableTreeNode) tp.getLastPathComponent (); + + // Get the offset. + DefaultMutableTreeNode parent = (DefaultMutableTreeNode) node.getParent (); + + Chapter c = (Chapter) parent.getUserObject (); + + Segment s = (Segment) o; + + this.showChapterSegment (c, + s); + + } else { + + this.toggleTreePath (tp); + + } + + } + + public void clearHighlight () + { + + if (this.highlightedEditor != null) + { + + this.highlightedEditor.removeHighlight (this.highlightId); + + } + + } + + public void showChapterSegment (final Chapter c, + final Segment s) + { + + this.clearHighlight (); + + final ChapterFindResultsBox _this = this; + + this.viewer.viewObject (c, + new ActionListener () + { + + public void actionPerformed (ActionEvent ev) + { + + AbstractEditorPanel p = _this.viewer.getEditorForChapter (c); + + try + { + + p.scrollToPosition (s.getBeginIndex ()); + + } catch (Exception e) { + + Environment.logError ("Unable to scroll to: " + s.getBeginIndex (), + e); + + return; + + } + + final QTextEditor ed = p.getEditor (); + + UIUtils.doLater (new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + _this.highlightId = ed.addHighlight (s.getBeginIndex (), + s.getEndIndex (), + null, + true); + + _this.highlightedEditor = ed; + + } + + }); + + } + + }); + + } + +} diff --git a/src/com/quollwriter/ui/ChapterGoalsAccordionItem.java b/src/main/java/com/quollwriter/ui/ChapterGoalsAccordionItem.java similarity index 100% rename from src/com/quollwriter/ui/ChapterGoalsAccordionItem.java rename to src/main/java/com/quollwriter/ui/ChapterGoalsAccordionItem.java diff --git a/src/com/quollwriter/ui/ChapterItemMoveHandler.java b/src/main/java/com/quollwriter/ui/ChapterItemMoveHandler.java similarity index 100% rename from src/com/quollwriter/ui/ChapterItemMoveHandler.java rename to src/main/java/com/quollwriter/ui/ChapterItemMoveHandler.java diff --git a/src/com/quollwriter/ui/ChapterItemMoveMouseHandler.java b/src/main/java/com/quollwriter/ui/ChapterItemMoveMouseHandler.java similarity index 100% rename from src/com/quollwriter/ui/ChapterItemMoveMouseHandler.java rename to src/main/java/com/quollwriter/ui/ChapterItemMoveMouseHandler.java diff --git a/src/main/java/com/quollwriter/ui/ChapterItemTransferHandler.java b/src/main/java/com/quollwriter/ui/ChapterItemTransferHandler.java new file mode 100644 index 00000000..12999366 --- /dev/null +++ b/src/main/java/com/quollwriter/ui/ChapterItemTransferHandler.java @@ -0,0 +1,155 @@ +package com.quollwriter.ui; + +import java.awt.Point; +import java.awt.event.*; +import java.awt.datatransfer.*; + +import javax.swing.*; + +import com.quollwriter.*; +import com.quollwriter.ui.panels.*; +import com.quollwriter.ui.actionHandlers.*; +import com.quollwriter.data.*; + +public class ChapterItemTransferHandler extends TransferHandler +{ + + private IconColumn ic = null; + private ChapterItemMoveHandler moveHandler = null; + + public ChapterItemTransferHandler (IconColumn ic) + { + + this.ic = ic; + + this.moveHandler = new ChapterItemMoveHandler (this.ic); + + } + + public void setItem (ChapterItem item) + { + + this.moveHandler.setItem (item); + + } + + public Icon getVisualRepresentation (Transferable t) + { + + // Never called... bug in java + return Environment.getObjectIcon (this.moveHandler.getItem (), + Constants.ICON_COLUMN); + + } + + public int getSourceActions (JComponent comp) + { + + return TransferHandler.COPY_OR_MOVE; + + } + + public void exportDone (JComponent comp, + Transferable t, + int action) + { + + this.moveHandler.dragFinished (); + + } + + public Transferable createTransferable (JComponent comp) + { + + ChapterItem item = this.moveHandler.getItem (); + + return new Transferable () + { + + @Override + public Object getTransferData (DataFlavor flavor) + { + + return item; + + } + + @Override + public boolean isDataFlavorSupported (DataFlavor flavor) + { + + return true; + + } + + @Override + public DataFlavor[] getTransferDataFlavors () + { + + try + { + + return new DataFlavor[] { new DataFlavor ("object/" + item.getObjectType ()) }; + + } catch (Exception e) { + + Environment.logError ("Unable to create data flavor for: " + + item.getObjectType (), + e); + + return new DataFlavor[0]; + + } + + } + + }; + + //return new javax.activation.DataHandler (item, "object/" + item.getObjectType ()); + + } + + public boolean importData (TransferHandler.TransferSupport supp) + { + + return true; + + } + + public void exportAsDrag (JComponent comp, + InputEvent ev, + int action) + { + + super.exportAsDrag (comp, + ev, + action); + + this.moveHandler.startDrag (); + + try + { + + Point xp = this.ic.getImagePanel (this.moveHandler.getItem ()).getBounds ().getLocation (); + + SwingUtilities.convertPointToScreen (xp, + this.ic); + + new java.awt.Robot ().mouseMove (xp.x, + xp.y); + + } catch (Exception e) {} + + } + + public boolean canImport (JComponent comp, + DataFlavor[] transferFlavors) + { + + this.moveHandler.doDrag (); + + return true; + + } + +} diff --git a/src/com/quollwriter/ui/ChapterItemViewPanelProvider.java b/src/main/java/com/quollwriter/ui/ChapterItemViewPanelProvider.java similarity index 100% rename from src/com/quollwriter/ui/ChapterItemViewPanelProvider.java rename to src/main/java/com/quollwriter/ui/ChapterItemViewPanelProvider.java diff --git a/src/com/quollwriter/ui/ChapterItemViewPopupProvider.java b/src/main/java/com/quollwriter/ui/ChapterItemViewPopupProvider.java similarity index 100% rename from src/com/quollwriter/ui/ChapterItemViewPopupProvider.java rename to src/main/java/com/quollwriter/ui/ChapterItemViewPopupProvider.java diff --git a/src/com/quollwriter/ui/ChapterItemViewer.java b/src/main/java/com/quollwriter/ui/ChapterItemViewer.java similarity index 100% rename from src/com/quollwriter/ui/ChapterItemViewer.java rename to src/main/java/com/quollwriter/ui/ChapterItemViewer.java diff --git a/src/com/quollwriter/ui/ChapterPlanAccordionItem.java b/src/main/java/com/quollwriter/ui/ChapterPlanAccordionItem.java similarity index 100% rename from src/com/quollwriter/ui/ChapterPlanAccordionItem.java rename to src/main/java/com/quollwriter/ui/ChapterPlanAccordionItem.java diff --git a/src/com/quollwriter/ui/ChapterProblemResultsBox.java b/src/main/java/com/quollwriter/ui/ChapterProblemResultsBox.java similarity index 100% rename from src/com/quollwriter/ui/ChapterProblemResultsBox.java rename to src/main/java/com/quollwriter/ui/ChapterProblemResultsBox.java diff --git a/src/com/quollwriter/ui/ChaptersAccordionItem.java b/src/main/java/com/quollwriter/ui/ChaptersAccordionItem.java similarity index 99% rename from src/com/quollwriter/ui/ChaptersAccordionItem.java rename to src/main/java/com/quollwriter/ui/ChaptersAccordionItem.java index cd701a8f..2882d001 100644 --- a/src/com/quollwriter/ui/ChaptersAccordionItem.java +++ b/src/main/java/com/quollwriter/ui/ChaptersAccordionItem.java @@ -24,7 +24,7 @@ public class ChaptersAccordionItem extends ProjectObjectsAccordionItem 0; i--) + { + + vers.add (" " + i); + + } + + final JComboBox versions = new JComboBox (vers); + + versBox.add (versions); + versBox.add (Box.createHorizontalStrut (5)); + + JButton upgradeButton = UIUtils.createButton ("Run"); + versBox.add (upgradeButton); + versBox.add (Box.createHorizontalGlue ()); + + upgradeButton.addActionListener (new ActionListener () + { + + public void actionPerformed (ActionEvent ev) + { + + int ver = -1; + + try + { + + ver = Integer.parseInt ((versions.getSelectedItem () + "").trim ()); + + } catch (Exception e) { + + return; + + } + + try + { + + pv.getObjectManager ().forceRunUpgradeScript (ver); + + } catch (Exception e) { + + UIUtils.showErrorMessage (_this, + "Unable to upgrade to version: " + ver + " see the log for details."); + + Environment.logError ("Unable to upgrade to version: " + ver, + e); + + } + + } + + }); + + builder.addLabel ("Upgrade to version", + cc.xy (1, + row)); + + builder.add (versBox, + cc.xy (3, + row)); + + row += 2; + + JPanel p = builder.getPanel (); + p.setOpaque (false); + p.setAlignmentX (Component.LEFT_ALIGNMENT); + p.setBorder (new EmptyBorder (5, 10, 10, 5)); + + bprops.add (p); + + JSplitPane sp = new JSplitPane (JSplitPane.HORIZONTAL_SPLIT); + sp.setAlignmentX (Component.LEFT_ALIGNMENT); + sp.setDividerLocation (0.5f); + + //bprops.add (sp); + + final JTextArea console = new JTextArea (); + console.setMargin (new Insets (5, + 5, + 5, + 5)); + console.setFont (new Font ("Consolas", + Font.PLAIN, + 12)); + // console.setBorder (null); + + JScrollPane scroll = new JScrollPane (console); + scroll.setBorder (null); + scroll.getViewport ().setBorder (null); + scroll.setAlignmentX (Component.LEFT_ALIGNMENT); + + Box b = new Box (BoxLayout.PAGE_AXIS); + b.add (scroll); + + // Add a button bar. + + sp.setTopComponent (b); + + + Vector colNames = new Vector (); + + /* + JTable tab = new JTable (data, + colNames); + + bprops.add (new JScrollPane (tab)); + */ + return bprops; + + } + + private JComponent createPropertiesPanel (Properties ps) + { + + Box bprops = new Box (BoxLayout.PAGE_AXIS); + bprops.setBorder (new EmptyBorder (10, + 3, + 3, + 3)); + + java.util.List props = ps.getProperties (); + + try + { + + Query q = new Query (); + q.parse ("SELECT * FROM " + AbstractProperty.class.getName () + " ORDER BY iD"); + + QueryResults qr = q.execute (ps.getProperties ()); + + props = qr.getResults (); + + } catch (Exception e) + { + + Environment.logError ("Unable to execute sort query on properties", + e); + + } + + Vector data = new Vector (); + + for (int i = 0; i < props.size (); i++) + { + + Vector d = new Vector (); + + AbstractProperty p = (AbstractProperty) props.get (i); + + d.add (p.getID ()); + + d.add (ps.getDefinedIn (p).getId ()); + + d.add (p.getValue ()); + + data.add (d); + + } + + Vector colNames = new Vector (); + colNames.add ("Name"); + colNames.add ("Scope"); + colNames.add ("Value"); + + JTable tab = new JTable (data, + colNames); + + bprops.add (new JScrollPane (tab)); + + return bprops; + + } + + private JComponent createAchievementsPanel () + { + + Box bprops = new Box (BoxLayout.PAGE_AXIS); + bprops.setBorder (new EmptyBorder (10, + 3, + 3, + 3)); + + Map> achieved = null; // TODO Environment.getAchievementsManager ().getAchievedAchievementIds (this.viewer); + + Vector data = new Vector (); + + Set user = achieved.get ("user"); + + for (String id : user) + { + + Vector d = new Vector (); + + d.add ("User"); + d.add (id); + + data.add (d); + + } + + Set project = achieved.get ("project"); + + if (project != null) + { + + for (String id : project) + { + + Vector d = new Vector (); + + d.add ("Project"); + d.add (id); + + data.add (d); + + } + + } + + Vector colNames = new Vector (); + colNames.add ("Type"); + colNames.add ("Id"); + + final JTable tab = new JTable (data, + colNames); + + bprops.add (new JScrollPane (tab)); + + bprops.add (Box.createVerticalStrut (10)); + + JButton b = new JButton ("Clear Selected Achievements"); + + b.setAlignmentX (Component.LEFT_ALIGNMENT); + + final DebugConsole _this = this; + + b.addActionListener (new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + // Get the selected rows. + int[] selRows = tab.getSelectedRows (); + + for (int i = selRows.length - 1; i > -1; i--) + { + + DefaultTableModel mod = (DefaultTableModel) tab.getModel (); + + String id = (String) mod.getValueAt (i, 1); + + try + { + + Environment.getAchievementsManager ().removeAchievedAchievement (((String) mod.getValueAt (i, 0)).toLowerCase (), + id, + null); + // TODO _this.viewer); + + } catch (Exception e) { + + UIUtils.showErrorMessage (_this, + "Unable to remove achievement: " + id); + + Environment.logError ("Unable to remove achievement: " + id, + e); + + } + + mod.removeRow (i); + + } + + } + + }); + + bprops.add (b); + + return bprops; + + } + + private JComponent createLogPanel () + throws IOException + { + + JTabbedPane tp = new JTabbedPane (); + + tp.setBorder (new EmptyBorder (10, + 5, + 5, + 5)); + + Box errorlog = new Box (BoxLayout.PAGE_AXIS); + errorlog.setBorder (new EmptyBorder (3, + 3, + 3, + 3)); +/* +TODO Remove + File file = Environment.getErrorLogFile (); + + JTextField f = UIUtils.createTextField (); + f.setText (file + ", can write: " + file.canWrite () + ", can read: " + file.canRead ()); + + f.setMaximumSize (new Dimension (Short.MAX_VALUE, + f.getPreferredSize ().height)); + f.setAlignmentX (Component.LEFT_ALIGNMENT); + + errorlog.add (f); + + errorlog.add (Box.createVerticalStrut (5)); + + JTextArea t = new JTextArea (); + + try + { + + t.setText (Utils.getFileContentAsString (file.toPath ())); + + } catch (Exception e) + { + + try + { + + t.setText ("Unable to read log file: " + + file + + ", Exception: \n" + + Utils.getExceptionTraceAsString (e)); + + } catch (Exception ee) + { + } + + } + + errorlog.add (Box.createVerticalStrut (5)); + + errorlog.add (new JScrollPane (t)); + + tp.add ("Error", + errorlog); + + Box sqllog = new Box (BoxLayout.PAGE_AXIS); + sqllog.setBorder (new EmptyBorder (3, + 3, + 3, + 3)); + + file = Environment.getLogFile (); + + f = UIUtils.createTextField (); + f.setText (file + ", can write: " + file.canWrite () + ", can read: " + file.canRead ()); + f.setAlignmentX (Component.LEFT_ALIGNMENT); + + f.setMaximumSize (new Dimension (Short.MAX_VALUE, + f.getPreferredSize ().height)); + + sqllog.add (f); + + sqllog.add (Box.createVerticalStrut (5)); + + t = new JTextArea (); + + try + { + + t.setText (Utils.getFileContentAsString (file.toPath ())); + + } catch (Exception e) + { + + try + { + + t.setText ("Unable to read log file: " + + file + + ", Exception: \n" + + Utils.getExceptionTraceAsString (e)); + + } catch (Exception ee) + { + } + + } + + sqllog.add (Box.createVerticalStrut (5)); + + sqllog.add (new JScrollPane (t)); + + tp.add ("SQL", + sqllog); + + Box genlog = new Box (BoxLayout.PAGE_AXIS); + genlog.setBorder (new EmptyBorder (3, + 3, + 3, + 3)); + + file = Environment.getGeneralLogFile (); + + f = UIUtils.createTextField (); + f.setText (file + ", can write: " + file.canWrite () + ", can read: " + file.canRead ()); + f.setAlignmentX (Component.LEFT_ALIGNMENT); + + f.setMaximumSize (new Dimension (Short.MAX_VALUE, + f.getPreferredSize ().height)); + + genlog.add (f); + + genlog.add (Box.createVerticalStrut (5)); + + t = new JTextArea (); + + try + { + + t.setText (Utils.getFileContentAsString (file.toPath ())); + + } catch (Exception e) + { + + try + { + + t.setText ("Unable to read log file: " + + file + + ", Exception: \n" + + Utils.getExceptionTraceAsString (e)); + + } catch (Exception ee) + { + } + + } + + genlog.add (Box.createVerticalStrut (5)); + + genlog.add (new JScrollPane (t)); + + tp.add ("General", + genlog); +*/ + return tp; + + } + +} diff --git a/src/com/quollwriter/ui/DefaultChapterItemViewPopupProvider.java b/src/main/java/com/quollwriter/ui/DefaultChapterItemViewPopupProvider.java similarity index 100% rename from src/com/quollwriter/ui/DefaultChapterItemViewPopupProvider.java rename to src/main/java/com/quollwriter/ui/DefaultChapterItemViewPopupProvider.java diff --git a/src/com/quollwriter/ui/DefaultQuollPanelAction.java b/src/main/java/com/quollwriter/ui/DefaultQuollPanelAction.java similarity index 100% rename from src/com/quollwriter/ui/DefaultQuollPanelAction.java rename to src/main/java/com/quollwriter/ui/DefaultQuollPanelAction.java diff --git a/src/main/java/com/quollwriter/ui/DefaultQuollWriterUpdater.java b/src/main/java/com/quollwriter/ui/DefaultQuollWriterUpdater.java new file mode 100644 index 00000000..7c76bf41 --- /dev/null +++ b/src/main/java/com/quollwriter/ui/DefaultQuollWriterUpdater.java @@ -0,0 +1,752 @@ +package com.quollwriter.ui; + +import java.awt.*; +import java.awt.event.*; + +import java.io.*; + +import java.net.*; + +import java.security.*; + +import java.util.*; +import java.util.zip.*; + +import javax.swing.*; +import javax.swing.border.*; +import javax.swing.table.*; + +import com.gentlyweb.properties.*; + +import com.jgoodies.forms.builder.*; +import com.jgoodies.forms.factories.*; +import com.jgoodies.forms.layout.*; + +import com.quollwriter.*; + +import com.quollwriter.data.*; +import com.quollwriter.data.comparators.*; +import com.quollwriter.ui.*; +import com.quollwriter.ui.components.*; + +import static com.quollwriter.LanguageStrings.*; +import static com.quollwriter.uistrings.UILanguageStringsManager.getUIString; + +public class DefaultQuollWriterUpdater //implements QuollWriterUpdater +{ + + private AbstractViewer viewer = null; + private JProgressBar progressBar = null; + private boolean stop = false; + private Version version = null; + private long size = 0; + private byte[] digest = null; + private boolean beta = false; + private Notification downloadNotification = null; + private JTextPane help = null; + private JButton cancel = null; + + public DefaultQuollWriterUpdater () + { + + } + + public URL getUpgradeURL (Version version) + throws Exception + { + + String parms = "?version=" + version.getVersion (); + + return Environment.getSupportUrl (Constants.GET_UPGRADE_FILE_PAGE_PROPERTY_NAME, + parms); + + } + + private URL getNewsAndVersionCheckURL () + throws Exception + { + + String parms = "?"; + + if (UserProperties.getAsBoolean (Constants.OPTIN_TO_BETA_VERSIONS_PROPERTY_NAME)) + { + + parms += "beta=true&"; + + } + + String lastVersionCheckTime = UserProperties.get (Constants.LAST_VERSION_CHECK_TIME_PROPERTY_NAME); + + if (lastVersionCheckTime != null) + { + + parms += "since=" + lastVersionCheckTime; + + } + + return Environment.getSupportUrl (Constants.GET_LATEST_VERSION_PAGE_PROPERTY_NAME, + parms); + + } + + private void doDownload () + { + + final java.util.List prefix = new ArrayList<> (); + prefix.add (LanguageStrings.upgrade); + prefix.add (LanguageStrings.download); + + final DefaultQuollWriterUpdater _this = this; + + this.progressBar = new JProgressBar (); + + this.progressBar.setAlignmentX (Component.LEFT_ALIGNMENT); + + int ind = 0; + + Box c = new Box (BoxLayout.Y_AXIS); + + this.help = UIUtils.createHelpTextPane (String.format (Environment.getUIString (prefix, + LanguageStrings.start), + //"Downloading upgrade file for new version: %s", + version), + viewer); + this.help.setAlignmentX (Component.LEFT_ALIGNMENT); + this.help.setSize (new Dimension (500, 50)); + + this.help.setMaximumSize (new Dimension (Short.MAX_VALUE, + Short.MAX_VALUE)); + this.help.setBorder (null); + + c.add (this.help); + + c.add (Box.createVerticalStrut (5)); + + Box pb = new Box (BoxLayout.X_AXIS); + + pb.setAlignmentX (Component.LEFT_ALIGNMENT); + pb.add (this.progressBar); + + pb.add (Box.createHorizontalStrut (5)); + + this.progressBar.setPreferredSize (new Dimension (500, + 20)); + this.progressBar.setMaximumSize (new Dimension (500, + 20)); + + this.cancel = UIUtils.createButton (Environment.getUIString (LanguageStrings.buttons, + LanguageStrings.cancel)); + //"Cancel"); + + pb.add (this.cancel); + + pb.add (Box.createHorizontalGlue ()); + + this.cancel.addActionListener (new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + _this.stop = true; + + _this.downloadNotification.removeNotification (); + + } + + }); + + c.add (pb); + + this.downloadNotification = viewer.addNotification (c, + Constants.DOWNLOAD_ICON_NAME, + -1); + + this.downloadNotification.setOnRemove (new ActionListener () + { + + public void actionPerformed (ActionEvent ev) + { + + _this.stop = true; + + } + + }); + + File tf = null; + + try + { + + tf = File.createTempFile ("QuollWriter-install-" + _this.version.getVersion () + ".", + ".exe"); + +// tf.deleteOnExit (); + + } catch (Exception e) + { + + Environment.logError ("Unable to create temp file for: " + + _this.version + ".exe", + e); + + _this.showError (Environment.getUIString (prefix, + LanguageStrings.errors, + LanguageStrings.cantcreatetemporaryfile)); + //"Unable to create the temporary file for the download."); + + return; + + } + + final File outFile = tf; + + final javax.swing.Timer watch = new javax.swing.Timer (750, + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + int length = (int) outFile.length (); + + float v = (float) length / (float) _this.size; + + float perc = v * 90f; + + _this.help.setText (String.format (Environment.getUIString (prefix, + LanguageStrings.inprogress), + //"Downloading upgrade file for new version %s - %s of %s bytes", + _this.version.getVersion (), + Environment.formatNumber (length), + Environment.formatNumber (size))); + + _this.setProgress ((int) perc); + + _this.help.setSize (new Dimension (500, _this.help.getPreferredSize ().height)); + _this.downloadNotification.validate (); + _this.downloadNotification.repaint (); + + } + + }); + + Runnable r = new Runnable () + { + + @Override + public void run () + { + + try + { + + URL u = _this.getUpgradeURL (_this.version); + + HttpURLConnection conn = (HttpURLConnection) u.openConnection (); + + conn.setDoInput (true); + conn.setDoOutput (true); + + conn.connect (); + + int p = 0; + + BufferedOutputStream out = new BufferedOutputStream (new FileOutputStream (outFile)); + + BufferedInputStream in = new BufferedInputStream (conn.getInputStream ()); + + byte[] buf = new byte[65536]; + + int bRead = -1; + + while ((bRead = in.read (buf)) != -1) + { + + if (_this.stop) + { + + in.close (); + out.flush (); + out.close (); + + return; + + } + + out.write (buf, + 0, + bRead); + + } + + in.close (); + out.flush (); + out.close (); + + _this.setProgress (90); + + watch.stop (); + + if (_this.stop) + { + + return; + + } + + UIUtils.doLater (new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + _this.help.setText (Environment.getUIString (LanguageStrings.upgrade, + LanguageStrings.checkingfile)); + //)"Checking the file...")); + + } + + }); + + // Calculate a hash code. + MessageDigest md = MessageDigest.getInstance ("SHA-256"); + + DigestInputStream dis = new DigestInputStream (new BufferedInputStream (new FileInputStream (outFile)), + md); + + buf = new byte[65536]; + + bRead = -1; + + String ll = outFile.length () + ""; + + ll = ll.substring (ll.length () - 1); + + int v = 0; + + try + { + + v = Integer.parseInt (ll); + + } catch (Exception e) + { + } + + boolean odd = ((v % 2) == 0); + + while ((bRead = dis.read (buf)) != -1) + { + + if (odd) + { + + md.update (ll.getBytes ()); + + } else + { + + md.update (_this.version.getVersion ().getBytes ()); + + } + + } + + dis.close (); + + byte[] ddigest = md.digest (); + + if (_this.stop) + { + + return; + + } + + _this.setProgress (95); + + // Digest calculated from download file is not the same as gained from the server. + String digestNotEqualError = Environment.getUIString (prefix, + LanguageStrings.errors, + LanguageStrings.digestinvalid); + //"Digest calculated from download file is not the same as gained from the server."; + + // Compare the digest with that gained from the server. + if (!Arrays.equals (ddigest, + _this.digest)) + { + + throw new GeneralException (digestNotEqualError); + + } + + UIUtils.doLater (new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + _this.help.setText (Environment.getUIString (prefix, + LanguageStrings.complete)); + //"Download of upgrade file complete..."); + + _this.cancel.setVisible (false); + + } + + }); + + _this.setProgress (100); + + _this.downloadNotification.removeNotification (); + + Map buts = new LinkedHashMap (); + + buts.put (Environment.getUIString (LanguageStrings.upgrade, + LanguageStrings.restart, + LanguageStrings.buttons, + LanguageStrings.exitnow), + //"Yes, exit now", + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + _this.closeDown (); + + } + + }); + + buts.put (Environment.getUIString (LanguageStrings.upgrade, + LanguageStrings.restart, + LanguageStrings.buttons, + LanguageStrings.exitlater), + //"No, I'll exit later", + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + // Do nothing. + + } + + }); + + UIUtils.createQuestionPopup (_this.viewer, + Environment.getUIString (LanguageStrings.upgrade, + LanguageStrings.restart, + LanguageStrings.title), + //"Restart Quoll Writer?", + null, + String.format (getUIString (upgrade,restart,text), + //"Version %s of Quoll Writer has been downloaded. To complete the upgrade you must exit Quoll Writer, the installer will then guide you through the rest of the upgrade process.

    Would you like to exit now?", + _this.version), + buts, + null, + null); + + Environment.addDoOnShutdown (new Runnable () + { + + @Override + public void run () + { + + try + { + + java.util.List args = new ArrayList (); + args.add (outFile.getPath ()); + + ProcessBuilder pb = new ProcessBuilder (args); + pb.start (); + + // TODO Check that the JVM is exiting... + + } catch (Exception e) { + + Environment.logError ("Unable to run upgrade file: " + + outFile.getPath (), + e); + + } + + } + + }); + + } catch (Exception e) + { + + Environment.logError ("Unable to download the upgrade file", + e); + + _this.showError (Environment.getUIString (prefix, + LanguageStrings.errors, + LanguageStrings.unabletodownload)); + //"Unable to download the upgrade file."); + + } + + } + + }; + + Thread t = new Thread (r); + + t.setDaemon (true); + t.setPriority (Thread.MIN_PRIORITY); + + t.start (); + + watch.start (); + + } + + public void doUpdate (AbstractViewer viewer) + { + + final DefaultQuollWriterUpdater _this = this; + + this.viewer = viewer; + + try + { + + URL u = this.getNewsAndVersionCheckURL (); + + HttpURLConnection conn = (HttpURLConnection) u.openConnection (); + + conn.setDoInput (true); + conn.setDoOutput (true); + + conn.connect (); + + BufferedInputStream bin = new BufferedInputStream (conn.getInputStream ()); + + ByteArrayOutputStream bout = new ByteArrayOutputStream (); + + Utils.streamTo (bin, + bout, + 8192); + + UserProperties.set (Constants.LAST_VERSION_CHECK_TIME_PROPERTY_NAME, + String.valueOf (System.currentTimeMillis ())); + + String info = new String (bout.toByteArray (), + "utf-8"); + + // Should be json. + Map data = (Map) JSONDecoder.decode (info); + + Map version = (Map) data.get ("version"); + + if (version != null) + { + + this.version = new Version ((String) version.get ("version")); + + this.size = ((Number) version.get ("size")).longValue (); + + this.digest = com.quollwriter.Base64.decode ((String) version.get ("digest")); + + if (Environment.getQuollWriterVersion ().isNewer (this.version)) + { + + UIUtils.doLater (new ActionListener () + { + + public void actionPerformed (ActionEvent ev) + { + + Box ib = new Box (BoxLayout.Y_AXIS); + ib.setMaximumSize (new Dimension (Short.MAX_VALUE, + Short.MAX_VALUE)); + + JTextPane p = UIUtils.createHelpTextPane (String.format (Environment.getUIString (LanguageStrings.upgrade, + LanguageStrings.newversionavailable, + LanguageStrings.text), + //"A new version of %s is available. View the changes.", + // Constants.QUOLL_WRITER_NAME, + _this.version.getVersion ().replace (".", + "_")), + viewer); + + p.setAlignmentX (Component.LEFT_ALIGNMENT); + + p.setMaximumSize (new Dimension (Short.MAX_VALUE, + Short.MAX_VALUE)); + p.setBorder (null); + + ib.add (p); + ib.add (Box.createVerticalStrut (5)); + + JButton installNow = UIUtils.createButton (Environment.getUIString (LanguageStrings.upgrade, + LanguageStrings.newversionavailable, + LanguageStrings.buttons, + LanguageStrings.download)); + //"Download now"); + JButton installLater = UIUtils.createButton (Environment.getUIString (LanguageStrings.upgrade, + LanguageStrings.newversionavailable, + LanguageStrings.buttons, + LanguageStrings.later)); + //"Later"); + + Box bb = new Box (BoxLayout.X_AXIS); + bb.add (installNow); + bb.add (Box.createHorizontalStrut (5)); + bb.add (installLater); + bb.setAlignmentX (Component.LEFT_ALIGNMENT); + + ib.add (bb); + ib.add (Box.createVerticalStrut (5)); + + final ActionListener hasVersionNotification = _this.viewer.addNotification (ib, + "notify", + 600); + + installNow.addActionListener (new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + hasVersionNotification.actionPerformed (ev); + + _this.doDownload (); + + } + + }); + + installLater.addActionListener (hasVersionNotification); + + } + + }); + + } + + } + + } catch (Exception e) + { + + Environment.logError ("Unable to perform update check", + e); + + } + + } + + private void showError (String m) + { + + UIUtils.showErrorMessage (this.viewer, + m); + + this.downloadNotification.removeNotification (); + + } + + private void showGeneralError () + { + + this.showError (String.format (getUIString (LanguageStrings.upgrade, + LanguageStrings.download, + LanguageStrings.errors, + LanguageStrings.general), + //"Unable to download/install the new version. Click here to download the latest version from the Quoll Writer website", + UserProperties.get (Constants.QUOLLWRITER_DOWNLOADS_URL_PROPERTY_NAME))); + + this.downloadNotification.removeNotification (); + + } + + public void setProgress (int p) + { + + final DefaultQuollWriterUpdater _this = this; + + UIUtils.doLater (new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + _this.progressBar.setValue (p); + _this.downloadNotification.validate (); + _this.downloadNotification.repaint (); + + } + + }); + + } + + private void closeDown () + { + + final DefaultQuollWriterUpdater _this = this; + + // TODO Environment.doForOpenViewers -> close () +/* +TODO + Map open = Environment.getOpenProjects (); + + // Get the first, close it. + if (open.size () > 0) + { + + AbstractProjectViewer pv = open.values ().iterator ().next (); + + pv.setState (java.awt.Frame.NORMAL); + pv.toFront (); + + pv.close (false, + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + _this.closeDown (); + + } + + }); + + return; + + } else { + + if (Environment.getAllProjectsViewer () != null) + { + + Environment.getAllProjectsViewer ().close (null); + + } else { + + Environment.closeDown (); + + } + + } +*/ + + } + +} diff --git a/src/com/quollwriter/ui/DefaultTransferHandler.java b/src/main/java/com/quollwriter/ui/DefaultTransferHandler.java similarity index 100% rename from src/com/quollwriter/ui/DefaultTransferHandler.java rename to src/main/java/com/quollwriter/ui/DefaultTransferHandler.java diff --git a/src/main/java/com/quollwriter/ui/DictionaryManager.java b/src/main/java/com/quollwriter/ui/DictionaryManager.java new file mode 100644 index 00000000..ff1a900c --- /dev/null +++ b/src/main/java/com/quollwriter/ui/DictionaryManager.java @@ -0,0 +1,233 @@ +package com.quollwriter.ui; + +import java.awt.*; +import java.awt.event.*; + +import java.io.File; + +import java.net.*; + +import java.text.*; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.StringTokenizer; +import java.util.Vector; +import java.util.Set; +import java.util.TreeSet; +import java.util.HashSet; + +import javax.swing.*; +import javax.swing.border.*; +import javax.swing.filechooser.*; +import javax.swing.table.*; +import javax.swing.tree.*; +import javax.swing.event.*; + +//import com.jgoodies.forms.builder.*; +//import com.jgoodies.forms.factories.*; +//import com.jgoodies.forms.layout.*; + +import com.quollwriter.*; + +import com.quollwriter.data.*; +import com.quollwriter.data.comparators.*; +import com.quollwriter.events.*; + +import static com.quollwriter.LanguageStrings.*; +import static com.quollwriter.Environment.getUIString; + +import com.quollwriter.ui.components.*; +import com.quollwriter.ui.renderers.*; + +public class DictionaryManager extends TypesEditor implements TypesHandler +{ + + //private FileWatcher watcher = null; + private Set listeners = new HashSet<> (); + private UserDictionaryProvider userDict = null; + + public DictionaryManager (final AbstractViewer pv) + throws Exception + { + + super (pv); + + this.userDict = new UserDictionaryProvider (); + + } + + @Override + public boolean renameType (String oldType, + String newType, + boolean reload) + { + + this.removeType (oldType, + reload); + this.addType (newType, + reload); + + return true; + + } + + @Override + public boolean removeType (String type, + boolean reload) + { + + this.userDict.removeWord (type); + + this.viewer.fireProjectEvent (ProjectEvent.PERSONAL_DICTIONARY, + ProjectEvent.REMOVE_WORD, + type); + + return true; + + } + + @Override + public void addType (String t, + boolean reload) + { + + this.userDict.addWord (t); + + this.viewer.fireProjectEvent (ProjectEvent.PERSONAL_DICTIONARY, + ProjectEvent.ADD_WORD, + t); + + } + + @Override + public Set getTypes () + { + + // Get the words. + // TODO Use the path. + File userDict = DictionaryProvider.getUserDictionaryFilePath ().toFile (); + + Set words = new TreeSet<> (); + + String w = null; + + try + { + + w = Utils.getFileContentAsString (userDict.toPath ()); + + } catch (Exception e) + { + + w = ""; + + Environment.logError ("Unable to get user dictionary file: " + + userDict, + e); + + } + + StringTokenizer tt = new StringTokenizer (w, + String.valueOf ('\n')); + + while (tt.hasMoreTokens ()) + { + + words.add (tt.nextToken ()); + + } + + return words; + + } + + @Override + public void removePropertyChangedListener (PropertyChangedListener l) + { + + this.listeners.remove (l); + + } + + @Override + public void addPropertyChangedListener (PropertyChangedListener l) + { + + this.listeners.add (l); + + } + + @Override + public TypesHandler getTypesHandler () + { + + return this; + + } + + @Override + public String getNewItemsTitle () + { + + return getUIString (dictionary,manage,newwords,title); + } + + @Override + public String getNewItemsHelp () + { + + return getUIString (dictionary,manage,newwords,text); + } + + @Override + public String getExistingItemsTitle () + { + + return getUIString (dictionary,manage,table,title); + + } + + @Override + public void init () + { + + super.init (); + + final DictionaryManager _this = this; + + //this.watcher = new FileWatcher (); + // TODO Use the Files.watch service instead. + // See Path.register + //this.watcher.addFile (DictionaryProvider.getUserDictionaryFilePath ().toFile ()); + + // TODO CHange to use a path and the Files.watchService. + /* + this.watcher.addFileChangeListener (new FileChangeListener () + { + + public void fileChanged (FileChangeEvent ev, + int types) + { + + // Tell the listeners about the change. + for (PropertyChangedListener l : _this.listeners) + { + + l.propertyChanged (new PropertyChangedEvent (_this, + "changed", + 0, + 0)); + + } + + } + + }, + FileChangeEvent.MODIFIED | FileChangeEvent.EXISTS); +*/ + //this.watcher.start (); + + } + +} diff --git a/src/com/quollwriter/ui/DragActionHandler.java b/src/main/java/com/quollwriter/ui/DragActionHandler.java similarity index 100% rename from src/com/quollwriter/ui/DragActionHandler.java rename to src/main/java/com/quollwriter/ui/DragActionHandler.java diff --git a/src/com/quollwriter/ui/EditItemTypes.java b/src/main/java/com/quollwriter/ui/EditItemTypes.java similarity index 95% rename from src/com/quollwriter/ui/EditItemTypes.java rename to src/main/java/com/quollwriter/ui/EditItemTypes.java index 2d489039..ab1ace70 100644 --- a/src/com/quollwriter/ui/EditItemTypes.java +++ b/src/main/java/com/quollwriter/ui/EditItemTypes.java @@ -21,10 +21,6 @@ import javax.swing.table.*; import javax.swing.tree.*; -import com.gentlyweb.utils.*; - -import com.gentlyweb.xml.*; - import com.jgoodies.forms.builder.*; import com.jgoodies.forms.factories.*; import com.jgoodies.forms.layout.*; diff --git a/src/com/quollwriter/ui/EditNoteTypes.java b/src/main/java/com/quollwriter/ui/EditNoteTypes.java similarity index 97% rename from src/com/quollwriter/ui/EditNoteTypes.java rename to src/main/java/com/quollwriter/ui/EditNoteTypes.java index 81a5eef5..23e3029b 100644 --- a/src/com/quollwriter/ui/EditNoteTypes.java +++ b/src/main/java/com/quollwriter/ui/EditNoteTypes.java @@ -2,8 +2,6 @@ import javax.swing.*; -import com.gentlyweb.utils.*; - import com.quollwriter.*; import static com.quollwriter.LanguageStrings.*; diff --git a/src/com/quollwriter/ui/EditPanel.java b/src/main/java/com/quollwriter/ui/EditPanel.java similarity index 100% rename from src/com/quollwriter/ui/EditPanel.java rename to src/main/java/com/quollwriter/ui/EditPanel.java diff --git a/src/com/quollwriter/ui/EditProjectStatuses.java b/src/main/java/com/quollwriter/ui/EditProjectStatuses.java similarity index 98% rename from src/com/quollwriter/ui/EditProjectStatuses.java rename to src/main/java/com/quollwriter/ui/EditProjectStatuses.java index 5e4a560b..53825e6b 100644 --- a/src/com/quollwriter/ui/EditProjectStatuses.java +++ b/src/main/java/com/quollwriter/ui/EditProjectStatuses.java @@ -2,8 +2,6 @@ import java.util.*; -import com.gentlyweb.utils.*; - import com.quollwriter.*; import com.quollwriter.events.*; diff --git a/src/com/quollwriter/ui/EditorPanePrinter.java b/src/main/java/com/quollwriter/ui/EditorPanePrinter.java similarity index 100% rename from src/com/quollwriter/ui/EditorPanePrinter.java rename to src/main/java/com/quollwriter/ui/EditorPanePrinter.java diff --git a/src/com/quollwriter/ui/ErrorWindow.java b/src/main/java/com/quollwriter/ui/ErrorWindow.java similarity index 98% rename from src/com/quollwriter/ui/ErrorWindow.java rename to src/main/java/com/quollwriter/ui/ErrorWindow.java index 44d36932..f8450ac8 100644 --- a/src/com/quollwriter/ui/ErrorWindow.java +++ b/src/main/java/com/quollwriter/ui/ErrorWindow.java @@ -10,8 +10,6 @@ import javax.swing.*; import javax.swing.border.*; -import com.gentlyweb.utils.*; - import com.jgoodies.forms.builder.*; import com.jgoodies.forms.factories.*; import com.jgoodies.forms.layout.*; diff --git a/src/com/quollwriter/ui/ExportProject.java b/src/main/java/com/quollwriter/ui/ExportProject.java similarity index 99% rename from src/com/quollwriter/ui/ExportProject.java rename to src/main/java/com/quollwriter/ui/ExportProject.java index 6c4fa461..628f4df3 100644 --- a/src/com/quollwriter/ui/ExportProject.java +++ b/src/main/java/com/quollwriter/ui/ExportProject.java @@ -19,8 +19,6 @@ import javax.swing.filechooser.*; import javax.swing.tree.*; -import com.gentlyweb.xml.*; - import com.jgoodies.forms.builder.*; import com.jgoodies.forms.factories.*; import com.jgoodies.forms.layout.*; @@ -129,7 +127,8 @@ public boolean handleFinish () dir.mkdirs (); - de.exportProject (dir); + de.exportProject (dir.toPath (), + null); this.viewer.createActionLogEntry (this.proj, "Exported project to directory: " + @@ -216,7 +215,7 @@ public DocumentExporter getExporter () try { - de = (DocumentExporter) c.newInstance (); + de = (DocumentExporter) c.getDeclaredConstructor ().newInstance (); de.setProject (this.proj); this.exporters.put (fileType, diff --git a/src/com/quollwriter/ui/FileFinder.java b/src/main/java/com/quollwriter/ui/FileFinder.java similarity index 100% rename from src/com/quollwriter/ui/FileFinder.java rename to src/main/java/com/quollwriter/ui/FileFinder.java diff --git a/src/main/java/com/quollwriter/ui/FindResultsBox.java b/src/main/java/com/quollwriter/ui/FindResultsBox.java new file mode 100644 index 00000000..13752ab0 --- /dev/null +++ b/src/main/java/com/quollwriter/ui/FindResultsBox.java @@ -0,0 +1,142 @@ +package com.quollwriter.ui; + +import java.awt.event.*; + +import javax.swing.*; +import javax.swing.tree.*; + +import com.quollwriter.data.*; + +public abstract class FindResultsBox extends ProjectObjectsAccordionItem +{ + + protected int count = 0; + + private String forObjType = null; + + public FindResultsBox (String title, + ImageIcon icon, + E viewer) + { + + super (title, + icon, + viewer); + + this.getTree ().getSelectionModel().setSelectionMode (TreeSelectionModel.SINGLE_TREE_SELECTION); + + } + + public FindResultsBox (String title, + String iconType, + String forObjType, + E viewer) + { + + super (title, + iconType, + viewer); + + this.forObjType = forObjType; + + this.getTree ().getSelectionModel().setSelectionMode (TreeSelectionModel.SINGLE_TREE_SELECTION); + + } + + @Override + public String getId () + { + + return this.forObjType; + + } + + @Override + public boolean showItemCountOnHeader () + { + + return true; + + } + + public void exapndAllResultsInTree () + { + + UIUtils.expandAllNodesWithChildren (this.tree); + + } + + public int getItemCount () + { + + return this.count; + + } + + @Override + public void reloadTree () + { + + } + + public void fillTreePopupMenu (JPopupMenu m, + MouseEvent ev) + { + + } + + @Override + public TreeCellEditor getTreeCellEditor (AbstractProjectViewer pv) + { + + return null; + + } + + public int getViewObjectClickCount (Object d) + { + + return 1; + + } + + @Override + public boolean isAllowObjectPreview () + { + + return true; + + } + + public boolean isTreeEditable () + { + + return false; + + } + + public boolean isDragEnabled () + { + + return false; + + } + + @Override + public DragActionHandler getTreeDragActionHandler (AbstractProjectViewer pv) + { + + return null; + + } +/* + public void clearResults () + { + + ((DefaultTreeModel) this.tree.getModel ()).setRoot (null); + + this.setVisible (false); + + } +*/ +} diff --git a/src/main/java/com/quollwriter/ui/FirstUseWizard.java b/src/main/java/com/quollwriter/ui/FirstUseWizard.java new file mode 100644 index 00000000..9d7f362f --- /dev/null +++ b/src/main/java/com/quollwriter/ui/FirstUseWizard.java @@ -0,0 +1,1630 @@ +package com.quollwriter.ui; + +import java.io.*; +import java.net.*; +import java.util.*; +import java.awt.event.*; +import javax.swing.*; +import javax.swing.tree.*; +import javax.swing.filechooser.*; + +import com.jgoodies.forms.builder.*; +import com.jgoodies.forms.factories.*; +import com.jgoodies.forms.layout.*; + +import com.quollwriter.*; +import com.quollwriter.events.*; +import com.quollwriter.data.*; +import com.quollwriter.importer.*; +import com.quollwriter.data.comparators.*; +import com.quollwriter.ui.renderers.*; +import com.quollwriter.text.*; +import com.quollwriter.uistrings.*; + +import static com.quollwriter.LanguageStrings.*; +import static com.quollwriter.uistrings.UILanguageStringsManager.getUIString; + +public class FirstUseWizard extends PopupWizard +{ + + private final static String SELECT_FILE_STAGE = "select-file"; + private final static String DECIDE_STAGE = "decide"; + private final static String START_STAGE = "start"; + private static final String EXISTING_STAGE = "existing"; + private static final String NEW_PROJECT_STAGE = "newproject"; + private static final String IMPORT_STAGE = "import"; + private static final String SELECT_PROJECT_DB_STAGE = "select-project-db"; + private static final String SPELL_CHECK_LANG_STAGE = "spell-check-lang"; + + private ImportTransferHandlerOverlay importOverlay = null; + private ImportProject importProject = null; + private JRadioButton importFile = null; + private JTree itemsTree = null; + private Project importProj = null; + + private JRadioButton createNewProject = null; + private NewProjectPanel newProjectPanel = null; + + private JRadioButton selectProjectDB = null; + private JRadioButton findProjects = null; + private FileFinder projDBFind = null; + private JLabel projDBFindError = null; + private JLabel dlUILangFile = null; + private JLabel dlUILangError = null; + + private FileFinder fileFind = null; + private JLabel fileFindError = null; + + public FirstUseWizard () + { + + super (null); + + final FirstUseWizard _this = this; + + this.importFile = new JRadioButton (); + this.createNewProject = new JRadioButton (); + this.findProjects = new JRadioButton (); + this.selectProjectDB = new JRadioButton (); + this.importFile.setSelected (false); + this.createNewProject.setSelected (false); + + this.newProjectPanel = new NewProjectPanel (); + + this.importProject = new ImportProject (); + this.importProject.init (); + + this.projDBFind = new FileFinder (); + + // This doesn't appear to ever be visible... + this.projDBFindError = UIUtils.createErrorLabel (""); + //Please select a directory."); + + this.fileFindError = UIUtils.createErrorLabel (""); + //"Please select a file to import."); + this.fileFind = new FileFinder (); + this.fileFind.setFileFilter (ImportProject.fileFilter); + this.fileFind.setClearOnCancel (true); + this.fileFind.showCancel (true, + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + _this.enableButton ("next", + false); + + } + + }); + + this.itemsTree = UIUtils.createTree (); + this.itemsTree.setModel (null); + + this.importOverlay = new ImportTransferHandlerOverlay (); + + this.importOverlay.addMouseListener (new MouseEventHandler () + { + + public void handlePress (MouseEvent ev) + { + + _this.importOverlay.setVisible (false); + + _this.validate (); + _this.repaint (); + + } + + }); + + this.setTransferHandler (new ImportTransferHandler (new ActionListener () + { + + public void actionPerformed (ActionEvent ev) + { + + File f = (File) ev.getSource (); + + _this.importOverlay.setFile (f); + + _this.setGlassPane (_this.importOverlay); + + _this.importOverlay.setVisible (true); + _this.validate (); + _this.repaint (); + + } + + }, + new ActionListener () + { + + public void actionPerformed (ActionEvent ev) + { + + _this.importOverlay.setVisible (false); + _this.validate (); + _this.repaint (); + + File f = (File) ev.getSource (); + + _this.importProject.setFile (f); + _this.fileFind.setFile (f); + _this.importFile.setSelected (true); + + _this.setImportFile (f); + + _this.showStage (IMPORT_STAGE); + + } + + }, + new ActionListener () + { + + public void actionPerformed (ActionEvent ev) + { + + _this.importOverlay.setVisible (false); + _this.validate (); + _this.repaint (); + + } + + }, + new java.io.FileFilter () + { + + @Override + public boolean accept (File f) + { + + return ImportProject.isSupportedFileType (f); + + } + + })); + + } + + @Override + public String getWindowTitle () + { + + return this.getHeaderTitle (); + + } + + @Override + public String getHeaderTitle () + { + + return Environment.getUIString (firstusewizard,title); + //return "Welcome to Quoll Writer"; + + } + + @Override + public String getHeaderIconType () + { + + return null; + + } + + @Override + public String getHelpText () + { + + return Environment.getUIString (firstusewizard,text); + //"Welcome to Quoll Writer, this page will help you get started. Don't worry, there are only a couple of questions and then you can get started on your first {project}."; + + } + + @Override + public int getMaximumContentHeight () + { + + return 350; + + } + + @Override + public boolean handleFinish () + { + + if ((this.importFile.isSelected ()) + || + (this.createNewProject.isSelected ()) + ) + { + + return this.newProjectPanel.createProject (this); + + } + + return true; + + } + + @Override + public void handleCancel () + { + + } + + @Override + public String getNextStage (String currStage) + { + + if (START_STAGE.equals (currStage)) + { + + return SPELL_CHECK_LANG_STAGE; + + } + + if (SPELL_CHECK_LANG_STAGE.equals (currStage)) + { + + return DECIDE_STAGE; + + } + + if (SELECT_FILE_STAGE.equals (currStage)) + { + + return IMPORT_STAGE; + + } + + if (EXISTING_STAGE.equals (currStage)) + { + + return SELECT_PROJECT_DB_STAGE; + + } + + if (IMPORT_STAGE.equals (currStage)) + { + + return NEW_PROJECT_STAGE; + + } + + if (DECIDE_STAGE.equals (currStage)) + { + + if (this.createNewProject.isSelected ()) + { + + return NEW_PROJECT_STAGE; + + } + + if (this.importFile.isSelected ()) + { + + return SELECT_FILE_STAGE; + + } + + return IMPORT_STAGE; + + } + + return null; + + } + + @Override + public String getPreviousStage (String currStage) + { + + if (SELECT_PROJECT_DB_STAGE.equals (currStage)) + { + + return EXISTING_STAGE; + + } + + if (SPELL_CHECK_LANG_STAGE.equals (currStage)) + { + + return START_STAGE; + + } + + if (START_STAGE.equals (currStage)) + { + + return null; + + } + + if (NEW_PROJECT_STAGE.equals (currStage)) + { + + return DECIDE_STAGE; + + } + + if (EXISTING_STAGE.equals (currStage)) + { + + return START_STAGE; + + } + + if (IMPORT_STAGE.equals (currStage)) + { + + return SELECT_FILE_STAGE; + + } + + if (SELECT_FILE_STAGE.equals (currStage)) + { + + return DECIDE_STAGE; + + } + + if (DECIDE_STAGE.equals (currStage)) + { + + return SPELL_CHECK_LANG_STAGE; + + } + + return null; + + } + + @Override + public boolean handleStageChange (String oldStage, + String newStage) + { + + final FirstUseWizard _this = this; + + if (SELECT_FILE_STAGE.equals (oldStage)) + { + + if (!IMPORT_STAGE.equals (newStage)) + { + + return true; + + } + + this.fileFindError.setVisible (false); + + File f = this.fileFind.getSelectedFile (); + + if (!f.isFile ()) + { + + this.fileFindError.setText (getUIString (firstusewizard,stages,selectfile,errors,novalue)); + this.fileFindError.setVisible (true); + + return false; + + } + + return true; + + } + + if (DECIDE_STAGE.equals (oldStage)) + { + + if (START_STAGE.equals (newStage)) + { + + return true; + + } + + return true; +/* + if (this.importFile.isSelected ()) + { + + this.showStage (SELECT_FILE_STAGE); + + return false; + + } + + if (this.createNewProject.isSelected ()) + { + + this.newProjectPanel.setProject (null); + this.newProjectPanel.setName (null); + + this.showStage (NEW_PROJECT_STAGE); + + return false; + + } +*/ + } + + if ((START_STAGE.equals (oldStage)) + && + (SPELL_CHECK_LANG_STAGE.equals (newStage)) + ) + { + + this.enableButton ("next", + true); + + String lsid = UserProperties.get (Constants.USER_UI_LANGUAGE_PROPERTY_NAME); + + try + { + + if (UILanguageStringsManager.getUILanguageStrings (lsid) == null) + { + + this.enableButton ("next", + false); + + // Show the downloading message. + this.dlUILangFile.setVisible (true); + + UILanguageStringsManager.downloadUILanguageFile (lsid, + () -> + { + // Set the language. + try + { + + Environment.setUILanguage (lsid); + + } catch (Exception e) { + + Environment.logError ("Unable to set ui language to: " + lsid, + e); + + UIUtils.showErrorMessage (_this, + getUIString (uilanguage,set,actionerror)); + + _this.dlUILangError.setVisible (true); + _this.dlUILangFile.setVisible (false); + + return; + + } + + _this.dlUILangFile.setVisible (true); + _this.showStage (SPELL_CHECK_LANG_STAGE); + }, + // On error + () -> + { + + UIUtils.showErrorMessage (_this, + getUIString (uilanguage,set,actionerror)); + + _this.dlUILangFile.setVisible (false); + + _this.dlUILangError.setVisible (true); + + }); + + this.validate (); + this.repaint (); + + //this.xxx + + return false; + + } else { + + // Set the language. + try + { + + Environment.setUILanguage (lsid); + + } catch (Exception e) { + + Environment.logError ("Unable to set ui language to: " + lsid, + e); + + UIUtils.showErrorMessage (_this, + getUIString (uilanguage,set,actionerror)); + + _this.dlUILangError.setVisible (true); + _this.dlUILangFile.setVisible (false); + + return false; + + } + + _this.dlUILangFile.setVisible (true); + _this.showStage (SPELL_CHECK_LANG_STAGE); + + } + + } catch (Exception e) { + + Environment.logError ("Unable to get ui language strings for: " + lsid, + e); + + UIUtils.showErrorMessage (this, + getUIString (firstusewizard,stages,start,actionerror)); + + return false; + + } + + } + + if ((SPELL_CHECK_LANG_STAGE.equals (oldStage)) + && + (DECIDE_STAGE.equals (newStage)) + ) + { + + this.enableButton ("next", + false); + + return true; + + } + + if ((EXISTING_STAGE.equals (oldStage)) + && + (newStage == null) + ) + { + + if (this.findProjects.isSelected ()) + { + + Environment.showAllProjectsViewer (); + + // TODO Environment.getLanding ().showFindProjects (); + + this.close (); + + return false; + + } + + } + + return true; + + } + + @Override + public String getStartStage () + { + + return START_STAGE; + + } + + @Override + public WizardStep getStage (String stage) + { + + final FirstUseWizard _this = this; + + WizardStep ws = new WizardStep (); + + if (NEW_PROJECT_STAGE.equals (stage)) + { + + java.util.List prefix = Arrays.asList (firstusewizard,stages,newproject); + + ws.title = Environment.getUIString (prefix, + title); + //"{Project} details"; + + ws.helpText = Environment.getUIString (prefix, + text); + //"Enter the name of the {project} below and select the directory where it should be saved."; + + ws.panel = this.newProjectPanel.createPanel (this, + null, + false, + null, + false); + + return ws; + + } + + if (SELECT_PROJECT_DB_STAGE.equals (stage)) + { + + java.util.List prefix = Arrays.asList (firstusewizard,stages,selectprojectdb); + + ws.title = Environment.getUIString (prefix, + title); + //"Select your {projects} directory"; + /* + TODO + ws.helpText = String.format (Environment.getUIString (prefix, + text), + //"Use the finder below to find the directory where your {projects} database file is stored. The file is called %s%s", + Environment.getProjectInfoDBFile ().getName () + Constants.H2_DB_FILE_SUFFIX); +*/ + Box b = new Box (BoxLayout.Y_AXIS); + + this.projDBFindError.setVisible (false); + this.projDBFindError.setBorder (UIUtils.createPadding (0, 5, 5, 5)); + b.add (this.projDBFindError); + + FormLayout fl = new FormLayout ("right:p, 6px, fill:200px:grow, 10px", + "p"); + + PanelBuilder builder = new PanelBuilder (fl); + + CellConstraints cc = new CellConstraints (); + + this.projDBFind.setOnSelectHandler (new ActionListener () + { + + public void actionPerformed (ActionEvent ev) + { + + //_this.file = _this.fileFind.getSelectedFile (); + + //_this.checkForFileToImport (); + + _this.enableButton ("next", + true); + + } + + }); + + this.projDBFind.setApproveButtonText (Environment.getUIString (prefix, + finder, + button)); + //"Select"); + this.projDBFind.setFinderSelectionMode (JFileChooser.DIRECTORIES_ONLY); + this.projDBFind.setFinderTitle (Environment.getUIString (prefix, + finder, + title)); + //"Select the directory"); + + this.projDBFind.setFile (Environment.getUserQuollWriterDirPath ().toFile ()); + + this.projDBFind.setFindButtonToolTip (Environment.getUIString (prefix, + finder, + tooltip)); + //"Click to find a directory"); + this.projDBFind.setClearOnCancel (true); + this.projDBFind.init (); + + builder.addLabel (Environment.getUIString (prefix, + LanguageStrings.finder, + LanguageStrings.label), + //"Directory", + cc.xy (1, + 1)); + builder.add (this.projDBFind, + cc.xy (3, + 1)); + + JPanel p = builder.getPanel (); + p.setOpaque (false); + p.setAlignmentX (JComponent.LEFT_ALIGNMENT); + + b.add (p); + + ws.panel = b; + + return ws; + + } + + if (EXISTING_STAGE.equals (stage)) + { + + java.util.List prefix = new ArrayList<> (); + prefix.add (LanguageStrings.firstusewizard); + prefix.add (LanguageStrings.stages); + prefix.add (LanguageStrings.existing); + + ws.title = Environment.getUIString (prefix, + LanguageStrings.title); + //"Find your {projects}"; + ws.helpText = Environment.getUIString (prefix, + LanguageStrings.text); + //"If you would like {QW} to find your {projects} then click Finish below."; + + FormLayout fl = new FormLayout ("10px, p, 10px", + "p, 6px, p, 6px, p, 6px"); + + PanelBuilder builder = new PanelBuilder (fl); + + CellConstraints cc = new CellConstraints (); + + this.findProjects.setText (Environment.getUIString (prefix, + LanguageStrings.labels, + LanguageStrings.find)); + //.replaceObjectNames ("{QW} should find my {projects}")); + + this.findProjects.setOpaque (false); + + this.selectProjectDB = new JRadioButton (Environment.getUIString (prefix, + LanguageStrings.labels, + LanguageStrings.manual)); + //"I know where my {projects} database is")); + + this.selectProjectDB.setOpaque (false); + + ButtonGroup bg = new ButtonGroup (); + + bg.add (this.findProjects); + bg.add (this.selectProjectDB); + + this.findProjects.setSelected (false); + this.selectProjectDB.setSelected (false); + + this.findProjects.addActionListener (new ActionListener () + { + + public void actionPerformed (ActionEvent ev) + { + + _this.enableButton ("next", + true); + + } + + }); + + this.selectProjectDB.addActionListener (new ActionListener () + { + + public void actionPerformed (ActionEvent ev) + { + + _this.enableButton ("next", + true); + + } + + }); + + builder.add (this.findProjects, + cc.xy (2, + 1)); + + builder.add (this.selectProjectDB, + cc.xy (2, + 3)); + + JPanel p = builder.getPanel (); + p.setOpaque (false); + p.setAlignmentX (JComponent.LEFT_ALIGNMENT); + + ws.panel = p; + + return ws; + + + } + + if (DECIDE_STAGE.equals (stage)) + { + + java.util.List prefix = new ArrayList<> (); + prefix.add (LanguageStrings.firstusewizard); + prefix.add (LanguageStrings.stages); + prefix.add (LanguageStrings.decide); + + ws.title = Environment.getUIString (prefix, + LanguageStrings.title); + //"Your first {project}"; + ws.helpText = Environment.getUIString (prefix, + LanguageStrings.text); + //"If you already have your story in a .docx or .doc file then use the import option below, otherwise use the create option. You can also just drag your .docx or .doc file onto this window."; + + FormLayout fl = new FormLayout ("p", + "p, 6px, p"); + + PanelBuilder builder = new PanelBuilder (fl); + + CellConstraints cc = new CellConstraints (); + + this.importFile.setText (Environment.getUIString (prefix, + LanguageStrings.labels, + LanguageStrings.importfile)); + //"Import a File"); + + this.importFile.setOpaque (false); + + this.createNewProject = new JRadioButton (Environment.getUIString (prefix, + LanguageStrings.labels, + LanguageStrings.newproject)); + //Environment.replaceObjectNames ("Create a {project}")); + + this.createNewProject.setOpaque (false); + + ButtonGroup bg = new ButtonGroup (); + + bg.add (this.importFile); + bg.add (this.createNewProject); + + this.importFile.addActionListener (new ActionListener () + { + + public void actionPerformed (ActionEvent ev) + { + + _this.enableButton ("next", + true); + + } + + }); + + this.createNewProject.addActionListener (new ActionListener () + { + + public void actionPerformed (ActionEvent ev) + { + + _this.enableButton ("next", + true); + + } + + }); + + builder.add (this.createNewProject, + cc.xy (1, + 1)); + + builder.add (this.importFile, + cc.xy (1, + 3)); + + JPanel p = builder.getPanel (); + p.setOpaque (false); + p.setAlignmentX (JComponent.LEFT_ALIGNMENT); + p.setAlignmentY (JComponent.TOP_ALIGNMENT); + + Box b = new Box (BoxLayout.Y_AXIS); + + b.add (p); + b.add (Box.createVerticalGlue ()); + + JLabel l = UIUtils.createClickableLabel (Environment.getUIString (prefix, + LanguageStrings.labels, + LanguageStrings.notfirst), + //"Not your first {project}? Click here to find your {projects}.", + Environment.getIcon (Constants.FIND_ICON_NAME, + Constants.ICON_CLICKABLE_LABEL), + new ActionListener () + { + + public void actionPerformed (ActionEvent ev) + { + + Environment.showAllProjectsViewer (); + + // TODO Environment.getLanding ().showFindProjects (); + + _this.close (); + + } + + }); + + b.add (l); + + ws.panel = b; + + return ws; + + } + + if (SELECT_FILE_STAGE.equals (stage)) + { + + java.util.List prefix = new ArrayList<> (); + prefix.add (LanguageStrings.firstusewizard); + prefix.add (LanguageStrings.stages); + prefix.add (LanguageStrings.selectfile); + + ws.title = Environment.getUIString (prefix, + LanguageStrings.title); + //"Select a file to import"; + ws.helpText = Environment.getUIString (prefix, + LanguageStrings.text); + //"Microsoft Word files (.doc and .docx) are supported. Please check the import guide to ensure your file has the correct format."; + + Box b = new Box (BoxLayout.Y_AXIS); + + this.fileFindError.setVisible (false); + this.fileFindError.setBorder (UIUtils.createPadding (0, 5, 5, 5)); + b.add (this.fileFindError); + + FormLayout fl = new FormLayout ("right:p, 6px, fill:200px:grow, 10px", + "p"); + + PanelBuilder builder = new PanelBuilder (fl); + + CellConstraints cc = new CellConstraints (); + + this.fileFind.setApproveButtonText (Environment.getUIString (prefix, + LanguageStrings.finder, + LanguageStrings.button)); + //"Select"); + this.fileFind.setFinderSelectionMode (JFileChooser.FILES_ONLY); + this.fileFind.setFinderTitle (Environment.getUIString (prefix, + LanguageStrings.finder, + LanguageStrings.title)); + //"Select a file to import"); + + if (this.fileFind.getSelectedFile () == null) + { + + this.fileFind.setFile (FileSystemView.getFileSystemView ().getDefaultDirectory ()); + + } + + this.fileFind.setOnSelectHandler (new ActionListener () + { + + public void actionPerformed (ActionEvent ev) + { + + _this.setImportFile (_this.fileFind.getSelectedFile ()); + + } + + }); + + this.fileFind.setFileFilter (ImportProject.fileFilter); + + this.fileFind.setFindButtonToolTip (Environment.getUIString (prefix, + LanguageStrings.finder, + LanguageStrings.tooltip)); + //"Click to find a file"); + this.fileFind.setClearOnCancel (true); + this.fileFind.init (); + + builder.addLabel (Environment.getUIString (prefix, + LanguageStrings.finder, + LanguageStrings.label), + //"File", + cc.xy (1, + 1)); + builder.add (this.fileFind, + cc.xy (3, + 1)); + + JPanel p = builder.getPanel (); + p.setOpaque (false); + p.setAlignmentX (JComponent.LEFT_ALIGNMENT); + + b.add (p); + + ws.panel = b; + + return ws; + + } + + if (IMPORT_STAGE.equals (stage)) + { + + java.util.List prefix = new ArrayList<> (); + prefix.add (LanguageStrings.firstusewizard); + prefix.add (LanguageStrings.stages); + prefix.add (LanguageStrings.selectitems); + + ws.title = Environment.getUIString (prefix, + LanguageStrings.title); + //"Select the items you wish to import"; + + ws.helpText = Environment.getUIString (prefix, + LanguageStrings.text); + //"Check the items below to ensure that they match what is in your file. The first and last sentences of the description (if present) are shown for each item."; + + this.itemsTree.addMouseListener (new MouseAdapter () + { + + private void selectAllChildren (DefaultTreeModel model, + DefaultMutableTreeNode n, + boolean v) + { + + Enumeration en = n.children (); + + while (en.hasMoreElements ()) + { + + DefaultMutableTreeNode c = (DefaultMutableTreeNode) en.nextElement (); + + Object uo = c.getUserObject (); + + if (uo instanceof SelectableDataObject) + { + + SelectableDataObject s = (SelectableDataObject) uo; + + s.selected = v; + + // Tell the model that something has changed. + model.nodeChanged (c); + + // Iterate. + this.selectAllChildren (model, + c, + v); + + } + + } + + } + + public void mousePressed (MouseEvent ev) + { + + TreePath tp = _this.itemsTree.getPathForLocation (ev.getX (), + ev.getY ()); + + if (tp != null) + { + + DefaultMutableTreeNode n = (DefaultMutableTreeNode) tp.getLastPathComponent (); + + // Tell the model that something has changed. + DefaultTreeModel model = (DefaultTreeModel) _this.itemsTree.getModel (); + + if (n.getUserObject () instanceof SelectableDataObject) + { + + SelectableDataObject s = (SelectableDataObject) n.getUserObject (); + + s.selected = !s.selected; + + model.nodeChanged (n); + + this.selectAllChildren (model, + n, + s.selected); + + } + + } + + } + + }); + + this.itemsTree.setCellRenderer (new SelectableProjectTreeCellRenderer ()); + + this.itemsTree.setOpaque (false); + this.itemsTree.setBorder (UIUtils.createPadding (5, 5, 5, 5)); + + JScrollPane sp = UIUtils.createScrollPane (this.itemsTree); + + ws.panel = sp; + + return ws; + + } + + if (SPELL_CHECK_LANG_STAGE.equals (stage)) + { + + java.util.List prefix = Arrays.asList (firstusewizard,stages,spellcheck); + + ws.title = Environment.getUIString (prefix, + title); + //"Select the spell checker language"; + + ws.helpText = Environment.getUIString (prefix, + text); + //"Welcome to Quoll Writer, this wizard will help you get started.

    First, select the language you would like to use for the spell checker. You can download additional languages in the Options panel later."; + + Box b = new Box (BoxLayout.Y_AXIS); + JComboBox lb = UIUtils.getSpellCheckLanguagesSelector (new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + // Set the property. + String lang = ev.getActionCommand (); + + UserProperties.set (Constants.SPELL_CHECK_LANGUAGE_PROPERTY_NAME, + lang); + + } + + }, + UserProperties.get (Constants.SPELL_CHECK_LANGUAGE_PROPERTY_NAME)); + + lb.setMaximumSize (lb.getPreferredSize ()); + + Box wrap = new Box (BoxLayout.X_AXIS); + + wrap.add (lb); + wrap.add (Box.createHorizontalGlue ()); + wrap.setAlignmentX (JComponent.LEFT_ALIGNMENT); + wrap.setAlignmentY (JComponent.TOP_ALIGNMENT); + + b.add (wrap); + b.add (Box.createVerticalGlue ()); + + ws.panel = b; + + return ws; + + } + + if (START_STAGE.equals (stage)) + { + + java.util.List prefix = Arrays.asList (firstusewizard,stages,start); + + ws.title = getUIString (prefix,title); + + ws.helpText = getUIString (prefix,text); + + Box b = new Box (BoxLayout.Y_AXIS); + + JComboBox ub = UIUtils.getUILanguagesSelector (new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + // Set the property. + String uilid = ev.getActionCommand (); + + UserProperties.set (Constants.USER_UI_LANGUAGE_PROPERTY_NAME, + uilid); + + } + + }, + UserProperties.get (Constants.USER_UI_LANGUAGE_PROPERTY_NAME)); + + ub.setMaximumSize (ub.getPreferredSize ()); + + Box wrap = new Box (BoxLayout.X_AXIS); + + wrap.add (ub); + wrap.add (Box.createHorizontalGlue ()); + wrap.setAlignmentX (JComponent.LEFT_ALIGNMENT); + wrap.setAlignmentY (JComponent.TOP_ALIGNMENT); + + b.add (wrap); + + this.dlUILangFile = UIUtils.createInformationLabel (getUIString (prefix,downloading)); + this.dlUILangFile.setVisible (false); + + this.dlUILangFile.setBorder (UIUtils.createPadding (10, 0, 0, 5)); + this.dlUILangFile.setIcon (Environment.getIcon (Constants.INFO_ICON_NAME, + Constants.ICON_MENU)); + + b.add (this.dlUILangFile); + + this.dlUILangError = UIUtils.createErrorLabel (getUIString(firstusewizard,stages,start,actionerror)); + this.dlUILangError.setVisible (false); + + this.dlUILangError.setBorder (UIUtils.createPadding (10, 0, 0, 5)); + + b.add (this.dlUILangError); + + b.add (Box.createVerticalGlue ()); + + ws.panel = b; + + return ws; + + } + + return null; + + } + + @Override + protected void enableButtons (String currentStage) + { + + super.enableButtons (currentStage); + + if (DECIDE_STAGE.equals (currentStage)) + { + + this.enableButton ("next", + (this.importFile.isSelected () || this.createNewProject.isSelected ())); + + } + + if (SELECT_FILE_STAGE.equals (currentStage)) + { + + this.enableButton ("next", + (this.fileFind.getSelectedFile () != null)); + + } + + if (SELECT_PROJECT_DB_STAGE.equals (currentStage)) + { + + File f = this.projDBFind.getSelectedFile (); + + boolean enable = false; + + if (f != null) + { + + File pf = this.getProjectDBFile (f); + + enable = pf.exists () && pf.isFile (); + + } + + this.enableButton ("next", + enable); + + return; + + } + + if (EXISTING_STAGE.equals (currentStage)) + { + + this.enableButton ("next", + (this.selectProjectDB.isSelected () || this.findProjects.isSelected ())); + + } + + } + + private File getProjectDBFile (File dir) + { + + return new File (dir, + Constants.PROJECT_INFO_DB_FILE_NAME_PREFIX + Constants.H2_DB_FILE_SUFFIX); + + } + + private void addAssetsToTree (DefaultMutableTreeNode root, + UserConfigurableObjectType type, + Set assets) + { + + if ((assets == null) + || + (assets.size () == 0) + ) + { + + return; + + } + + TreeParentNode c = new TreeParentNode (type.getObjectTypeId (), + type.getObjectTypeNamePlural ()); + + SelectableDataObject sd = new SelectableDataObject (c); + + sd.selected = true; + + DefaultMutableTreeNode tn = new DefaultMutableTreeNode (sd); + + root.add (tn); + + java.util.List lassets = new ArrayList (assets); + + Collections.sort (lassets, + NamedObjectSorter.getInstance ()); + + for (Asset a : lassets) + { + + sd = new SelectableDataObject (a); + + sd.selected = true; + + DefaultMutableTreeNode n = new DefaultMutableTreeNode (sd); + + tn.add (n); + + String t = this.getFirstLastSentence (a.getDescriptionText ()); + + if (t.length () > 0) + { + + // Get the first and last sentence. + n.add (new DefaultMutableTreeNode (t)); + + } + + } + + } + + private Project getSelectedItems () + { + + String projName = null; + + Project p = new Project (projName); + + Book b = new Book (p, + null); + + p.addBook (b); + b.setName (projName); + + DefaultTreeModel dtm = (DefaultTreeModel) this.itemsTree.getModel (); + + DefaultMutableTreeNode root = (DefaultMutableTreeNode) dtm.getRoot (); + + Enumeration en = root.depthFirstEnumeration (); + + while (en.hasMoreElements ()) + { + + DefaultMutableTreeNode node = (DefaultMutableTreeNode) en.nextElement (); + + Object o = node.getUserObject (); + + if (o instanceof SelectableDataObject) + { + + SelectableDataObject so = (SelectableDataObject) o; + + if (so.selected) + { + + if (so.obj instanceof Asset) + { + + p.addAsset ((Asset) so.obj); + + } + + if (so.obj instanceof Chapter) + { + + b.addChapter ((Chapter) so.obj); + + } + + } + + } + + } + + if ((b.getChapters () != null) + && + (b.getChapters ().size () == 0) + ) + { + + p.getBooks ().remove (b); + + } + + return p; + + } + + private void setImportFile (final File f) + { + + final FirstUseWizard _this = this; + + try + { + + Importer.importProject (f.toURI (), + new ImportCallback () + { + + @Override + public void exceptionOccurred (Exception e, + URI uri) + { + + Environment.logError ("Unable to import file: " + + f, + e); + + UIUtils.showErrorMessage (_this, + Environment.getUIString (LanguageStrings.firstusewizard, + LanguageStrings.stages, + LanguageStrings.importfile, + LanguageStrings.actionerror)); + //"Unable to import file"); + + } + + @Override + public void projectCreated (final Project p, + URI uri) + { + + UIUtils.doLater (new ActionListener () + { + + public void actionPerformed (ActionEvent ev) + { + + if (_this.itemsTree != null) + { + + _this.itemsTree.setModel (new DefaultTreeModel (_this.createTree (p))); + + UIUtils.expandAllNodesWithChildren (_this.itemsTree); + + _this.importProj = p; + + _this.newProjectPanel.setName (p.getName ()); + + _this.newProjectPanel.setProject (p); + + } + + } + + }); + + } + + }); + + + + } catch (Exception e) { + + Environment.logError ("Unable to import file: " + + f, + e); + + UIUtils.showErrorMessage (this, + Environment.getUIString (LanguageStrings.firstusewizard, + LanguageStrings.stages, + LanguageStrings.importfile, + LanguageStrings.actionerror)); + //"Unable to import file"); + + } + + } + + private DefaultMutableTreeNode createTree (Project p) + { + + DefaultMutableTreeNode root = new DefaultMutableTreeNode (new SelectableDataObject (p)); + + DefaultMutableTreeNode n = null; + DefaultMutableTreeNode tn = null; + + if (p.getBooks ().size () > 0) + { + + Book b = p.getBooks ().get (0); + + if (b.getChapters ().size () > 0) + { + + TreeParentNode c = new TreeParentNode (Chapter.OBJECT_TYPE, + Environment.getObjectTypeNamePlural (Chapter.OBJECT_TYPE).getValue ()); + + SelectableDataObject sd = new SelectableDataObject (c); + + sd.selected = true; + + tn = new DefaultMutableTreeNode (sd); + + root.add (tn); + + Collections.sort (b.getChapters (), + NamedObjectSorter.getInstance ()); + + for (Chapter ch : b.getChapters ()) + { + + sd = new SelectableDataObject (ch); + + sd.selected = true; + + n = new DefaultMutableTreeNode (sd); + + tn.add (n); + + String t = this.getFirstLastSentence (ch.getChapterText ()); + + if (t.length () > 0) + { + + // Get the first and last sentence. + n.add (new DefaultMutableTreeNode (t)); + + } + + } + + } + + } + + Set assetTypes = Environment.getAssetUserConfigurableObjectTypes (true); + + for (UserConfigurableObjectType t : assetTypes) + { + + Set as = p.getAssets (t); + + this.addAssetsToTree (root, + t, + as); + + } + + return root; + + } + + private String getFirstLastSentence (String st) + { + + if (st == null) + { + + return ""; + + } + + TextIterator t = new TextIterator (st); + + Paragraph p = t.getFirstParagraph (); + + if (p != null) + { + + Sentence s = p.getFirstSentence (); + + StringBuilder b = new StringBuilder (); + + b.append (s.getText ()); + + p = t.getLastParagraph (); + + if (p != null) + { + + b.append (" ... "); + + b.append (p.getLastSentence ().getText ()); + + } + + return b.toString (); + + } + + return ""; + + } + +} diff --git a/src/com/quollwriter/ui/FullScreenFrame.java b/src/main/java/com/quollwriter/ui/FullScreenFrame.java similarity index 98% rename from src/com/quollwriter/ui/FullScreenFrame.java rename to src/main/java/com/quollwriter/ui/FullScreenFrame.java index aa759a1d..1127c6a8 100644 --- a/src/com/quollwriter/ui/FullScreenFrame.java +++ b/src/main/java/com/quollwriter/ui/FullScreenFrame.java @@ -31,7 +31,6 @@ import com.quollwriter.data.*; import com.quollwriter.events.*; -import com.quollwriter.ui.events.*; import com.quollwriter.ui.sidebars.*; import com.quollwriter.ui.panels.*; import com.quollwriter.ui.components.ActionAdapter; @@ -295,10 +294,11 @@ public void doAction (QuollPanel qp) this.projectViewer.fullScreenClosed (this.panel.getChild ()); EditorsEnvironment.fullScreenExited (); - +/* +TODO this.projectViewer.fireProjectEventLater (ProjectEvent.FULL_SCREEN, ProjectEvent.EXIT); - +*/ } public void removePopup (Component c) @@ -561,10 +561,11 @@ public void restorePanel () AbstractEditorPanel edPanel = (AbstractEditorPanel) child; edPanel.setIgnoreDocumentChanges (true); - +/* +TODO Environment.getProjectTextProperties ().setOn (edPanel, true); - +*/ edPanel.setIgnoreDocumentChanges (false); edPanel.setUseTypewriterScrolling (false); @@ -632,10 +633,11 @@ public void setDistractionFreeModeEnabled (boolean v) if (v) { - +/* +TODO this.projectViewer.fireProjectEvent (ProjectEvent.DISTRACTION_FREE, ProjectEvent.ENTER); - +*/ } } @@ -793,7 +795,16 @@ public void paintComponent (Graphics g) { // Legacy < v2 - File f = UserProperties.getAsFile (Constants.FULL_SCREEN_BG_IMAGE_PROPERTY_NAME); + java.nio.file.Path _f = UserProperties.getAsFile (Constants.FULL_SCREEN_BG_IMAGE_PROPERTY_NAME); + + File f = null; + + if (_f != null) + { + + f = _f.toFile (); + + } if ((f != null) && @@ -933,10 +944,11 @@ public void mouseWheelMoved (MouseWheelEvent ev) _this.setBorderOpacity (_this.borderOpacity + (-1 * r * 0.1f)); //_this.properties.backgroundOpacityChanged (); - - _this.projectViewer.fireProjectEvent (ProjectEvent.FULL_SCREEN, - ProjectEvent.CHANGE_BG_OPACITY); - +/* +TODO + _this.projectViewer.fireProjectEvent (ProjectEvent.Type.fullscreen, + ProjectEvent.Action.changebgopacity); +*/ } private void handlePopup (MouseEvent ev) @@ -954,7 +966,7 @@ private void handlePopup (MouseEvent ev) JPopupMenu p = new JPopupMenu (); - String oName = Environment.getObjectTypeName (Chapter.OBJECT_TYPE); + String oName = Environment.getObjectTypeName (Chapter.OBJECT_TYPE).getValue (); JMenuItem mi = new JMenuItem (Environment.getUIString (LanguageStrings.fullscreen, LanguageStrings.popupmenu, @@ -1109,10 +1121,11 @@ public void mouseDragged (MouseEvent ev) //_this.properties.displayAreaSizeChanged (); _this.lastX = x; - - _this.projectViewer.fireProjectEvent (ProjectEvent.FULL_SCREEN, - ProjectEvent.CHANGE_BORDER_SIZE); - +/* +TODO + _this.projectViewer.fireProjectEvent (ProjectEvent.Type.fullscreen, + ProjectEvent.Action.changebordersize); +*/ } if (_this.lastY > 0) @@ -1143,10 +1156,11 @@ public void mouseDragged (MouseEvent ev) //_this.properties.displayAreaSizeChanged (); _this.lastY = y; - - _this.projectViewer.fireProjectEvent (ProjectEvent.FULL_SCREEN, - ProjectEvent.CHANGE_BORDER_SIZE); - +/* +TODO + _this.projectViewer.fireProjectEvent (ProjectEvent.Type.fullscreen, + ProjectEvent.Action.changebordersize); +*/ } } @@ -1284,10 +1298,11 @@ public void mouseMoved (MouseEvent ev) this.setVisible (true); EditorsEnvironment.fullScreenEntered (); - +/* +TODO this.projectViewer.fireProjectEventLater (ProjectEvent.FULL_SCREEN, ProjectEvent.ENTER); - +*/ } private void createSideBar () @@ -1705,12 +1720,12 @@ public void actionPerformed (ActionEvent ev) if ((maxChapWC > 0) && - (cc.wordCount > maxChapWC) + (cc.getWordCount () > maxChapWC) ) { t = String.format (", %s", - Environment.formatNumber (cc.wordCount - maxChapWC)); + Environment.formatNumber (cc.getWordCount () - maxChapWC)); } @@ -1721,7 +1736,7 @@ public void actionPerformed (ActionEvent ev) pl = LanguageStrings.words; - if (cc.wordCount == 1) + if (cc.getWordCount () == 1) { pl = LanguageStrings.word; @@ -1729,7 +1744,7 @@ public void actionPerformed (ActionEvent ev) } chapWords.setText (String.format ("%s %s%s", - Environment.formatNumber (cc.wordCount), + Environment.formatNumber (cc.getWordCount ()), Environment.getUIString (prefix, pl), t)); @@ -2042,12 +2057,13 @@ public void stateChanged (ChangeEvent ev) BackgroundChangeEvent bce = (BackgroundChangeEvent) ev; _this.setFullScreenBackground (bce.getValue ()); - +/* +TODO Environment.fireUserProjectEvent (_this, - ProjectEvent.FULL_SCREEN, - ProjectEvent.CHANGE_BG_IMAGE, + ProjectEvent.Type.fullscreen, + ProjectEvent.Action.changebgimage, bce.getValue ()); - +*/ } }, @@ -2501,7 +2517,7 @@ public void actionPerformed (ActionEvent ev) if (b.getComponentCount () > 0) { - arBox.setBorder (new CompoundBorder (new MatteBorder (0, 0, 1, 0, Environment.getBorderColor ()), + arBox.setBorder (new CompoundBorder (new MatteBorder (0, 0, 1, 0, UIUtils.getBorderColor ()), arBox.getBorder ())); } @@ -2788,9 +2804,11 @@ private void initPanel () AbstractEditorPanel edPanel = (AbstractEditorPanel) child; + /* + TODO Environment.getFullScreenTextProperties ().setOn (edPanel, true); - +*/ this.showFirstTimeInDistractionFreeModeInfoPopup (); } @@ -2861,10 +2879,11 @@ public void incrementYBorderWidth (float v) this.yBorderWidth += v; this.setChildBorder (); - +/* +TODO this.projectViewer.fireProjectEvent (ProjectEvent.FULL_SCREEN, ProjectEvent.CHANGE_BORDER_SIZE); - +*/ } public void incrementXBorderWidth (float v) @@ -2873,10 +2892,11 @@ public void incrementXBorderWidth (float v) this.xBorderWidth += v; this.setChildBorder (); - +/* +TODO this.projectViewer.fireProjectEvent (ProjectEvent.FULL_SCREEN, ProjectEvent.CHANGE_BORDER_SIZE); - +*/ } public float getBorderOpacity () @@ -2892,10 +2912,11 @@ public void setBorderOpacity (float f) this.borderOpacity = f; this.setChildBorder (); - +/* +TODO this.projectViewer.fireProjectEvent (ProjectEvent.FULL_SCREEN, ProjectEvent.CHANGE_BG_OPACITY); - +*/ } public void toggleMaximizeDisplayArea () @@ -2929,10 +2950,11 @@ public void toggleMaximizeDisplayArea () } this.setChildBorder (); - - this.projectViewer.fireProjectEvent (ProjectEvent.FULL_SCREEN, - ProjectEvent.CHANGE_BORDER_SIZE); - +/* +TODO + this.projectViewer.fireProjectEvent (ProjectEvent.Type.fullscreen, + ProjectEvent.Action.changebordersize); +*/ } public float getYBorderWidth () @@ -2990,7 +3012,7 @@ public void setChildBorder () if (showBorder) { - innerBorder = new LineBorder (Environment.getBorderColor (), + innerBorder = new LineBorder (UIUtils.getBorderColor (), 1, true); diff --git a/src/com/quollwriter/ui/FullScreenOverlay.java b/src/main/java/com/quollwriter/ui/FullScreenOverlay.java similarity index 100% rename from src/com/quollwriter/ui/FullScreenOverlay.java rename to src/main/java/com/quollwriter/ui/FullScreenOverlay.java diff --git a/src/com/quollwriter/ui/FullScreenPropertiesEditPanel.java b/src/main/java/com/quollwriter/ui/FullScreenPropertiesEditPanel.java similarity index 100% rename from src/com/quollwriter/ui/FullScreenPropertiesEditPanel.java rename to src/main/java/com/quollwriter/ui/FullScreenPropertiesEditPanel.java diff --git a/src/main/java/com/quollwriter/ui/FullScreenTextProperties.java b/src/main/java/com/quollwriter/ui/FullScreenTextProperties.java new file mode 100644 index 00000000..5a0b6051 --- /dev/null +++ b/src/main/java/com/quollwriter/ui/FullScreenTextProperties.java @@ -0,0 +1,242 @@ +package com.quollwriter.ui; + +import java.awt.Color; + +import com.gentlyweb.properties.*; + +import com.quollwriter.*; +import com.quollwriter.data.*; +import com.quollwriter.ui.sidebars.*; +import com.quollwriter.ui.panels.*; +import com.quollwriter.events.*; +import com.quollwriter.ui.components.TextProperties; +import com.quollwriter.ui.components.QTextEditor; + +public class FullScreenTextProperties extends TextProperties implements UserPropertySetter +{ + + private boolean allowSet = true; + + public FullScreenTextProperties () + { + + this.initInternal (UserProperties.get (Constants.FULL_SCREEN_EDITOR_FONT_PROPERTY_NAME, + Constants.EDITOR_FONT_PROPERTY_NAME), + UserProperties.getAsInt (Constants.FULL_SCREEN_EDITOR_FONT_SIZE_PROPERTY_NAME, + Constants.EDITOR_FONT_SIZE_PROPERTY_NAME), + UserProperties.get (Constants.FULL_SCREEN_EDITOR_ALIGNMENT_PROPERTY_NAME, + Constants.EDITOR_ALIGNMENT_PROPERTY_NAME), + UserProperties.getAsBoolean (Constants.FULL_SCREEN_EDITOR_INDENT_FIRST_LINE_PROPERTY_NAME, + Constants.EDITOR_INDENT_FIRST_LINE_PROPERTY_NAME), + UserProperties.getAsFloat (Constants.FULL_SCREEN_EDITOR_LINE_SPACING_PROPERTY_NAME, + Constants.EDITOR_LINE_SPACING_PROPERTY_NAME), + UIUtils.getColor (UserProperties.get (Constants.FULL_SCREEN_EDITOR_FONT_COLOR_PROPERTY_NAME, + Constants.EDITOR_FONT_COLOR_PROPERTY_NAME)), + UIUtils.getColor (UserProperties.get (Constants.FULL_SCREEN_EDITOR_BGCOLOR_PROPERTY_NAME, + Constants.EDITOR_BGCOLOR_PROPERTY_NAME)), + UIUtils.getColor (UserProperties.get (Constants.FULL_SCREEN_EDITOR_WRITING_LINE_COLOR_PROPERTY_NAME, + Constants.EDITOR_WRITING_LINE_COLOR_PROPERTY_NAME)), + UserProperties.getAsBoolean (Constants.FULL_SCREEN_EDITOR_HIGHLIGHT_WRITING_LINE_PROPERTY_NAME, + Constants.EDITOR_HIGHLIGHT_WRITING_LINE_PROPERTY_NAME), + UserProperties.getAsInt (Constants.FULL_SCREEN_EDITOR_TEXT_BORDER_PROPERTY_NAME, + Constants.EDITOR_TEXT_BORDER_PROPERTY_NAME) + ); + + } + + public FullScreenTextProperties (TextProperties props) + { + + this.initInternal (props); + + } + + @Override + public void stopSetting () + { + + this.allowSet = false; + + } + + @Override + public void startSetting () + { + + this.allowSet = true; + + } + + public void setBackgroundColor (Color c) + { + + super.setBackgroundColor (c); + + if (c.equals (this.getTextColor ())) + { + + if (c.equals (Color.black)) + { + + // Set the background to white. + this.setTextColor (Color.white); + + } + + if (c.equals (Color.white)) + { + + // Set the background to black. + this.setTextColor (Color.black); + + } + + } + + this.setProperty (new StringProperty (Constants.FULL_SCREEN_EDITOR_BGCOLOR_PROPERTY_NAME, + UIUtils.colorToHex (this.getBackgroundColor ()))); + + } + + public void setTextColor (Color c) + { + + super.setTextColor (c); + + if (c.equals (this.getBackgroundColor ())) + { + + if (c.equals (Color.black)) + { + + this.setBackgroundColor (Color.white); + + } + + if (c.equals (Color.white)) + { + + // Set the background to black. + this.setBackgroundColor (Color.black); + + } + + } + + this.setProperty (new StringProperty (Constants.FULL_SCREEN_EDITOR_FONT_COLOR_PROPERTY_NAME, + UIUtils.colorToHex (this.getTextColor ()))); + + } + + public void setWritingLineColor (Color c) + { + + super.setWritingLineColor (c); + + this.setProperty (new StringProperty (Constants.FULL_SCREEN_EDITOR_WRITING_LINE_COLOR_PROPERTY_NAME, + UIUtils.colorToHex (this.getWritingLineColor ()))); + + } + + public void setHighlightWritingLine (boolean v) + { + + super.setHighlightWritingLine (v); + + this.setProperty (new BooleanProperty (Constants.FULL_SCREEN_EDITOR_HIGHLIGHT_WRITING_LINE_PROPERTY_NAME, + v)); + + } + + public void setLineSpacing (float v) + { + + super.setLineSpacing (v); + + this.setProperty (new FloatProperty (Constants.FULL_SCREEN_EDITOR_LINE_SPACING_PROPERTY_NAME, + this.getLineSpacing ())); + + } + + public void setFirstLineIndent (boolean v) + { + + super.setFirstLineIndent (v); + + this.setProperty (new BooleanProperty (Constants.FULL_SCREEN_EDITOR_INDENT_FIRST_LINE_PROPERTY_NAME, + this.getFirstLineIndent ())); + + } + + public void setAlignment (String v) + { + + super.setAlignment (v); + + this.setProperty (new StringProperty (Constants.FULL_SCREEN_EDITOR_ALIGNMENT_PROPERTY_NAME, + this.getAlignment ())); + + } + + public void setFontSize (int v) + { + + super.setFontSize (v); + + this.setProperty (new IntegerProperty (Constants.FULL_SCREEN_EDITOR_FONT_SIZE_PROPERTY_NAME, + this.getFontSize ())); + + } + + public void setTextBorder (int v) + { + + super.setTextBorder (v); + + this.setProperty (new IntegerProperty (Constants.FULL_SCREEN_EDITOR_TEXT_BORDER_PROPERTY_NAME, + this.getTextBorder ())); + + } + + public void setFontFamily (String f) + { + + super.setFontFamily (f); + + this.setProperty (new StringProperty (Constants.FULL_SCREEN_EDITOR_FONT_PROPERTY_NAME, + this.getFontFamily ())); + + } + + private void setProperty (AbstractProperty prop) + { + + if (!this.allowSet) + { + + return; + + } + + UserProperties.set (prop.getID (), + prop); + + } + + public void resetToDefaults () + { + + this.setBackgroundColor (UIUtils.getColor (UserProperties.get (Constants.DEFAULT_EDITOR_BGCOLOR_PROPERTY_NAME))); + this.setTextColor (UIUtils.getColor (UserProperties.get (Constants.DEFAULT_EDITOR_FONT_COLOR_PROPERTY_NAME))); + this.setTextBorder (UserProperties.getAsInt (Constants.DEFAULT_EDITOR_TEXT_BORDER_PROPERTY_NAME)); + this.setFontFamily (UserProperties.get (Constants.DEFAULT_EDITOR_FONT_PROPERTY_NAME)); + this.setFontSize (UserProperties.getAsInt (Constants.DEFAULT_EDITOR_FONT_SIZE_PROPERTY_NAME)); + this.setAlignment (Environment.getDefaultTextAlignment ()); + this.setFirstLineIndent (UserProperties.getAsBoolean (Constants.DEFAULT_EDITOR_INDENT_FIRST_LINE_PROPERTY_NAME)); + this.setLineSpacing (UserProperties.getAsFloat (Constants.DEFAULT_EDITOR_LINE_SPACING_PROPERTY_NAME)); + this.setWritingLineColor (UIUtils.getColor (UserProperties.get (Constants.DEFAULT_EDITOR_WRITING_LINE_COLOR_PROPERTY_NAME))); + this.setHighlightWritingLine (UserProperties.getAsBoolean (Constants.DEFAULT_EDITOR_HIGHLIGHT_WRITING_LINE_PROPERTY_NAME)); + + } + +} diff --git a/src/com/quollwriter/ui/HTMLPanel.java b/src/main/java/com/quollwriter/ui/HTMLPanel.java similarity index 82% rename from src/com/quollwriter/ui/HTMLPanel.java rename to src/main/java/com/quollwriter/ui/HTMLPanel.java index a7f81f59..f838842c 100644 --- a/src/com/quollwriter/ui/HTMLPanel.java +++ b/src/main/java/com/quollwriter/ui/HTMLPanel.java @@ -14,42 +14,40 @@ import org.xhtmlrenderer.render.*; import org.xhtmlrenderer.simple.extend.*; -import com.gentlyweb.utils.*; - import com.quollwriter.*; public class HTMLPanel extends XHTMLPanel { - + private AbstractProjectViewer projectViewer = null; - + public HTMLPanel (String t, AbstractProjectViewer projectViewer) { - + this.projectViewer = projectViewer; - + LinkListener ll = null; - + for (int i = 0; i < this.getMouseTrackingListeners ().size (); i++) { - + Object lll = this.getMouseTrackingListeners ().get (i); - + if (lll instanceof LinkListener) { - + ll = (LinkListener) lll; - + } - + } - + if (ll != null) { - + this.removeMouseTrackingListener (ll); - + } this.getSharedContext ().getTextRenderer ().setSmoothingThreshold (8f); @@ -70,97 +68,97 @@ public void onMouseUp(BasicPanel panel, Box box) node.getNodeType () == Node.ELEMENT_NODE; node = node.getParentNode ()) { - + uri = panel.getSharedContext().getNamespaceHandler().getLinkUri ((Element) node); if (uri != null) { - + break; - + } - + } if (uri != null) { - + _this.handleURI (uri); - + } } - + }); this.setText (t); - + } - + public void setText (String text) { if (text == null) { - + return; - + } StringBuilder buf = new StringBuilder (); - text = StringUtils.replaceString (text, + text = Utils.replaceString (text, String.valueOf ('\n'), - "
    "); - + "
    "); + text = UIUtils.markupLinks (text); - + int ind = text.indexOf ("["); - + while (ind > -1) { - + int end = text.indexOf ("]", ind + 1); if (end > ind + 1) { - + String v = text.substring (ind + 1, end); - + StringTokenizer st = new StringTokenizer (v, ",;"); - + String icon = st.nextToken ().trim ().toLowerCase (); String action = null; - + if (st.hasMoreTokens ()) { - + action = st.nextToken ().trim ().toLowerCase (); - + } - + v = ""; - + if (action != null) { - + v = "" + v + ""; - + } - + // Split up the value. text = text.substring (0, ind) + v + text.substring (end + 1); - + ind = text.indexOf ("[", ind + v.length ()); - - + + } - + } StringBuilder t = new StringBuilder (); @@ -177,101 +175,101 @@ public void setText (String text) this.setDocumentFromString (t.toString (), null, - new XhtmlNamespaceHandler ()); - + new XhtmlNamespaceHandler ()); + } - + private void handleURI (String u) { - + URL uri = null; - + try { - + uri = new URL (u); - + } catch (Exception e) { - + Environment.logError ("Unable to convert string: " + u + " to a uri", e); - + return; - + } if (this.projectViewer != null) { - + UIUtils.openURL (this.projectViewer, uri); return; - + } /* if (uri.getScheme ().equals (Constants.HELP_PROTOCOL)) { - + try { - + UIUtils.openURL (this, uri.toURL ()); - + return; } catch (Exception e) { - + Environment.logError ("Unable to open help url: " + uri, e); - + return; - + } - + } - + if (uri.getScheme ().equals ("action")) { - + if (this.handler != null) - { - + { + this.handler.handleHTMLPanelAction (uri.getSchemeSpecificPart ()); - + } return; - + } - + if (this.handler != null) { - + this.handler.handleHTMLPanelAction (u); - + } - */ + */ } - + public static JScrollPane createHelpPanel (String t, AbstractProjectViewer projectViewer) { - + HTMLPanel p = new HTMLPanel (t, projectViewer); - + return HTMLPanel.createHelpPanel (p); - + } public static JScrollPane createHelpPanel (HTMLPanel p) { - + JScrollPane sp = new JScrollPane (p); - + sp.getVerticalScrollBar ().setUnitIncrement (20); sp.getViewport ().setOpaque (false); sp.setVerticalScrollBarPolicy (ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER); @@ -284,9 +282,9 @@ public static JScrollPane createHelpPanel (HTMLPanel p) sp.setOpaque (false); p.setBackground (null); p.setOpaque (false); - + return sp; - + } - -} \ No newline at end of file + +} diff --git a/src/com/quollwriter/ui/HTMLPanelActionHandler.java b/src/main/java/com/quollwriter/ui/HTMLPanelActionHandler.java similarity index 100% rename from src/com/quollwriter/ui/HTMLPanelActionHandler.java rename to src/main/java/com/quollwriter/ui/HTMLPanelActionHandler.java diff --git a/src/com/quollwriter/ui/HideablePopup.java b/src/main/java/com/quollwriter/ui/HideablePopup.java similarity index 98% rename from src/com/quollwriter/ui/HideablePopup.java rename to src/main/java/com/quollwriter/ui/HideablePopup.java index 4203cbcf..a5ebf474 100644 --- a/src/com/quollwriter/ui/HideablePopup.java +++ b/src/main/java/com/quollwriter/ui/HideablePopup.java @@ -10,8 +10,6 @@ import javax.swing.*; import javax.swing.border.*; -import com.gentlyweb.utils.*; - import com.quollwriter.*; import com.quollwriter.data.*; import com.quollwriter.text.*; @@ -91,8 +89,8 @@ public void mouseExited (MouseEvent ev) * * @return The content of the popup. */ - public abstract JComponent getContent (); - + public abstract JComponent getContent (); + /** * Use if you want to show the popup after a specific delay. The hideDelay indicates how long to wait * until the user moves the mouse out of the popup before closing. The hide delay is restarted if the user @@ -212,7 +210,7 @@ public void hidePopup () this.hideTimer = null; } - + /** * Immediately shows the popup at the specified point. {@link getContent()} is called to get the content of the * popup. @@ -229,7 +227,7 @@ public void show (Point showAt) content.add (this.getContent ()); this.add (content); - + // For some reason we need to set the size manually. content.setPreferredSize (new Dimension (310, content.getPreferredSize ().height)); diff --git a/src/com/quollwriter/ui/IconColumn.java b/src/main/java/com/quollwriter/ui/IconColumn.java similarity index 100% rename from src/com/quollwriter/ui/IconColumn.java rename to src/main/java/com/quollwriter/ui/IconColumn.java diff --git a/src/com/quollwriter/ui/ImageSelector.java b/src/main/java/com/quollwriter/ui/ImageSelector.java similarity index 100% rename from src/com/quollwriter/ui/ImageSelector.java rename to src/main/java/com/quollwriter/ui/ImageSelector.java diff --git a/src/com/quollwriter/ui/ImportProject.java b/src/main/java/com/quollwriter/ui/ImportProject.java similarity index 99% rename from src/com/quollwriter/ui/ImportProject.java rename to src/main/java/com/quollwriter/ui/ImportProject.java index 6fecff12..711b7bee 100644 --- a/src/com/quollwriter/ui/ImportProject.java +++ b/src/main/java/com/quollwriter/ui/ImportProject.java @@ -20,8 +20,6 @@ import javax.swing.tree.*; import javax.swing.event.*; -import com.gentlyweb.xml.*; - import com.jgoodies.forms.builder.*; import com.jgoodies.forms.factories.*; import com.jgoodies.forms.layout.*; @@ -1015,12 +1013,12 @@ private void selectAllChildren (DefaultTreeModel model, boolean v) { - Enumeration en = n.children (); + Enumeration en = n.children (); while (en.hasMoreElements ()) { - DefaultMutableTreeNode c = en.nextElement (); + DefaultMutableTreeNode c = (DefaultMutableTreeNode) en.nextElement (); Object uo = c.getUserObject (); @@ -1768,7 +1766,7 @@ private DefaultMutableTreeNode createTree (Project p) { TreeParentNode c = new TreeParentNode (Chapter.OBJECT_TYPE, - Environment.getObjectTypeNamePlural (Chapter.OBJECT_TYPE)); + Environment.getObjectTypeNamePlural (Chapter.OBJECT_TYPE).getValue ()); SelectableDataObject sd = new SelectableDataObject (c); diff --git a/src/com/quollwriter/ui/ImportTransferHandler.java b/src/main/java/com/quollwriter/ui/ImportTransferHandler.java similarity index 100% rename from src/com/quollwriter/ui/ImportTransferHandler.java rename to src/main/java/com/quollwriter/ui/ImportTransferHandler.java diff --git a/src/com/quollwriter/ui/ImportTransferHandlerOverlay.java b/src/main/java/com/quollwriter/ui/ImportTransferHandlerOverlay.java similarity index 100% rename from src/com/quollwriter/ui/ImportTransferHandlerOverlay.java rename to src/main/java/com/quollwriter/ui/ImportTransferHandlerOverlay.java diff --git a/src/com/quollwriter/ui/Landing.java b/src/main/java/com/quollwriter/ui/Landing.java similarity index 98% rename from src/com/quollwriter/ui/Landing.java rename to src/main/java/com/quollwriter/ui/Landing.java index 4b58ef4c..d512e39b 100644 --- a/src/com/quollwriter/ui/Landing.java +++ b/src/main/java/com/quollwriter/ui/Landing.java @@ -2,6 +2,7 @@ import java.awt.*; import java.io.*; +import java.nio.file.*; import java.awt.datatransfer.*; import java.awt.event.*; import java.util.*; @@ -14,7 +15,6 @@ import javax.swing.plaf.LayerUI; import com.gentlyweb.properties.*; -import com.gentlyweb.utils.*; import org.josql.*; @@ -38,7 +38,7 @@ import com.quollwriter.ui.actionHandlers.*; import static com.quollwriter.LanguageStrings.*; -import static com.quollwriter.Environment.getUIString; +import static com.quollwriter.uistrings.UILanguageStringsManager.getUIString; // TODO: Create a PopupFrame that supports popups. @@ -104,7 +104,7 @@ public Landing () this.splitPane.setBorder (null); javax.swing.plaf.basic.BasicSplitPaneDivider div = ((javax.swing.plaf.basic.BasicSplitPaneUI) this.splitPane.getUI ()).getDivider (); - div.setBorder (new MatteBorder (0, 0, 0, 1, Environment.getBorderColor ())); + div.setBorder (new MatteBorder (0, 0, 0, 1, UIUtils.getBorderColor ())); this.splitPane.setOpaque (false); this.splitPane.setBackground (UIUtils.getComponentColor ()); @@ -580,7 +580,7 @@ private void showEditProjectInfo () ProjectInfo _bogus = new ProjectInfo (); - _bogus.setProjectDirectory (FileSystemView.getFileSystemView ().getDefaultDirectory ()); + _bogus.setProjectDirectory (FileSystemView.getFileSystemView ().getDefaultDirectory ().toPath ()); _bogus.setName (Environment.getUIString (prefix, LanguageStrings.example, LanguageStrings.name)); @@ -1130,14 +1130,14 @@ public void actionPerformed (ActionEvent ev) }); - String reason = Environment.canOpenProject (p); + javafx.beans.property.StringProperty reason = Environment.canOpenProject (p); String message = String.format (Environment.getUIString (prefix, LanguageStrings.popup, LanguageStrings.text), //"Sorry, {project} %s cannot be opened for the following reason:

    %s

    This can happen if your projects file gets out of sync with your hard drive, for example if you have re-installed your machine or if you are using a file syncing service.

    Do you want to remove it from your list of {projects}?", p.getName (), - reason); + reason.getValue ()); //message = message + "

    Note: this will only remove the {project} from the list it will not remove any other data."; @@ -1166,7 +1166,7 @@ private void showDeleteProject (final ProjectInfo p, final Landing _this = this; - final AbstractProjectViewer viewer = Environment.getProjectViewer (p); + final AbstractProjectViewer viewer = null; // TODO Environment.getProjectViewer (p); if (viewer != null) { @@ -1266,7 +1266,7 @@ private boolean handleOpenProject (final ProjectInfo p, final ActionListener onOpen) { - String reason = Environment.canOpenProject (p); + javafx.beans.property.StringProperty reason = Environment.canOpenProject (p); if (reason != null) { @@ -1286,7 +1286,7 @@ private boolean handleOpenProject (final ProjectInfo p, } // Is the project already open? - AbstractProjectViewer pv = Environment.getProjectViewer (p); + AbstractProjectViewer pv = null; // TODO Environment.getProjectViewer (p); if (pv != null) { @@ -1329,9 +1329,11 @@ public void actionPerformed (ActionEvent ev) try { +/* +TODO Environment.openProject (p, _onOpen); - +*/ return true; } catch (Exception e) @@ -1653,7 +1655,7 @@ public void init () this.showProjects (); - Environment.addProjectInfoChangedListener (this); + // TODO Environment.addProjectInfoChangedListener (this); this.setTitleHeaderControlsVisible (true); @@ -2008,14 +2010,14 @@ public String getToolTipText() String tip = null; - tip = Environment.canOpenProject (_this.project); + javafx.beans.property.StringProperty _tip = Environment.canOpenProject (_this.project); - if (tip != null) + if (_tip != null) { tip = String.format (Environment.getUIString (prefix, LanguageStrings.error), - tip); + _tip.getValue ()); //"This {project} cannot be opened for the following reason:

    " + tip + "

    Right click to remove this from your list of {projects}."; } @@ -2050,7 +2052,7 @@ public String getToolTipText() if (ed != null) { - name = ed.getShortName (); + name = ed.getMainName (); } @@ -2129,7 +2131,7 @@ public void processMouseEvent (MouseEvent ev, JPopupMenu popup = new JPopupMenu (); - String reason = Environment.canOpenProject (_this.project); + javafx.beans.property.StringProperty reason = Environment.canOpenProject (_this.project); if (reason != null) { @@ -2273,7 +2275,7 @@ public void actionPerformed (ActionEvent ev) { UIUtils.showFile (null, - _this.project.getProjectDirectory ()); + _this.project.getProjectDirectory ().toFile ()); } @@ -2514,42 +2516,42 @@ public String getFormattedProjectInfo () text = text.toLowerCase (); - text = StringUtils.replaceString (text, + text = Utils.replaceString (text, " ", " "); - text = StringUtils.replaceString (text, + text = Utils.replaceString (text, nl, "
    "); - text = StringUtils.replaceString (text, + text = Utils.replaceString (text, STATUS_TAG, (this.project.getStatus () != null ? this.project.getStatus () : getUIString (LanguageStrings.project,status,novalue))); //"No status")); - text = StringUtils.replaceString (text, + text = Utils.replaceString (text, WORDS_TAG, String.format (Environment.getUIString (prefix, LanguageStrings.words), //"%s words", Environment.formatNumber (this.project.getWordCount ()))); - text = StringUtils.replaceString (text, + text = Utils.replaceString (text, CHAPTERS_TAG, String.format (Environment.getUIString (prefix, LanguageStrings.chapters), //"%s ${objectnames.%s.chapter}", Environment.formatNumber (this.project.getChapterCount ()))); - text = StringUtils.replaceString (text, + text = Utils.replaceString (text, LAST_EDITED_TAG, lastEd); - text = StringUtils.replaceString (text, + text = Utils.replaceString (text, EDIT_COMPLETE_TAG, String.format (Environment.getUIString (prefix, LanguageStrings.editcomplete), //"%s%% complete", - Environment.formatNumber (Environment.getPercent (this.project.getEditedWordCount (), project.getWordCount ())))); - text = StringUtils.replaceString (text, + Environment.formatNumber (Utils.getPercent (this.project.getEditedWordCount (), project.getWordCount ())))); + text = Utils.replaceString (text, READABILITY_TAG, String.format (Environment.getUIString (prefix, LanguageStrings.readability), @@ -2787,7 +2789,7 @@ private String getIconName () String n = Project.OBJECT_TYPE; - if (!this.project.getProjectDirectory ().exists ()) + if (Files.notExists (this.project.getProjectDirectory ())) { // Return a problem icon. @@ -2979,7 +2981,7 @@ public boolean viewEditors () try { - EditorsUIUtils.showRegister (this); + //EditorsUIUtils.showRegister (this); } catch (Exception e) { @@ -2998,7 +3000,8 @@ public boolean viewEditors () return true; } - +/* + REMOVE AbstractSideBar sb = this.sideBars.get (EditorsSideBar.ID); if (sb == null) @@ -3013,7 +3016,7 @@ public boolean viewEditors () } this.showSideBar (EditorsSideBar.ID); - +*/ return true; } @@ -3101,7 +3104,8 @@ public void viewEditor (final EditorEditor ed) public void actionPerformed (ActionEvent ev) { - +/* +REMOVE EditorsSideBar sb = (EditorsSideBar) _this.sideBars.get (EditorsSideBar.ID); if (sb == null) @@ -3129,7 +3133,7 @@ public void actionPerformed (ActionEvent ev) //"Unable to show Editor"); } - +*/ } }); @@ -3139,7 +3143,8 @@ public void actionPerformed (ActionEvent ev) @Override public boolean isEditorsVisible () { - +/* +REMOVE EditorsSideBar sb = (EditorsSideBar) this.sideBars.get (EditorsSideBar.ID); if (sb != null) @@ -3148,7 +3153,7 @@ public boolean isEditorsVisible () return sb.isShowing (); } - +*/ return false; } @@ -3219,7 +3224,7 @@ public void actionPerformed (ActionEvent ev) c = UIUtils.createButton (Constants.PROJECT_IMPORT_ICON_NAME, Constants.ICON_TITLE_ACTION, Environment.getUIString (prefix, - LanguageStrings.add, + LanguageStrings.importfile, LanguageStrings.tooltip), //"Click to create a new {project} by importing a file", new ActionAdapter () @@ -3602,7 +3607,8 @@ public boolean showOptions (String section) Options.Section.warmups, Options.Section.achievements, Options.Section.problems, - Options.Section.betas); + Options.Section.betas, + Options.Section.website); this.options.init (); @@ -3721,7 +3727,7 @@ public void actionPerformed (ActionEvent ev) try { - pi = Environment.getProjectByDirectory (dir); + pi = null; // TODO Environment.getProjectByDirectory (dir); } catch (Exception e) { @@ -3742,7 +3748,7 @@ public void actionPerformed (ActionEvent ev) { pi = new ProjectInfo (); - pi.setProjectDirectory (dir); + pi.setProjectDirectory (dir.toPath ()); om = Environment.getProjectObjectManager (pi, null); @@ -3777,11 +3783,11 @@ public void actionPerformed (ActionEvent ev) // Get the file name. pi.setEncrypted (true); pi.setName (WordsCapitalizer.capitalizeEveryWord (dir.getName ())); - pi.setProjectDirectory (dir); + pi.setProjectDirectory (dir.toPath ()); Project p = new Project (); p.setProjectDirectory (dir); - pi.setBackupDirectory (p.getBackupDirectory ()); + pi.setBackupDirPath (p.getBackupDirectory ().toPath ()); } else { @@ -3921,7 +3927,7 @@ public void showFindProjects () LanguageStrings.find)); //"Find"); - final FileFinder finder = UIUtils.createFileFind (Environment.getUserQuollWriterDir ().getPath (), + final FileFinder finder = UIUtils.createFileFind (Environment.getUserQuollWriterDirPath ().toFile ().getPath (), Environment.getUIString (prefix, LanguageStrings.finder, LanguageStrings.title), @@ -4133,7 +4139,8 @@ public void sendMessageToEditor (final EditorEditor ed) public void actionPerformed (ActionEvent ev) { - +/* +REMOVE EditorsSideBar sb = (EditorsSideBar) _this.sideBars.get (EditorsSideBar.ID); if (sb == null) @@ -4161,7 +4168,7 @@ public void actionPerformed (ActionEvent ev) LanguageStrings.vieweditorerror)); } - +*/ } }); @@ -4237,7 +4244,7 @@ public boolean close (boolean noConfirm, } - Environment.removeProjectInfoChangedListener (this); + // TODO Environment.removeProjectInfoChangedListener (this); super.close (true, null); diff --git a/src/main/java/com/quollwriter/ui/LanguageStringsEditor.java b/src/main/java/com/quollwriter/ui/LanguageStringsEditor.java new file mode 100644 index 00000000..782a2568 --- /dev/null +++ b/src/main/java/com/quollwriter/ui/LanguageStringsEditor.java @@ -0,0 +1,1609 @@ +package com.quollwriter.ui; + +import java.awt.*; +import java.io.*; +import java.awt.datatransfer.*; +import java.awt.event.*; +import java.util.*; +import java.util.concurrent.*; +import java.text.*; +import java.net.*; + +import javax.swing.*; +import javax.swing.border.*; +import javax.swing.text.*; +import javax.swing.event.*; +import javax.swing.filechooser.*; +import javax.swing.plaf.LayerUI; +import javax.swing.tree.*; + +import com.gentlyweb.properties.*; + +import org.josql.*; + +import com.jgoodies.forms.builder.*; +import com.jgoodies.forms.factories.*; +import com.jgoodies.forms.layout.*; + +import com.quollwriter.*; +import com.quollwriter.events.*; +import com.quollwriter.data.*; +import com.quollwriter.ui.events.*; +import com.quollwriter.data.comparators.*; +import com.quollwriter.data.editors.*; +import com.quollwriter.editors.*; +import com.quollwriter.ui.components.*; +import com.quollwriter.ui.panels.*; +import com.quollwriter.text.*; +import com.quollwriter.db.*; +import com.quollwriter.ui.sidebars.*; +import com.quollwriter.editors.*; +import com.quollwriter.editors.ui.*; +import com.quollwriter.editors.ui.sidebars.*; +import com.quollwriter.achievements.ui.*; +import com.quollwriter.ui.charts.*; +import com.quollwriter.ui.actionHandlers.*; +import com.quollwriter.ui.forms.*; +import com.quollwriter.ui.components.ScrollableBox; +import com.quollwriter.ui.components.SpellChecker; +import com.quollwriter.uistrings.*; + +import static com.quollwriter.LanguageStrings.*; +import static com.quollwriter.Environment.getUIString; + +public class LanguageStringsEditor extends AbstractLanguageStringsEditor +{ + + public static final String MAIN_CARD = "main"; + public static final String OPTIONS_CARD = "options"; + + public static final String SUBMIT_HEADER_CONTROL_ID = "submit"; + public static final String USE_HEADER_CONTROL_ID = "use"; + public static final String HELP_HEADER_CONTROL_ID = "help"; + public static final String FIND_HEADER_CONTROL_ID = "find"; + + public static int INTERNAL_SPLIT_PANE_DIVIDER_WIDTH = 2; + + public LanguageStringsEditor (UILanguageStrings userStrings) + throws Exception + { + + this (userStrings, + Environment.getQuollWriterVersion ()); + + } + + public LanguageStringsEditor (UILanguageStrings userStrings, + UILanguageStrings baseStrings) + throws Exception + { + + super (userStrings, + baseStrings); + + } + + public LanguageStringsEditor (UILanguageStrings userStrings, + Version baseQWVersion) + throws Exception + { + + super (userStrings); + + if (baseQWVersion == null) + { + + baseQWVersion = Environment.getQuollWriterVersion (); + + } + + if (userStrings == null) + { + + throw new IllegalArgumentException ("No strings provided."); + + } + + UILanguageStrings baseStrings = UILanguageStringsManager.getUserUIEnglishLanguageStrings (baseQWVersion); + + if (baseStrings == null) + { + + throw new IllegalArgumentException ("Unable to find English strings for version: " + baseQWVersion); + + } + + this.setBaseStrings (baseStrings); + + } +/* + private int getErrorCount (LanguageStrings.Node n) + { + + int c = 0; + + // Get the card. + IdsPanel p = this.panels.get (n.getNodeId ()); + + if (p != null) + { + + return p.getErrorCount (); + + } + + for (LanguageStrings.Value nv : this.valuesCache.get (n)) + { + + LanguageStrings.Value uv = this.userStrings.getValue (nv.getId (), + true); + + if (uv instanceof LanguageStrings.TextValue) + { + + LanguageStrings.TextValue _nv = this.baseStrings.getTextValue (uv.getId ()); + + if (nv == null) + { + + // The string is present in the user strings but not the base! + Environment.logError ("Found string: " + uv.getId () + " present in user strings but not base."); + + continue; + + } + + if (LanguageStrings.getErrors (((LanguageStrings.TextValue) uv).getRawText (), + LanguageStrings.toId (nv.getId ()), + _nv.getSCount (), + this).size () > 0) + { + + c++; + + }; + + } + + } + + return c; + + } +*/ + + public void showChanges (UILanguageStrings newls) + { + + Version v = this.userStrings.getQuollWriterVersion (); + + try + { + + UILanguageStringsManager.saveUserUILanguageStrings (newls); + + this.userStrings.setQuollWriterVersion (newls.getQuollWriterVersion ()); + + UILanguageStringsManager.saveUserUILanguageStrings (this.userStrings); + + this.userStrings.setQuollWriterVersion (v); + + UILanguageStrings uls = UILanguageStringsManager.getUserUILanguageStrings (newls.getQuollWriterVersion (), + this.userStrings.getId ()); + + // Get a diff of the default to this new. +/* + LanguageStringsEditor lse = UILanguageStringsManager.editUILanguageStrings (uls, + newls.getQuollWriterVersion ()); + lse.limitViewToPreviousVersionDiff (); +*/ + } catch (Exception e) { + + Environment.logError ("Unable to show strings editor for: " + + newls, + e); + + UIUtils.showErrorMessage (this, + "Unable to show strings."); + + } + + } + + public void limitViewToPreviousVersionDiff () + throws Exception + { + + try + { + + this.save (); + + } catch (Exception e) { + + Environment.logError ("Unable to save", + e); + + UIUtils.showErrorMessage (this, + "Unable to update view."); + + return; + + } + + final UILanguageStrings basels = this.baseStrings; + + // Get the previous version (which will be the current QW version). + final UILanguageStrings prevbasels = UILanguageStringsManager.getUserUIEnglishLanguageStrings (Environment.getQuollWriterVersion ()); + + if (prevbasels == null) + { + + // No strings. + return; + + } + + this.setNodeFilter (new Filter () + { + + @Override + public boolean accept (Node n) + { + + Node pn = prevbasels.getNode (n.getId ()); + + // Does the node exist in the current base strings but not the previous? + if (pn == null) + { + + // This is a new node. + return true; + + } + + // It exists, but has it changed? + if ((n instanceof Value) + && + (!(pn instanceof Value)) + ) + { + + // Node type changed. + return true; + + } + + if ((pn instanceof Value) + && + (!(n instanceof Value)) + ) + { + + // Node type changed. + return true; + + } + + if ((pn instanceof TextValue) + && + (n instanceof TextValue) + ) + { + + TextValue pnv = (TextValue) pn; + TextValue nv = (TextValue) n; + + // Value changed? + if (pnv.getRawText ().equals (nv.getRawText ())) + { + + return false; + + } + + } + + return true; + + } + + }); + + this.showForwardLabel (String.format ("Click to show all the strings for version %s.", + this.userStrings.getQuollWriterVersion ().toString ())); + + } + + private void saveToFile () + throws Exception + { + + UILanguageStringsManager.saveUserUILanguageStrings (this.userStrings); + + } + + @Override + public void save () + throws Exception + { + + // Cycle over all the id boxes and set the values if present. + for (LanguageStringsIdsPanel p : this.panels.values ()) + { + + p.saveValues (); + + } + + this.userStrings.setQuollWriterVersion (this.baseStrings.getQuollWriterVersion ()); + + this.saveToFile (); + + } + + private void updateTitle () + { + + this.setViewerTitle (String.format ("Edit Language Strings for: %s (%s)", + this.userStrings.getNativeName (), + this.baseStrings.getQuollWriterVersion ().toString ())); + + } + + @Override + public void onForwardLabelClicked () + throws Exception + { + + if (this.nodeFilter != null) + { + + this.showAllStrings (); + + this.showForwardLabel (String.format ("Click to show what's changed/new between version %s and %s.", + Environment.getQuollWriterVersion ().toString (), + this.userStrings.getQuollWriterVersion ().toString ())); + + } else { + + this.limitViewToPreviousVersionDiff (); + + } + + } + + @Override + public void init () + throws Exception + { + + super.init (); + + final LanguageStringsEditor _this = this; + + this.updateTitle (); + + // Check to see if a new version of the default strings is available. + Environment.schedule (() -> + { + + String url = UserProperties.get (Constants.QUOLL_WRITER_GET_UI_LANGUAGE_STRINGS_URL_PROPERTY_NAME); + + url = Utils.replaceString (url, + Constants.VERSION_TAG, + _this.baseStrings.getQuollWriterVersion ().toString ()); + url = Utils.replaceString (url, + Constants.ID_TAG, + _this.baseStrings.getId ()); + + url = Utils.replaceString (url, + Constants.LAST_MOD_TAG, + "0"); + + url += "&newer=true"; + + try + { + + String data = Utils.getUrlFileAsString (new URL (Environment.getQuollWriterWebsite () + "/" + url)); + + if (data.startsWith (Constants.JSON_RETURN_PREFIX)) + { + + data = data.substring (Constants.JSON_RETURN_PREFIX.length ()); + + } + + Object obj = JSONDecoder.decode (data); + + if (obj == null) + { + + return; + + } + + final UILanguageStrings newls = new UILanguageStrings (data); + + Box content = new Box (BoxLayout.Y_AXIS); + + content.add (UIUtils.createHelpTextPane (String.format ("A new version of the %s language strings is available. This is for version %s, of {QW}.
    You can view the changes and submit an update to your strings.", + newls.getNativeName (), + newls.getQuollWriterVersion ().toString ()), + _this)); + + content.add (Box.createVerticalStrut (5)); + + JButton b = UIUtils.createButton ("View the changes"); + + content.add (b); + + // Add a notification. + final Notification n = _this.addNotification (content, + Constants.INFO_ICON_NAME, + -1); + + b.addActionListener (new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + UILanguageStrings uls = null; + + try + { + + uls = UILanguageStringsManager.getUserUILanguageStrings (newls.getQuollWriterVersion (), + _this.userStrings.getId ()); + + } catch (Exception e) { + + Environment.logError ("Unable to get user strings for version: " + newls.getQuollWriterVersion () + ", " + _this.userStrings.getId (), + e); + + UIUtils.showErrorMessage (null, + getUIString (uilanguage,edit,actionerror)); + + return; + + } + + if (uls != null) + { + + // Open these instead. + /* + LanguageStringsEditor lse = UILanguageStringsManager.editUILanguageStrings (uls, + uls.getQuollWriterVersion ()); + + try + { + + lse.limitViewToPreviousVersionDiff (); + + } catch (Exception e) { + + Environment.logError ("Unable to update view", + e); + + UIUtils.showErrorMessage (_this, + "Unable to update view"); + + return; + + } +*/ + _this.removeNotification (n); + + return; + + } + + _this.showChanges (newls); + + _this.removeNotification (n); + + } + + }); + + } catch (Exception e) { + + Environment.logError ("Unable to get new user interface strings", + e); + + } + + }, + 5, + -1); + + if (!UserProperties.getAsBoolean (Constants.LANGUAGE_STRINGS_FIRST_USE_SEEN_PROPERTY_NAME)) + { + + UIUtils.showMessage ((PopupsSupported) this, + "Welcome to the Editor!", + "Welcome to the strings Editor. This window is where you'll create your own strings for a language for the {QW} User Interface.

    It is recommended that you read the strings editor guide before starting out. It describes how the editor works and the concepts used.

    All feedback and ideas are welcome."); + + UserProperties.set (Constants.LANGUAGE_STRINGS_FIRST_USE_SEEN_PROPERTY_NAME, + true); + + } + + } + + @Override + public void doSaveState () + { + + super.doSaveState (); + + } + + @Override + public Set getTitleHeaderControlIds () + { + + Set ids = new LinkedHashSet (); + + ids.add (SUBMIT_HEADER_CONTROL_ID); + ids.add (FIND_HEADER_CONTROL_ID); + ids.add (USE_HEADER_CONTROL_ID); + //ids.add (REPORT_BUG_HEADER_CONTROL_ID); + ids.add (HELP_HEADER_CONTROL_ID); + ids.add (SETTINGS_HEADER_CONTROL_ID); + + return ids; + + } + + @Override + public JComponent getTitleHeaderControl (String id) + { + + if (id == null) + { + + return null; + + } + + java.util.List prefix = Arrays.asList (allprojects,headercontrols,items); + + final LanguageStringsEditor _this = this; + + JComponent c = null; + + if (id.equals (HELP_HEADER_CONTROL_ID)) + { + + c = UIUtils.createButton (Constants.HELP_ICON_NAME, + Constants.ICON_TITLE_ACTION, + "Click to view the help about editing your strings", + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + UIUtils.openURL (_this, + "help:uilanguage"); + + } + + }); + + } + + if (c != null) + { + + return c; + + } + + return super.getTitleHeaderControl (id); + + } + + @Override + public void submit (ActionListener onSuccess, + ActionListener onError) + { + + final LanguageStringsEditor _this = this; + + try + { + + this.save (); + + } catch (Exception e) { + + Environment.logError ("Unable to save: " + this.userStrings, + e); + + UIUtils.showErrorMessage (this, + "Unable to save strings."); + + return; + + } + + Set vals = this.userStrings.getAllValues (); + + if (vals.size () == 0) + { + + UIUtils.showMessage ((PopupsSupported) this, + "No strings provided", + "Sorry, you must provide at least 1 string."); + + return; + + } + + int c = 0; + + for (Value uv : vals) + { + + if (uv instanceof TextValue) + { + + TextValue nv = this.baseStrings.getTextValue (uv.getId ()); + + if (nv == null) + { + + // The string is present in the user strings but not the base! + Environment.logError ("Found string: " + uv.getId () + " present in user strings but not base."); + + continue; + + } + + c += BaseStrings.getErrors (((TextValue) uv).getRawText (), + BaseStrings.toId (nv.getId ()), + nv.getSCount (), + this).size (); + + } + + } + + if (c > 0) + { + + UIUtils.showMessage ((PopupsSupported) this, + "Errors found in strings", + String.format ("Sorry, there are %s errors that must be corrected before you can submit the strings.", + Environment.formatNumber (c))); + + return; + + } + + final String popupName = "submit"; + QPopup popup = this.getNamedPopup (popupName); + + if (popup == null) + { + + popup = UIUtils.createClosablePopup ("Submit your strings", + Environment.getIcon (Constants.UP_ICON_NAME, + Constants.ICON_POPUP), + null); + + final QPopup qp = popup; + + Box content = new Box (BoxLayout.Y_AXIS); + + JTextPane help = UIUtils.createHelpTextPane ("Complete the form below to submit your strings. All the values are required.", + this); + + help.setBorder (null); + + content.add (help); + content.add (Box.createVerticalStrut (10)); + + final JLabel error = UIUtils.createErrorLabel (""); + error.setVisible (false); + error.setBorder (UIUtils.createPadding (0, 5, 5, 5)); + + content.add (error); + + Set items = new LinkedHashSet (); + + final TextFormItem nativelang = new TextFormItem ("Native Name (i.e. Espa\u00F1ol, Fran\u00E7ais, Deutsch)", + this.userStrings.getNativeName ()); + + items.add (nativelang); + + final TextFormItem lang = new TextFormItem ("English Name (i.e. Spanish, French, German)", + this.userStrings.getLanguageName ()); + + items.add (lang); + + final TextFormItem email = new TextFormItem ("Contact Email", + this.userStrings.getEmail ()); + + items.add (email); + + final JLabel tc = UIUtils.createClickableLabel ("View the Terms and Conditions for creating a translation", + Environment.getIcon (Constants.INFO_ICON_NAME, + Constants.ICON_CLICKABLE_LABEL), + Environment.getQuollWriterHelpLink ("uilanguages/terms-and-conditions", + null)); + + final CheckboxFormItem tandc = new CheckboxFormItem (null, "I have read and agree to the Terms and Conditions"); + + if (this.userStrings.getStringsVersion () == 0) + { + + items.add (new AnyFormItem (null, tc)); + items.add (tandc); + + } + + ActionListener saveAction = new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + String em = email.getValue (); + + if (em == null) + { + + error.setText ("Please enter a valid email."); + error.setVisible (true); + qp.resize (); + qp.resize (); + + return; + + } + + String l = lang.getValue (); + + if (l == null) + { + + error.setText ("Please enter the English Language name."); + error.setVisible (true); + qp.resize (); + + return; + + } + + String nl = nativelang.getValue (); + + if (nl == null) + { + + error.setText ("Please enter the Name Language name."); + error.setVisible (true); + qp.resize (); + + return; + + } + + if (_this.userStrings.getAllValues ().size () == 0) + { + + error.setText ("No strings provided. Please provide at least 1 string for your translation."); + error.setVisible (true); + qp.resize (); + + return; + + } + + if ((_this.userStrings.getStringsVersion () == 0) + && + (!tandc.isSelected ()) + ) + { + + error.setText ("To submit your strings you must agree to the Terms & Conditions, and please give them a quick read ;)"); + error.setVisible (true); + qp.resize (); + + return; + + } + + _this.userStrings.setEmail (em); + _this.userStrings.setLanguageName (l); + _this.userStrings.setNativeName (nl); + + _this.updateTitle (); + + try + { + + _this.save (); + + } catch (Exception e) { + + Environment.logError ("Unable to save strings: " + _this.userStrings, + e); + + UIUtils.showErrorMessage (_this, + "Unable to save strings."); + + return; + + } + + // Get the file, then send. + String t = null; + + try + { + + t = JSONEncoder.encode (_this.userStrings.getAsJSON ()); + + } catch (Exception e) + { + + Environment.logError ("Unable to upload strings: " + _this.userStrings, + e); + + UIUtils.showErrorMessage (_this, + "Unable to upload strings."); + + return; + + } + + Map headers = new HashMap<> (); + + String submitterid = UserProperties.get (Constants.UI_LANGUAGE_STRINGS_SUBMITTER_ID_PROPERTY_NAME); + + if (submitterid != null) + { + + headers.put (Constants.UI_LANGUAGE_STRINGS_SUBMITTER_ID_HEADER_NAME, + submitterid); + + } + + URL u = null; + + try + { + + u = new URL (Environment.getQuollWriterWebsite () + UserProperties.get (Constants.SUBMIT_UI_LANGUAGE_STRINGS_URL_PROPERTY_NAME)); + + } catch (Exception e) { + + Environment.logError ("Unable to construct the url for submitting the ui language strings.", + e); + + UIUtils.showErrorMessage (_this, + "Unable to upload strings."); + + return; + + } + + qp.setVisible (false); + + final ProgressPopup pp = new ProgressPopup (_this, + "Uploading", + "up", + "Uploading strings, please wait..."); + + _this.showPopupAt (pp, + UIUtils.getCenterShowPosition (_this, + pp), + false); + + pp.setDraggable (_this); + + Utils.postToURL (u, + headers, + t, + // On success + (content, resCode) -> + { + + pp.removeFromParent (); + + Map m = (Map) JSONDecoder.decode (content); + + String res = (String) m.get ("result"); + + String sid = (String) m.get ("submitterid"); + + UserProperties.set (Constants.UI_LANGUAGE_STRINGS_SUBMITTER_ID_PROPERTY_NAME, + sid); + + //_this.userStrings.setSubmitterId (sid); + _this.userStrings.setStringsVersion (((Number) m.get ("version")).intValue ()); + + try + { + + _this.saveToFile (); + + } catch (Exception e) { + + Environment.logError ("Unable to save strings file: " + + _this.userStrings, + e); + + UIUtils.showErrorMessage (_this, + "Your strings have been submitted to Quoll Writer support for review. However the associated local file, where the strings are kept on your machine, could not be updated."); + + return; + + } + + if (_this.userStrings.getStringsVersion () == 1) + { + + UIUtils.showMessage ((PopupsSupported) _this, + "Strings submitted", + String.format ("Your strings have been submitted to Quoll Writer support for review.

    A confirmation email has been sent to %s. Please click on the link in that email to confirm your email address.

    Thank you for taking the time and the effort to create the strings, it is much appreciated!", + _this.userStrings.getEmail ())); + + } else { + + UIUtils.showMessage ((PopupsSupported) _this, + "Strings submitted", + String.format ("Thank you! Your strings have been updated to version %s and will be made available to Quoll Writer users.

    Thank you for taking the time and effort to update the strings, it is much appreciated!", + Environment.formatNumber (_this.userStrings.getStringsVersion ()))); + + } + + qp.resize (); + qp.removeFromParent (); + + }, + // On error + (errContent, resCode) -> + { + + pp.removeFromParent (); + + Map m = (Map) JSONDecoder.decode (errContent); + + String res = (String) m.get ("reason"); + + // Get the errors. + UIUtils.showErrorMessage (_this, + "Unable to submit the strings, reason:
    • " + res + "
    "); + + }, + exp -> + { + +/* +TODO Improve + pp.removeFromParent (); + + Map m = (Map) JSONDecoder.decode ((String) ev.getSource ()); + + String res = (String) m.get ("reason"); + + // Get the errors. + UIUtils.showErrorMessage (_this, + "Unable to submit the strings, reason:
    • " + res + "
    "); +*/ + }, + // Updater + eev -> + { + + pp.update (eev.getPercent ()); + + }); + + } + + }; + + UIUtils.addDoActionOnReturnPressed (lang.getTextField (), + saveAction); + UIUtils.addDoActionOnReturnPressed (nativelang.getTextField (), + saveAction); + UIUtils.addDoActionOnReturnPressed (email.getTextField (), + saveAction); + + JButton save = UIUtils.createButton ("Submit", + saveAction); + JButton cancel = UIUtils.createButton ("Cancel", + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + qp.removeFromParent (); + _this.removeNamedPopup (popupName); + + } + + }); + + Set buttons = new LinkedHashSet (); + buttons.add (save); + buttons.add (cancel); + + Form f = new Form (Form.Layout.stacked, + items, + buttons); + + content.add (f); + + content.setSize (new Dimension (UIUtils.getPopupWidth () - 20, + content.getPreferredSize ().height)); + content.setBorder (UIUtils.createPadding (10, 10, 10, 10)); + + popup.setContent (content); + + popup.setDraggable (this); + + popup.setPopupName (popupName); + + this.addNamedPopup (popupName, + popup); + + //popup.resize (); + this.showPopupAt (popup, + UIUtils.getCenterShowPosition (this, + popup), + false); + + UIUtils.doLater (new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + //desc.grabFocus (); + qp.resize (); + + } + + }); + + } else { + + popup.setVisible (true); + popup.resize (); + + } + + } + + @Override + public void tryOut () + { + + if (!this.userStrings.getQuollWriterVersion ().equals (Environment.getQuollWriterVersion ())) + { + + UIUtils.showMessage ((PopupsSupported) this, + "Unable to try out", + "Sorry, you can only try out a set of strings if the version matches the currently installed {QW} version."); + + return; + + } + + try + { + + this.save (); + + Environment.setUILanguage ("user-" + this.userStrings.getId ()); + + } catch (Exception e) { + + Environment.logError ("Unable to update ui language for: " + this.userStrings.getId (), + e); + + UIUtils.showErrorMessage (this, + "Unable to set strings."); + + return; + + } + + UIUtils.showMessage ((PopupsSupported) this, + "Restart recommended", + "{QW} has been updated to make use of your strings. To make full use of them it is recommended that you restart {QW}."); + + } + + @Override + public void fillSettingsPopup (JPopupMenu popup) + { + + //java.util.List prefix = Arrays.asList (allprojects,settingsmenu,items); + + final LanguageStringsEditor _this = this; + + popup.add (this.createMenuItem ("Submit your strings", + Constants.UP_ICON_NAME, + new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + _this.submit (null, + null); + + } + + })); + + popup.add (this.createMenuItem ("Create a new translation", + Constants.NEW_ICON_NAME, + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + UIUtils.showAddNewUILanguageStringsPopup (_this); + + } + + })); + + popup.add (this.createMenuItem ("Edit a translation", + Constants.EDIT_ICON_NAME, + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + UIUtils.showEditUILanguageStringsSelectorPopup (_this); + + } + + })); + + if (this.baseStrings.getQuollWriterVersion ().equals (Environment.getQuollWriterVersion ())) + { + + popup.add (this.createMenuItem ("Try out your strings", + Constants.PLAY_ICON_NAME, + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + _this.tryOut (); + + } + + })); + + } + + popup.add (this.createMenuItem ("Delete", + Constants.DELETE_ICON_NAME, + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + try + { + + _this.delete (); + + } catch (Exception e) { + + Environment.logError ("Unable to delete strings.", + e); + + UIUtils.showErrorMessage (_this, + "Unable to delete the strings."); + + } + + } + + })); + + popup.add (this.createMenuItem ("Close", + Constants.CLOSE_ICON_NAME, + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + _this.close (true, + null); + + } + + })); + + popup.addSeparator (); + + popup.add (this.createMenuItem ("Open Project", + Constants.UP_ICON_NAME, + new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + Environment.showAllProjectsViewer (); + + } + + })); + + + } + + @Override + public void delete () + throws Exception + { + + final LanguageStringsEditor _this = this; + + QPopup qp = UIUtils.createPopup ("Delete the strings", + Constants.DELETE_ICON_NAME, + null, + true, + null); + + final Box content = new Box (BoxLayout.Y_AXIS); + + JComponent mess = UIUtils.createHelpTextPane ("Please confirm you wish to delete your strings. Enter Yes in the box below to confirm deletion.

    To delete all versions of the strings please check the box below.

    Warning! This is an irreverisble operation and cannot be undone. This will make your strings unavailable to {QW} users but will not remove it from anyone who has already downloaded the strings.", + this); + mess.setBorder (null); + mess.setSize (new Dimension (UIUtils.getPopupWidth () - 20, + mess.getPreferredSize ().height)); + + content.add (mess); + + content.add (Box.createVerticalStrut (10)); + + final JCheckBox delAll = UIUtils.createCheckBox ("Delete all versions"); + + content.add (delAll); + + content.add (Box.createVerticalStrut (10)); + + final JLabel error = UIUtils.createErrorLabel ("Please enter the word Yes."); + //"Please enter a value."); + + error.setVisible (false); + error.setBorder (UIUtils.createPadding (0, 0, 5, 0)); + + final JTextField text = UIUtils.createTextField (); + + text.setMinimumSize (new Dimension (300, + text.getPreferredSize ().height)); + text.setPreferredSize (new Dimension (300, + text.getPreferredSize ().height)); + text.setMaximumSize (new Dimension (Short.MAX_VALUE, + text.getPreferredSize ().height)); + text.setAlignmentX (Component.LEFT_ALIGNMENT); + + error.setAlignmentX (Component.LEFT_ALIGNMENT); + + content.add (error); + content.add (text); + + content.add (Box.createVerticalStrut (10)); + + JButton confirm = null; + JButton cancel = UIUtils.createButton ("No, keep them", + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + qp.removeFromParent (); + + } + + }); + + ActionListener confirmAction = new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + String mess = UIUtils.getYesValueValidator ().isValid (text.getText ().trim ()); + + if (mess != null) + { + + // Should probably wrap this in a + error.setText (mess); + + error.setVisible (true); + + // Got to be an easier way of doing this. + content.setPreferredSize (null); + + content.setPreferredSize (new Dimension (UIUtils.getPopupWidth (), + content.getPreferredSize ().height)); + + _this.showPopupAt (qp, + qp.getLocation (), + false); + + return; + + } + + String submitterid = UserProperties.get (Constants.UI_LANGUAGE_STRINGS_SUBMITTER_ID_PROPERTY_NAME); + + if ((submitterid != null) + && + // Has they been submitted? + (_this.userStrings.getStringsVersion () > 0) + ) + { + + URL u = null; + + try + { + + String p = UserProperties.get (Constants.DELETE_UI_LANGUAGE_STRINGS_URL_PROPERTY_NAME); + + p = Utils.replaceString (p, + Constants.ID_TAG, + _this.userStrings.getId ()); + + p = Utils.replaceString (p, + Constants.VERSION_TAG, + _this.userStrings.getQuollWriterVersion ().toString ()); + + p = Utils.replaceString (p, + Constants.ALL_TAG, + (delAll.isSelected () ? "true" : "")); + + u = new URL (Environment.getQuollWriterWebsite () + p); + + } catch (Exception e) { + + Environment.logError ("Unable to construct the url for submitting the ui language strings.", + e); + + UIUtils.showErrorMessage (_this, + "Unable to upload strings."); + + return; + + } + + Map headers = new HashMap<> (); + + headers.put (Constants.UI_LANGUAGE_STRINGS_SUBMITTER_ID_HEADER_NAME, + submitterid); + + Utils.postToURL (u, + headers, + "bogus", + // On success + (content, resCode) -> + { + + String r = (String) JSONDecoder.decode (content); + + // Delete our local versions. + try + { +/* +TODO Remove + UILanguageStringsManager.deleteUserUILanguageStrings (_this.userStrings, + delAll.isSelected ()); +*/ + } catch (Exception e) { + + Environment.logError ("Unable to delete user strings: " + _this.userStrings, + e); + + UIUtils.showErrorMessage (_this, + "Unable to delete the strings."); + + qp.removeFromParent (); + + return; + + } + + LanguageStringsEditor.super.close (true, + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + UIUtils.showMessage ((Component) null, + "Strings deleted", + "Your strings have been deleted.

    Thank you for the time and effort you put in to create the strings, it is much appreciated!"); + + } + + }); + + }, + // On error + (errContent, resCode) -> + { + + Map m = (Map) JSONDecoder.decode (errContent); + + String res = (String) m.get ("reason"); + + // Get the errors. + UIUtils.showErrorMessage (_this, + "Unable to submit the strings, reason:
    • " + res + "
    "); + + }, + eex -> + { + +/* +TODO Improve + Map m = (Map) JSONDecoder.decode ((String) ev.getSource ()); + + String res = (String) m.get ("reason"); + + // Get the errors. + UIUtils.showErrorMessage (_this, + "Unable to delete the strings, reason:
    • " + res + "
    "); +*/ + + }, + null); + + } else { + + // Not been submitted. + // Delete our local versions. + try + { + +/* +TODO Remove + UILanguageStringsManager.deleteUserUILanguageStrings (_this.userStrings, + delAll.isSelected ()); +*/ + } catch (Exception e) { + + Environment.logError ("Unable to delete user strings: " + _this.userStrings, + e); + + UIUtils.showErrorMessage (_this, + "Unable to delete the strings."); + + qp.removeFromParent (); + + return; + + } + + // Close without saving. + LanguageStringsEditor.super.close (true, + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + UIUtils.showMessage ((Component) null, + "Strings deleted", + "Your strings have been deleted."); + + } + + }); + + } + + } + + }; + + confirm = UIUtils.createButton ("Yes, delete them", + confirmAction); + + UIUtils.addDoActionOnReturnPressed (text, + confirmAction); + + JButton[] buts = null; + + if (confirm != null) + { + + buts = new JButton[] { confirm, cancel }; + + } else { + + buts = new JButton[] { cancel }; + + } + + JComponent buttons = UIUtils.createButtonBar2 (buts, + Component.LEFT_ALIGNMENT); //ButtonBarFactory.buildLeftAlignedBar (buts); + buttons.setAlignmentX (Component.LEFT_ALIGNMENT); + content.add (buttons); + content.setBorder (UIUtils.createPadding (10, 10, 10, 10)); + + content.setPreferredSize (new Dimension (UIUtils.getPopupWidth (), + content.getPreferredSize ().height)); + + qp.setContent (content); + qp.setDraggable (this); + + this.showPopupAt (qp, + UIUtils.getCenterShowPosition (this, + qp), + false); + + } + + @Override + public boolean close (boolean noConfirm, + final ActionListener afterClose) + { + + super.close (noConfirm, + afterClose); + + return true; + + } + + @Override + public void showReportProblemForId (String id) + { + + this.showReportProblem ("Language Strings Id: " + id + "\n\n"); + + } + + @Override + public boolean isIdValid (String id) + { + + throw new IllegalStateException ("DO NOT USE!"); + + } + +} diff --git a/src/main/java/com/quollwriter/ui/LanguageStringsIdBox.java b/src/main/java/com/quollwriter/ui/LanguageStringsIdBox.java new file mode 100644 index 00000000..90558a45 --- /dev/null +++ b/src/main/java/com/quollwriter/ui/LanguageStringsIdBox.java @@ -0,0 +1,1265 @@ +package com.quollwriter.ui; + +import java.awt.Font; +import java.awt.Dimension; +import java.awt.Component; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.datatransfer.*; +import java.awt.Toolkit; + +import java.util.concurrent.*; +import java.awt.event.*; + +import java.util.*; + +import javax.swing.event.*; +import javax.swing.*; +import javax.swing.text.*; + +import com.jgoodies.forms.builder.*; +import com.jgoodies.forms.factories.*; +import com.jgoodies.forms.layout.*; + +import com.quollwriter.*; +import com.quollwriter.ui.actionHandlers.*; +import com.quollwriter.uistrings.*; +import com.quollwriter.ui.components.*; +import com.quollwriter.text.*; +import com.quollwriter.ui.forms.*; +import com.quollwriter.events.*; + +public abstract class LanguageStringsIdBox extends Box +{ + + protected LanguageStringsIdsPanel panel = null; + protected E baseValue = null; + protected E stringsValue = null; + private Box errorsWrapper = null; + private JLabel errorsLabel = null; + private JTextPane errors = null; + + public LanguageStringsIdBox (final E baseValue, + final E stringsValue, + final LanguageStringsIdsPanel panel) + { + + super (BoxLayout.Y_AXIS); + + final LanguageStringsIdBox _this = this; + + this.panel = panel; + this.baseValue = baseValue; + this.stringsValue = stringsValue; + + } + + public void init () + { + + final String fid = BaseStrings.toId (this.baseValue.getId ()); + + final LanguageStringsIdBox _this = this; + + // Needed to prevent the performance hit + this.errorsWrapper = new Box (BoxLayout.Y_AXIS); + + this.errorsLabel = UIUtils.createErrorLabel ("Errors"); + this.errorsLabel.setBorder (UIUtils.createPadding (0, 0, 0, 0)); + this.errorsLabel.setVisible (false); + this.errorsLabel.setIcon (null); + this.errorsLabel.setFocusable (false); + + final JTextField h = new JTextField (fid) + { + + @Override + public void copy () + { + + String sel = this.getSelectedText (); + + if ((sel == null) + || + (sel.equals ("")) + ) + { + + sel = fid; + + } + + if (sel.equals (fid)) + { + + sel = BaseStrings.ID_REF_START + fid + BaseStrings.ID_REF_END; + + } + + StringSelection stringSelection = new StringSelection (sel); + Clipboard clipboard = Toolkit.getDefaultToolkit ().getSystemClipboard (); + clipboard.setContents (stringSelection, null); + + } + + }; + + h.setEditable (false); + h.setAlignmentX (Component.LEFT_ALIGNMENT); + + h.setFont (h.getFont ().deriveFont ((float) UIUtils.getScaledFontSize (14)).deriveFont (Font.PLAIN)); + h.setForeground (UIUtils.getTitleColor ()); + h.setBackground (null); + h.setBackground (UIUtils.getComponentColor ()); + h.setBorder (UIUtils.createBottomLineWithPadding (0, 0, 3, 0)); + + h.addMouseListener (new MouseEventHandler () + { + + @Override + public void fillPopup (JPopupMenu m, + MouseEvent ev) + { + + JMenuItem mi = this.createMenuItem ("Find all references", + Constants.FIND_ICON_NAME, + "find"); + + mi.addActionListener (new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + _this.getEditor ().showFind (BaseStrings.toId (_this.baseValue.getId ())); + + } + + }); + + m.add (mi); + + mi = this.createMenuItem ("Report error about this Id", + Constants.BUG_ICON_NAME, + "bug"); + + mi.addActionListener (new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + _this.getEditor ().showReportProblemForId (BaseStrings.toId (_this.baseValue.getId ())); + + } + + }); + + m.add (mi); + + mi = this.createMenuItem ("Copy Id", + Constants.COPY_ICON_NAME, + "copy"); + + mi.addActionListener (new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + h.copy (); + + } + + }); + + m.add (mi); + + } + + }); + + this.add (h); + + String comment = this.baseValue.getComment (); + + String rows = (comment != null ? "top:p, 6px" : ""); + + Set items = this.getFormItems (); + + for (FormItem i : items) + { + + if (rows.length () > 0) + { + + rows += ","; + + } + + rows += "top:p,6px"; + + } + + rows += ",top:p"; + + Box b = new Box (BoxLayout.Y_AXIS); + FormLayout fl = new FormLayout ("right:60px, 5px, min(150px;p):grow", + rows); + //(comment != null ? "top:p, 6px," : "") + "top:p, 6px, top:p:grow, 6px, top:p, top:p, top:p"); + + fl.setHonorsVisibility (true); + PanelBuilder pb = new PanelBuilder (fl); + + CellConstraints cc = new CellConstraints (); + + int r = 1; + + if (comment != null) + { + + pb.addLabel ("Comment", + cc.xy (1, r)); + + String c = ""; + + int sc = this.getSCount (); + + if (sc > 0) + { + + for (int i = 0; i < sc; i++) + { + + if (c.length () > 0) + { + + c += ", "; + + } + + c += "%" + (i + 1) + "$s"; + + } + + c = "
    Requires values: " + c + " to be present in your value."; + + } + + final JLabel cl = UIUtils.createLabel (comment + c); + //cl.setFocusable (false); +/* + cl.addMouseListener (new MouseEventHandler () + { + + @Override + public void mouseEntered (MouseEvent ev) + { + + TextIterator iter = new TextIterator (this.editor.getText ()); + + final Word w = iter.getWordAt (this.editor.viewToModel (ev.getPoint ())); + + + } + + }); +*/ + pb.add (cl, + cc.xy (3, r)); + + r += 2; + + } + + for (FormItem i : items) + { + + Object l = i.getLabel (); + + if (l instanceof String) + { + + pb.addLabel (String.format ("%s", + l.toString ()), + cc.xy (1, + r)); + + } else { + + if (l instanceof JComponent) + { + + pb.add ((JComponent) l, + cc.xy (1, + r)); + + } + + } + + pb.add (i.getComponent (), + cc.xy (3, r)); + + r += 2; + + } + + //r++; + + pb.add (this.errorsLabel, + cc.xy (1, r)); + + pb.add (this.errorsWrapper, + cc.xy (3, r)); + + JPanel p = pb.getPanel (); + p.setOpaque (false); + p.setAlignmentX (Component.LEFT_ALIGNMENT); + p.setBorder (UIUtils.createPadding (5, 5, 0, 0)); + + this.add (p); + + this.setBorder (UIUtils.createPadding (0, 10, 20, 10)); + this.setAlignmentX (Component.LEFT_ALIGNMENT); + this.setAlignmentY (Component.TOP_ALIGNMENT); + + } + + private int getSCount () + { + + if (this.baseValue instanceof TextValue) + { + + return ((TextValue) this.baseValue).getSCount (); + + } + + return -1; + + } + + public void updatePreviews () + { + + this.panel.getEditor ().updatePreviews (); + + } + + public void updateSideBar (Node n) + { + + this.panel.getEditor ().updateSideBar (this.panel.getParentNode ()); + + } + + public AbstractLanguageStringsEditor getEditor () + { + + return this.panel.getEditor (); + + } + + public abstract Component getFocusableComponent (); + + public abstract T getUserValue (); + + public abstract Set getFormItems (); + + public abstract void saveValue () + throws GeneralException; + +/* + public void saveValue () + throws GeneralException + { + + String uv = this.getUserValue (); + + if (uv != null) + { + + if (this.stringsValue != null) + { + + this.stringsValue.setRawText (uv); + + } else { + + this.stringsValue = this.editor.userStrings.insertTextValue (this.baseValue.getId ()); + + //this.stringsValue.setSCount (this.baseValue.getSCount ()); + this.stringsValue.setRawText (uv); + + } + + } else { + + this.editor.userStrings.removeNode (this.baseValue.getId ()); + + } + + } +*/ +/* + public Id getIdAtOffset (int offset) + { + + return BaseStrings.getId (this.userValue.getEditor ().getText (), + offset); + + } +*/ +/* + public Id getIdAtCaret () + { + + return this.getIdAtOffset (this.userValue.getEditor ().getCaretPosition ()); + + } +*/ + public String getId () + { + + return BaseStrings.toId (this.baseValue.getId ()); + + } + + public boolean hasUserValue () + { + + return this.getUserValue () != null; + + } + +/* + public String getUserValue () + { + + StringWithMarkup sm = this.userValue.getTextWithMarkup (); + + if (sm != null) + { + + if (!sm.hasText ()) + { + + return null; + + } + + return sm.getMarkedUpText (); + + } + + return null; + + } +*/ +/* + public void useEnglishValue () + { + + this.userValue.updateText (this.baseValue.getRawText ()); + this.showPreview (); + this.validate (); + this.repaint (); + + } +*/ + + public abstract boolean hasErrors (); +/* + public boolean hasErrors () + { + + String s = this.getUserValue (); + + if (s == null) + { + + return false; + + } + + return BaseStrings.getErrors (s, + BaseStrings.toId (this.baseValue.getId ()), + this.baseValue.getSCount (), + this.editor).size () > 0; + + + } +*/ + + public abstract boolean showErrors (boolean requireUserValue); + + public void hideErrors () + { + + this.errorsLabel.setVisible (false); + this.errorsWrapper.setVisible (false); + + } + + public boolean showErrors (Set errs) + { + + this.hideErrors (); + + if ((errs == null) + || + (errs.size () == 0) + ) + { + + return false; + + } + + if (this.errors == null) + { + + this.errors = UIUtils.createHelpTextPane ("", + this.getEditor ()); + this.errors.setBorder (UIUtils.createPadding (0, 0, 0, 0)); + this.errors.setFocusable (false); + this.errorsWrapper.add (this.errors); + + } + + StringBuilder b = new StringBuilder (); + + for (String e : errs) + { + + if (b.length () > 0) + { + + b.append ("
    "); + + } + + b.append ("* " + e); + + } + + this.errors.setText ("" + b.toString () + ""); + this.errorsLabel.setVisible (true); + this.errorsWrapper.setVisible (true); + + this.getEditor ().updateSideBar (this.baseValue); + + return true; + + } + + public abstract void showPreview (); + /* + public void showPreview () + { + + if (this.showErrors (false)) + { + + return; + + } + + String s = this.getUserValue (); + + if (s == null) + { + + if (this.preview != null) + { + + this.preview.setText (""); + + } + + this.previewWrapper.setVisible (false); + this.previewLabel.setVisible (false); + + this.editor.updateSideBar (this.baseValue); + + return; + + } + + if (this.preview == null) + { + + this.preview = UIUtils.createHelpTextPane ("", + this.editor); + this.preview.setBorder (UIUtils.createPadding (6, 0, 0, 0)); + this.preview.setFocusable (false); + + this.previewWrapper.add (this.preview); + + } + + String t = this.editor.getPreviewText (s); + + this.previewLabel.setVisible (true); + this.preview.setText (t); + this.previewWrapper.setVisible (true); + + this.editor.updateSideBar (this.baseValue); + + this.validate (); + this.repaint (); + + } +*/ +/* + private void fillMatch () + { + + QTextEditor editor = this.userValue.getEditor (); + + int c = editor.getCaretPosition (); + + Id id = BaseStrings.getId (editor.getText (), + c); + + if (id == null) + { + + return; + + } + + String m = this.selections.getSelectedValue (); + + //m = id.getNewFullId (m); + + Id.Part part = id.getPart (c); + + if (part != null) + { + + editor.replaceText (part.start, part.end, m); + editor.setCaretPosition (part.start + m.length ()); + + } else { + + // Is the previous character a . if so append. + if ((editor.getText ().substring (c - 1, c).equals (".")) + || + (c == id.getEnd ()) + ) + { + + editor.replaceText (c, c, m); + editor.setCaretPosition (c + m.length ()); + + } else { + + part = id.getLastPart (); + + editor.replaceText (part.start, part.start + part.end, m); + editor.setCaretPosition (part.start + m.length ()); + + } + + } + + c = editor.getCaretPosition (); + + id = this.getIdAtCaret (); + + // We may be inserting into the middle of an id, check to see if it's valid. + + // Check to see if the id maps to a string. + if (this.editor.baseStrings.getString (id.getId ()) != null) + { + + if (id.isPartial ()) + { + + editor.replaceText (id.getEnd (), id.getEnd (), "}"); + editor.setCaretPosition (c + 1); + + } + + this.hideSelector (); + + return; + + } + + // Check to see if there are more matches further down the tree. + String nid = id.getId () + "."; + + Set matches = this.editor.baseStrings.getIdMatches (nid); + + if (matches.size () > 0) + { + + c = editor.getCaretPosition (); + + editor.replaceText (c, c, "."); + editor.setCaretPosition (c + 1); + + try + { + + this.showSelectionPopup (matches, + editor.modelToView (id.getPart (c).start).getLocation ()); + + } catch (Exception e) { + + e.printStackTrace (); + + } + + return; + + } else { + + c = editor.getCaretPosition (); + + editor.replaceText (c, c, "}"); + editor.setCaretPosition (c + 1); + + this.hideSelector (); + + return; + + } + + } +*/ +/* + private String updateSelectedMatch (int incr) + { + + int i = this.selections.getSelectedIndex (); + + i += incr; + + int s = this.selections.getModel ().getSize (); + + if (i < 0) + { + + i = s + i; + + } + + if (i > s - 1) + { + + i -= s; + + } + + this.selections.setSelectedIndex (i); + + return this.selections.getSelectedValue (); + + } +*/ +/* + public boolean isSelectorVisible () + { + + if (this.selector != null) + { + + return this.selector.isVisible (); + + } + + return false; + + } +*/ +/* + public void hideSelector () + { + + if (this.selector != null) + { + + this.selector.setVisible (false); + + } + + this.userValue.getEditor ().setFocusTraversalKeysEnabled (true); + + } +*/ +/* + public void showSelectionPopup (Set matches, + Point point) + { + + if (this.selector == null) + { + + this.selector = new Box (BoxLayout.Y_AXIS); + + this.selector.setOpaque (true); + this.selector.setBackground (UIUtils.getComponentColor ()); + this.selector.setBorder (UIUtils.createLineBorder ()); + + } + + if ((matches == null) + || + (matches.size () == 0) + ) + { + + this.hideSelector (); + + return; + + } + + this.userValue.getEditor ().setFocusTraversalKeysEnabled (false); + + this.selector.removeAll (); + + DefaultListModel m = new DefaultListModel<> (); + + for (String o : matches) + { + + m.addElement (o); + + } + + this.selections = new JList (); + final JList l = this.selections; + l.setModel (m); + l.setLayoutOrientation (JList.VERTICAL); + l.setVisibleRowCount (0); + l.setOpaque (true); + l.setBackground (UIUtils.getComponentColor ()); + l.setMaximumSize (new Dimension (Short.MAX_VALUE, + Short.MAX_VALUE)); + UIUtils.setAsButton (l); + + l.setCellRenderer (new DefaultListCellRenderer () + { + + public Component getListCellRendererComponent (JList list, + Object value, + int index, + boolean isSelected, + boolean cellHasFocus) + { + + String obj = (String) value; + + JLabel l = (JLabel) super.getListCellRendererComponent (list, + value, + index, + isSelected, + cellHasFocus); + + l.setText (obj);//.getName ()); + + l.setFont (l.getFont ().deriveFont (UIUtils.getScaledFontSize (10)).deriveFont (Font.PLAIN)); + l.setBorder (UIUtils.createBottomLineWithPadding (5, 5, 5, 5)); + l.setPreferredSize (new Dimension (l.getPreferredSize ().width, 29)); + + return l; + + } + + }); + + l.setSelectedIndex (0); + + int rowHeight = 30; + + l.setAlignmentX (JComponent.LEFT_ALIGNMENT); + + JScrollPane sp = new JScrollPane (l); + + sp.setHorizontalScrollBarPolicy (ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); + sp.getVerticalScrollBar ().setUnitIncrement (rowHeight); + sp.setAlignmentX (JComponent.LEFT_ALIGNMENT); + sp.setOpaque (false); + sp.setBorder (null); + + this.selector.add (sp); + + l.addListSelectionListener (new ListSelectionListener () + { + + @Override + public void valueChanged (ListSelectionEvent ev) + { + + } + + }); + + this.selector.setPreferredSize (new Dimension (300, + rowHeight * (matches.size () > 10 ? 10 : matches.size ()))); + + this.editor.showPopupAt (this.selector, + SwingUtilities.convertPoint (this.userValue, + point, + this.editor), + false); + + } +*/ + @Override + public Dimension getMaximumSize () + { + + return new Dimension (Short.MAX_VALUE, + this.getPreferredSize ().height); + + } +/* + public class Id + { + + private int _start = -1; + private String fullId = null; + private boolean hasClosingBrace = false; + private java.util.List parts = new ArrayList<> (); + public boolean hasErrors = false; + + public Id (String text, + int offset) + { + + if (text.length () < 3) + { + + return; + + } + + String idstart = LanguageStrings.ID_REF_START; + + int ind = text.lastIndexOf (idstart, offset); + + if (ind > -1) + { + + ind += idstart.length (); + this._start = ind; + + int idendind = text.indexOf (LanguageStrings.ID_REF_END, ind); + + if (idendind > -1) + { + + if (idendind < offset) + { + + return; + + } + + // We have an end, see if it's on the same line. + int leind = text.indexOf ("\n", ind); + + if (leind < 0) + { + + leind = text.length (); + + } + + if (idendind < leind) + { + + this.hasClosingBrace = true; + this.fullId = text.substring (ind, leind - 1); + + } + + } else { +System.out.println ("ELSE"); + StringBuilder b = new StringBuilder (); + + for (int i = ind; i < text.length (); i++) + { + + char c = text.charAt (i); + + if (Character.isWhitespace (c)) + { + + break; + + } + + b.append (c); + + } + + this.fullId = b.toString (); + + } +System.out.println ("ID: " + this.fullId); + if (this.fullId.equals ("")) + { + + this.fullId = null; + + } + + int start = ind; + + java.util.List parts = Utils.splitString (this.fullId, + "."); + + int cind = start; + + Part prevp = null; + + for (int i = 0; i < parts.size (); i++) + { + + if (i > 0) + { + + cind++; + + } + + String ps = parts.get (i); + + if (ps.trim ().length () != ps.length ()) + { + + this.hasErrors = true; + + } + + Part p = new Part (this, + cind, + ps, + prevp); + + prevp = p; + cind += ps.length (); + + this.parts.add (p); + + } + + } + + } + + public int getEnd () + { + + if (this.parts.size () == 0) + { + + return this._start; + + } + + return this.parts.get (this.parts.size () - 1).end; + + } + + public Part getPart (int offset) + { + + for (int i = 0; i < this.parts.size (); i++) + { + + Part p = this.parts.get (i); + + if ((offset >= p.start) + && + (offset <= p.end) + ) + { + + return p; + + } + + } + + return null; + + } + + public String getFullId () + { + + return this.fullId; + + } + + public boolean isIdValid (LanguageStrings baseStrings) + { + + if (this.fullId == null) + { + + return false; + + } + + return baseStrings.isIdValid (this.fullId); + + } + + public boolean hasErrors () + { + + return this.hasErrors; + + } + + public String getNewFullId (String suffix) + { + + if (this.fullId.endsWith (".")) + { + + return this.fullId + suffix; + + } + + String pref = this.getIdPrefix (); + + if (pref == null) + { + + return suffix; + + } + + return pref + "." + suffix; + + } + + public String getIdPrefix () + { + + StringBuilder b = new StringBuilder (); + + for (int i = 0; i < this.parts.size () - 1; i++) + { + + if (i > 0) + { + + b.append ("."); + + } + + b.append (this.parts.get (i).part); + + } + + if (b.length () == 0) + { + + return null; + + } + + return b.toString (); + + } + + public Part getLastPart () + { + + if (this.parts.size () == 0) + { + + return null; + + } + + return this.parts.get (this.parts.size () - 1); + + } + + public Set getPartMatches (int offset, + LanguageStrings baseStrings) + { + + Part p = this.getPart (offset); + + if (p != null) + { + + return baseStrings.getIdMatches (p.getFullId ()); + + } + + return this.getMatches (baseStrings); + + } + + public Set getMatches (LanguageStrings baseStrings) + { + + return baseStrings.getIdMatches (this.fullId); + + } + + public class Part + { + + public int start = -1; + public int end = -1; + public String part = null; + public Id parent = null; + public Part previous = null; + + public Part (Id parent, + int start, + String part, + Part prev) + { + + this.start = start; + this.end = this.start + part.length (); + this.parent = parent; + this.part = part; + this.previous = prev; + + } + + public String getFullId () + { + + StringBuilder b = new StringBuilder (this.part); + + Part prev = this.previous; + + while (prev != null) + { + + b.insert (0, prev.part + "."); + prev = prev.previous; + + } + + return b.toString (); + + } + + } + + } +*/ + +} diff --git a/src/main/java/com/quollwriter/ui/LanguageStringsIdsPanel.java b/src/main/java/com/quollwriter/ui/LanguageStringsIdsPanel.java new file mode 100644 index 00000000..757a8b4d --- /dev/null +++ b/src/main/java/com/quollwriter/ui/LanguageStringsIdsPanel.java @@ -0,0 +1,794 @@ +package com.quollwriter.ui; + +import java.util.*; + +import java.awt.Color; +import java.awt.Component; +import java.awt.Container; + +import java.awt.event.*; + +import java.beans.*; + +import javax.swing.*; +import javax.swing.event.*; +import javax.swing.border.*; + +import com.quollwriter.*; +import com.quollwriter.events.*; +import com.quollwriter.uistrings.*; +import com.quollwriter.ui.panels.*; +import com.quollwriter.ui.components.*; + +public class LanguageStringsIdsPanel extends BasicQuollPanel +{ + + public final static String LIMIT_ERROR_ACTION_NAME = "view-limit-error"; + public static final String LIMIT_NO_VALUE_ACTION_NAME = "view-limit-no-value"; + public static final String NEXT_ACTION_NAME = "next"; + + private String parentId = null; + private Set vals = null; + private Node parent = null; + private Set values = null; + private Box content = null; + private AbstractLanguageStringsEditor editor = null; + private String limitType = ""; + + public LanguageStringsIdsPanel (AbstractLanguageStringsEditor ed, + Node parent, + Set values) + { + + super (ed, + parent.getNodeId (), + null); + + final LanguageStringsIdsPanel _this = this; + + this.editor = ed; + + this.parent = parent; + this.values = values; + + //this.node = this.editor.baseStrings.getNode (id); + + String title = (this.parent.getTitle () != null ? this.parent.getTitle () : this.parent.getNodeId ()); + + // Replace the kludge to limit the length of the title. + title = Utils.replaceString (title, + "
      ", + " "); + + this.setTitle (String.format ("%s (%s)", + title, + Environment.formatNumber (this.values.size ()))); + + this.content = new ScrollableBox (BoxLayout.Y_AXIS); + this.content.setAlignmentY (Component.TOP_ALIGNMENT); + this.content.setAlignmentX (Component.LEFT_ALIGNMENT); + + this.content.setFocusTraversalPolicy (new java.awt.FocusTraversalPolicy () + { + + @Override + public Component getDefaultComponent (Container cont) + { + + return this.getFirstComponent (cont); + + } + + @Override + public Component getFirstComponent (Container cont) + { + + for (int i = 0; i < cont.getComponentCount (); i++) + { + + Component c = cont.getComponent (i); + + if (c instanceof LanguageStringsIdBox) + { + + return ((LanguageStringsIdBox) c).getFocusableComponent (); + + } + + } + + return null; + + } + + @Override + public Component getLastComponent (Container cont) + { + + LanguageStringsIdBox b = null; + + for (int i = cont.getComponentCount () - 1; i > -1; i--) + { + + Component c = cont.getComponent (i); + + if (c instanceof LanguageStringsIdBox) + { + + b = (LanguageStringsIdBox) c; + + break; + + } + + } + + if (b != null) + { + + return b.getFocusableComponent (); + + } + + return null; + + } + + @Override + public Component getComponentAfter (Container cont, + Component comp) + { + + Container parent = comp.getParent (); + + while (parent != null) + { + + if (parent instanceof LanguageStringsIdBox) + { + + if (comp instanceof JTextField) + { + + JTextField f = (JTextField) comp; + + if (!f.isEditable ()) + { + + LanguageStringsIdBox b = (LanguageStringsIdBox) parent; + + return b.getFocusableComponent (); + + } + + } + + LanguageStringsIdBox b = (LanguageStringsIdBox) parent; + + int i = 0; + + for (; i < cont.getComponentCount (); i++) + { + + if (b == cont.getComponent (i)) + { + + i++; + + break; + + } + + } + + if (i < cont.getComponentCount ()) + { + + Component x = cont.getComponent (i); + + if (x instanceof LanguageStringsIdBox) + { + + return ((LanguageStringsIdBox) x).getFocusableComponent (); + + } + + } + + break; + + } + + parent = parent.getParent (); + + } + + return null; + + } + + @Override + public Component getComponentBefore (Container cont, + Component comp) + { + + Container parent = comp.getParent (); + + while (parent != null) + { + + if (parent instanceof LanguageStringsIdBox) + { + + LanguageStringsIdBox b = (LanguageStringsIdBox) parent; + + int i = 0; + + for (; i < cont.getComponentCount (); i++) + { + + if (b == cont.getComponent (i)) + { + + i--; + + break; + + } + + } + + if (i > -1) + { + + Component x = cont.getComponent (i); + + if (x instanceof LanguageStringsIdBox) + { + + return ((LanguageStringsIdBox) x).getFocusableComponent (); + + } + + } + + break; + + } + + parent = parent.getParent (); + + } + + return null; + + } + + }); + + this.content.setFocusTraversalPolicyProvider (true); + + this.actions = this.content.getActionMap (); + + this.actions.put (LIMIT_ERROR_ACTION_NAME, + new ActionAdapter () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + _this.showOnlyErrors (); + + } + + }); + + this.actions.put (LIMIT_NO_VALUE_ACTION_NAME, + new ActionAdapter () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + _this.showOnlyNoValue (); + + } + + }); + + this.actions.put (NEXT_ACTION_NAME, + new ActionAdapter () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + + } + + }); + + InputMap im = this.content.getInputMap (JComponent.WHEN_IN_FOCUSED_WINDOW); + + im.put (KeyStroke.getKeyStroke (KeyEvent.VK_E, + InputEvent.CTRL_MASK), + LIMIT_ERROR_ACTION_NAME); + + im.put (KeyStroke.getKeyStroke (KeyEvent.VK_N, + InputEvent.CTRL_MASK), + LIMIT_NO_VALUE_ACTION_NAME); + + im.put (KeyStroke.getKeyStroke (KeyEvent.VK_KP_LEFT, + InputEvent.CTRL_MASK), + NEXT_ACTION_NAME); + + im.put (KeyStroke.getKeyStroke (KeyEvent.VK_LEFT, + InputEvent.CTRL_MASK), + NEXT_ACTION_NAME); + + } + + public Node getParentNode () + { + + return this.parent; + + } + + public void showOnlyErrors () + { + + boolean show = true; + + if (this.limitType.equals ("errors")) + { + + show = false; + this.limitType = ""; + + } else { + + this.limitType = "errors"; + + } + + for (int i = 0; i < this.content.getComponentCount (); i++) + { + + Component c = this.content.getComponent (i); + + if (c instanceof LanguageStringsIdBox) + { + + c.setVisible (true); + + if (show) + { + + LanguageStringsIdBox b = (LanguageStringsIdBox) c; + + if (!b.hasErrors ()) + { + + c.setVisible (false); + + } + + } + + } + + } + + this.getToolBarButton (LIMIT_ERROR_ACTION_NAME).setSelected (show); + this.getToolBarButton (LIMIT_NO_VALUE_ACTION_NAME).setSelected (false); + + this.validate (); + this.repaint (); + + } + + public void showOnlyNoValue () + { + + boolean show = true; + + if (this.limitType.equals ("novalue")) + { + + show = false; + this.limitType = ""; + + } else { + + this.limitType = "novalue"; + + } + + for (int i = 0; i < this.content.getComponentCount (); i++) + { + + Component c = this.content.getComponent (i); + + if (c instanceof LanguageStringsIdBox) + { + + c.setVisible (true); + + if (show) + { + + LanguageStringsIdBox b = (LanguageStringsIdBox) c; + + if (b.hasUserValue ()) + { + + c.setVisible (false); + + } + + } + + } + + } + + this.getToolBarButton (LIMIT_ERROR_ACTION_NAME).setSelected (false); + this.getToolBarButton (LIMIT_NO_VALUE_ACTION_NAME).setSelected (show); + + this.validate (); + this.repaint (); + + } + + @Override + public String getPanelId () + { + + return BaseStrings.toId (this.parent.getId ()); + + } + + @Override + public boolean isWrapContentInScrollPane () + { + + return true; + + } + + public void scrollToNode (String id) + { + + for (int i = 0; i < this.content.getComponentCount (); i++) + { + + Component c = this.content.getComponent (i); + + if (c instanceof LanguageStringsIdBox) + { + + final LanguageStringsIdBox box = (LanguageStringsIdBox) c; + + if (BaseStrings.toId (box.baseValue.getId ()).equals (id)) + { + + final Border origBorder = box.getBorder (); + + final Color col = UIUtils.getBorderHighlightColor (); + + final int r = col.getRed (); + final int g = col.getGreen (); + final int b = col.getBlue (); + + PropertyChangeListener l = new PropertyChangeListener () + { + + @Override + public void propertyChange (PropertyChangeEvent ev) + { + + Color c = new Color (r, + g, + b, + ((Number) ev.getNewValue ()).intValue ()); + + box.setBorder (new CompoundBorder (new MatteBorder (3, 3, 3, 3, c), + UIUtils.createPadding (3, 3, 3, 3))); + + } + + }; + + final javax.swing.Timer cycle = UIUtils.createCyclicAnimator (l, + l, + 60, + 1500, + 0, + 255, + 2, + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + box.setBorder (origBorder); + + } + + }); + + UIUtils.doLater (new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + UIUtils.scrollIntoView (box); + + cycle.start (); + + } + + }); + + } + + } + + } + + } + + public void updatePreviews () + { + + for (int i = 0; i < this.content.getComponentCount (); i++) + { + + Component c = this.content.getComponent (i); + + if (c instanceof LanguageStringsTextIdBox) + { + + LanguageStringsTextIdBox b = (LanguageStringsTextIdBox) c; + + b.showPreview (); + + } + + } + + } + + @Override + public JComponent getContent () + { + + final LanguageStringsIdsPanel _this = this; + + this.buildForm (this.parent.getNodeId ()); + + this.content.add (Box.createVerticalGlue ()); + + this.updatePreviews (); + + return this.content; + + } + + public void saveValues () + throws GeneralException + { + + for (int i = 0; i < this.content.getComponentCount (); i++) + { + + Component c = this.content.getComponent (i); + + if (c instanceof LanguageStringsTextIdBox) + { + + LanguageStringsTextIdBox b = (LanguageStringsTextIdBox) c; + + b.saveValue (); + + } + + if (c instanceof LanguageStringsImageIdBox) + { + + LanguageStringsImageIdBox b = (LanguageStringsImageIdBox) c; + + b.saveValue (); + + } + + } + + } + + public String getIdValue (String id) + { + + for (int i = 0; i < this.content.getComponentCount (); i++) + { + + Component c = this.content.getComponent (i); + + if (c instanceof LanguageStringsTextIdBox) + { + + LanguageStringsTextIdBox b = (LanguageStringsTextIdBox) c; + + if (b.getId ().equals (id)) + { + + return b.getUserValue (); + + } + + } + + } + + return null; + + } + + public int getErrorCount () + { + + int c = 0; + + for (int i = 0; i < this.content.getComponentCount (); i++) + { + + Component co = this.content.getComponent (i); + + if (co instanceof LanguageStringsTextIdBox) + { + + LanguageStringsTextIdBox b = (LanguageStringsTextIdBox) co; + + if (b.hasErrors ()) + { + + c++; + + } + + } + + } + + return c; + + } + + public int getUserValueCount () + { + + int c = 0; + + for (int i = 0; i < this.content.getComponentCount (); i++) + { + + Component co = this.content.getComponent (i); + + if (co instanceof LanguageStringsIdBox) + { + + LanguageStringsIdBox b = (LanguageStringsIdBox) co; + + if (b.hasUserValue ()) + { + + c++; + + } + + } + + } + + return c; + + } + + private void createComment (String comment) + { + + JComponent c = UIUtils.createHelpTextPane (comment, + this.getViewer ()); + c.setAlignmentX (LEFT_ALIGNMENT); + c.setBorder (UIUtils.createPadding (0, 15, 5, 5)); + + this.content.add (c); + + } + + private void buildForm (String idPrefix) + { + + // Check for the section comment. + if (this.parent.getComment () != null) + { + + this.createComment (this.parent.getComment ()); + + } + + for (Value v : this.values) + { + + if (v instanceof ImageValue) + { + + LanguageStringsImageIdBox b = new LanguageStringsImageIdBox ((ImageValue) v, + (this.editor.userStrings.containsId (v.getId ()) ? this.editor.userStrings.getImageValue (v.getId ()) : null), + this); + + b.init (); + + this.content.add (b); + + } + + if (v instanceof TextValue) + { + + LanguageStringsTextIdBox b = new LanguageStringsTextIdBox ((TextValue) v, + (this.editor.userStrings.containsId (v.getId ()) ? this.editor.userStrings.getTextValue (v.getId ()) : null), + this); + + b.init (); + + this.content.add (b); // scount + + } + + } + + } + + public AbstractLanguageStringsEditor getEditor () + { + + return this.editor; + + } + + @Override + public void fillToolBar (JToolBar toolBar, + boolean fullScreen) + { + + toolBar.add (this.createToolbarButton (Constants.ERROR_ICON_NAME, + "Click to limit the view to Ids with one or more errors", + LIMIT_ERROR_ACTION_NAME)); + + toolBar.add (this.createToolbarButton ("no-value", //Constants.CLEAR_ICON_NAME, + "Click to limit the view to Ids with no value", + LIMIT_NO_VALUE_ACTION_NAME)); +/* + toolBar.add (this.createToolbarButton (Constants.NEXT_ICON_NAME, + "Go to the next section", + NEXT_ACTION_NAME)); +*/ + } + + @Override + public void fillPopupMenu (MouseEvent ev, + JPopupMenu popup) + { + + } + +} diff --git a/src/main/java/com/quollwriter/ui/LanguageStringsImageIdBox.java b/src/main/java/com/quollwriter/ui/LanguageStringsImageIdBox.java new file mode 100644 index 00000000..526c1670 --- /dev/null +++ b/src/main/java/com/quollwriter/ui/LanguageStringsImageIdBox.java @@ -0,0 +1,233 @@ +package com.quollwriter.ui; + +import java.awt.Font; +import java.awt.Dimension; +import java.awt.Component; +import java.awt.Point; +import java.awt.Rectangle; + +import java.util.concurrent.*; +import java.awt.event.*; + +import java.io.*; +import java.util.*; + +import javax.swing.event.*; +import javax.swing.*; +import javax.swing.text.*; + +import com.jgoodies.forms.builder.*; +import com.jgoodies.forms.factories.*; +import com.jgoodies.forms.layout.*; + +import com.quollwriter.*; +import com.quollwriter.ui.actionHandlers.*; +import com.quollwriter.uistrings.*; +import com.quollwriter.ui.components.*; +import com.quollwriter.text.*; +import com.quollwriter.ui.forms.*; + +public class LanguageStringsImageIdBox extends LanguageStringsIdBox +{ + + //private AbstractLanguageStringsEditor editor = null; + private ImageSelector userValue = null; + //private ImageValue baseValue = null; + //private ImageValue stringsValue = null; + + //private JTextPane errors = null; + //private Box errorsWrapper = null; + //private JLabel errorsLabel = null; + + public LanguageStringsImageIdBox (final ImageValue baseValue, + final ImageValue stringsValue, + final LanguageStringsIdsPanel panel) + { + + super (baseValue, + stringsValue, + panel); + + } + + public Component getFocusableComponent () + { + + return this.userValue; + + } + + public Set getFormItems () + { + + final LanguageStringsImageIdBox _this = this; + + Set items = new LinkedHashSet<> (); + + AnyFormItem view = new AnyFormItem (null, + UIUtils.createClickableLabel ("View English Image Online", + Environment.getIcon (Constants.VIEW_ICON_NAME, + Constants.ICON_MENU), + Environment.getQuollWriterWebsite () + this.baseValue.getUrl ())); + + items.add (view); +/* + this.userValue = new ImageSelector ((this.stringsValue != null ? this.stringsValue.getImageFile () : null), + UIUtils.imageFileFilter, + new Dimension (150, + 150)); + this.userValue.setAlignmentX (Component.LEFT_ALIGNMENT); + this.userValue.setBorder (UIUtils.createLineBorder ()); +*/ + this.userValue.addChangeListener (new ChangeListener () + { + + @Override + public void stateChanged (ChangeEvent ev) + { + + _this.updateSideBar (_this.baseValue); + + } + + }); + + Box _b = new Box (BoxLayout.X_AXIS); + _b.add (this.userValue); + _b.add (Box.createHorizontalGlue ()); + + items.add (new AnyFormItem ("Your Image", + _b)); + + return items; + + } + + public void saveValue () + throws GeneralException + { + + File uv = this.getUserValue (); + + if (uv != null) + { + + if (this.stringsValue == null) + { + + this.stringsValue = this.getEditor ().userStrings.insertImageValue (this.baseValue.getId ()); + + } + + this.stringsValue.setImageFile (uv.toPath ()); + + } else { + + this.getEditor ().userStrings.removeNode (this.baseValue.getId ()); + + } + + } + + @Override + public File getUserValue () + { + + return this.userValue.getFile (); + + } + + @Override + public boolean hasErrors () + { + + File s = this.getUserValue (); + + if (s == null) + { + + return false; + + } + + return false; + + + } + + public boolean showErrors (boolean requireUserValue) + { + + this.hideErrors (); + + File s = this.getUserValue (); + + if ((s == null) + && + (!requireUserValue) + ) + { + + return false; + + } + + Set errs = null; + + if (s == null) + { + + errs = new LinkedHashSet<> (); + + errs.add ("Cannot show a preview, no value provided."); + + } else { + + } + + Node root = this.baseValue.getRoot (); + + this.updateSideBar (this.baseValue); + + return false; + + } + + public void showPreview () + { + + if (this.showErrors (false)) + { + + return; + + } + + File s = this.getUserValue (); + + if (s == null) + { + + this.updateSideBar (this.baseValue); + + return; + + } + + this.updateSideBar (this.baseValue); + + this.validate (); + this.repaint (); + + } + + @Override + public Dimension getMaximumSize () + { + + return new Dimension (Short.MAX_VALUE, + this.getPreferredSize ().height); + + } + +} diff --git a/src/main/java/com/quollwriter/ui/LanguageStringsTextIdBox.java b/src/main/java/com/quollwriter/ui/LanguageStringsTextIdBox.java new file mode 100644 index 00000000..379501d7 --- /dev/null +++ b/src/main/java/com/quollwriter/ui/LanguageStringsTextIdBox.java @@ -0,0 +1,1304 @@ +package com.quollwriter.ui; + +import java.awt.Font; +import java.awt.Dimension; +import java.awt.Component; +import java.awt.Point; +import java.awt.Rectangle; + +import java.util.concurrent.*; +import java.awt.event.*; + +import java.util.*; + +import javax.swing.event.*; +import javax.swing.*; +import javax.swing.text.*; + +import com.jgoodies.forms.builder.*; +import com.jgoodies.forms.factories.*; +import com.jgoodies.forms.layout.*; + +import com.quollwriter.*; +import com.quollwriter.ui.actionHandlers.*; +import com.quollwriter.uistrings.*; +import com.quollwriter.ui.components.*; +import com.quollwriter.text.*; +import com.quollwriter.ui.forms.*; + +public class LanguageStringsTextIdBox extends LanguageStringsIdBox +{ + + private TextArea userValue = null; + private Box selector = null; + private JList selections = null; + + private JTextPane preview = null; + private Box previewWrapper = null; + private JLabel previewLabel = null; + + public LanguageStringsTextIdBox (final TextValue baseValue, + final TextValue stringsValue, + final LanguageStringsIdsPanel panel) + { + + super (baseValue, + stringsValue, + panel); + + } + + public Component getFocusableComponent () + { + + return this.userValue.getEditor (); + + } + + public Set getFormItems () + { + + final LanguageStringsTextIdBox _this = this; + + // Needed to prevent the performance hit + this.previewWrapper = new Box (BoxLayout.Y_AXIS); + + this.previewLabel = UIUtils.createInformationLabel ("Preview"); + this.previewLabel.setBorder (UIUtils.createPadding (0, 0, 0, 0)); + this.previewLabel.setVisible (false); + + Set items = new LinkedHashSet<> (); + + JTextArea l = new JTextArea (this.baseValue.getRawText ()); + l.setLineWrap (true); + l.setWrapStyleWord (true); + l.setEditable (false); + l.setBackground (UIUtils.getComponentColor ()); + l.setAlignmentX (Component.LEFT_ALIGNMENT); + //l.setFocusable (false); + + AnyFormItem enValue = new AnyFormItem ("English", + l); + + items.add (enValue); + + this.userValue = new TextArea (null, + 3, + -1, + false) + { + + @Override + public void onCut () + { + + _this.updatePreviews (); +_this.showPreview (); + } + + @Override + public void onPaste () + { + + _this.updatePreviews (); +_this.showPreview (); + } + + @Override + public void fillPopupMenuForExtraItems (MouseEvent ev, + JPopupMenu popup, + boolean compress) + { + + if (compress) + { + + java.util.List buts = new java.util.ArrayList<> (); + + final Id id = _this.getIdAtPoint (ev.getPoint ()); + + if (id != null) + { + + buts.add (UIUtils.createButton (Constants.VIEW_ICON_NAME, + Constants.ICON_MENU, + "Go to Id definition", + new ActionListener () + { + + public void actionPerformed (ActionEvent ev) + { + + _this.getEditor ().showId (id.getId ()); + + } + + })); + + } + + + buts.add (UIUtils.createButton (Constants.COPY_ICON_NAME, + Constants.ICON_MENU, + "Use the English value", + new ActionListener () + { + + public void actionPerformed (ActionEvent ev) + { + + _this.useEnglishValue (); + + } + + })); + + popup.add (UIUtils.createPopupMenuButtonBar ("Manage", + //"Edit", + popup, + buts)); + + } else { + + JMenuItem mi = null; + + final Id id = _this.getIdAtPoint (ev.getPoint ()); + + if (id != null) + { + + popup.add (UIUtils.createMenuItem ("Go to Id definition", + Constants.VIEW_ICON_NAME, + new ActionListener () + { + + public void actionPerformed (ActionEvent ev) + { + + _this.getEditor ().showId (id.getId ()); + + } + + })); + + } + + mi = UIUtils.createMenuItem ("Use the English value", + Constants.COPY_ICON_NAME, + new ActionListener () + { + + public void actionPerformed (ActionEvent ev) + { + + _this.useEnglishValue (); + + } + + }); + popup.add (mi); + + } + + } + + }; + + this.userValue.addMouseMotionListener (new MouseAdapter () + { + + @Override + public void mouseMoved (MouseEvent ev) + { + + _this.userValue.setToolTipText (null); + + Id id = _this.getIdAtPoint (ev.getPoint ()); + + if (id != null) + { + + _this.userValue.setToolTipText (_this.getEditor ().getString (id.getId ())); + + } + + } + + }); + + this.userValue.getEditor ().getDocument ().addDocumentListener (new DocumentListener () + { + + private ScheduledFuture task = null; + + private void update () + { + + if (this.task != null) + { + + this.task.cancel (false); + + } + + this.task = _this.getEditor ().schedule (new Runnable () + { + + @Override + public void run () + { + + UIUtils.doLater (new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + _this.showPreview (); + + } + + }); + + } + + }, + 750, + 0); + + } + + @Override + public void insertUpdate (DocumentEvent ev) + { + + _this.updatePreviews (); +_this.showPreview (); + } + + @Override + public void changedUpdate (DocumentEvent ev) + { + + _this.updatePreviews (); +_this.showPreview (); + } + + @Override + public void removeUpdate (DocumentEvent ev) + { + + _this.updatePreviews (); +_this.showPreview (); + } + + }); + + this.userValue.addKeyListener (new KeyAdapter () + { + + private ScheduledFuture task = null; + + private void update () + { + + if (this.task != null) + { + + this.task.cancel (false); + + } + + this.task = _this.getEditor ().schedule (new Runnable () + { + + @Override + public void run () + { + + UIUtils.doLater (new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + _this.updatePreviews (); + + //_this.showPreview (); + + } + + }); + + } + + }, + 750, + 0); + + } + + @Override + public void keyPressed (KeyEvent ev) + { + + _this.updatePreviews (); +_this.showPreview (); + } + + @Override + public void keyReleased (KeyEvent ev) + { + + _this.updatePreviews (); +_this.showPreview (); + } + + }); + + //this.userValue.setBorder (UIUtils.createLineBorder ()); + + try + { + + this.userValue.setDictionaryProvider (new UserDictionaryProvider (UserProperties.get (Constants.SPELL_CHECK_LANGUAGE_PROPERTY_NAME)) + { + + @Override + public com.quollwriter.ui.fx.SpellChecker getSpellChecker () + { + + final com.quollwriter.ui.fx.SpellChecker sp = super.getSpellChecker (); + + return new com.quollwriter.ui.fx.SpellChecker () + { + + @Override + public boolean isCorrect (Word word) + { + + int offset = word.getAllTextStartOffset (); + + Id id = _this.getIdAtOffset (offset); + + if (id != null) + { + + return _this.getEditor ().baseStrings.isIdValid (id.getId ()); + + } + + return sp.isCorrect (word); + + } + + @Override + public boolean isIgnored (Word word) + { + + return false; + + } + + @Override + public java.util.List getSuggestions (Word word) + { + + return sp.getSuggestions (word); + + } + + }; + + } + + }); + + this.userValue.setSpellCheckEnabled (true); + + } catch (Exception e) { + + e.printStackTrace (); + + } + + final Action defSelect = this.userValue.getEditor ().getActionMap ().get (DefaultEditorKit.selectWordAction); + + this.userValue.getEditor ().getActionMap ().put (DefaultEditorKit.selectWordAction, + new TextAction (DefaultEditorKit.selectWordAction) + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + int c = _this.userValue.getEditor ().getCaretPosition (); + + Id id = _this.getIdAtCaret (); + + if (id != null) + { + + _this.userValue.getEditor ().setSelectionStart (id.getPart (c).start); + _this.userValue.getEditor ().setSelectionEnd (id.getPart (c).end); + + } else { + + defSelect.actionPerformed (ev); + + } + + } + + }); + + if (stringsValue != null) + { + + this.userValue.setText (stringsValue.getRawText ()); + + } + + this.userValue.setAutoGrabFocus (false); + + InputMap im = this.userValue.getInputMap (JComponent.WHEN_FOCUSED); + ActionMap am = this.userValue.getActionMap (); + + im.put (KeyStroke.getKeyStroke (KeyEvent.VK_P, + InputEvent.CTRL_MASK), + "preview"); + + am.put ("preview", + new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + _this.showPreview (); + + } + + }); + + this.userValue.addKeyListener (new KeyAdapter () + { + + @Override + public void keyPressed (KeyEvent ev) + { + + if ((ev.getKeyCode () == KeyEvent.VK_ENTER) + || + (ev.getKeyCode () == KeyEvent.VK_UP) + || + (ev.getKeyCode () == KeyEvent.VK_DOWN) + ) + { + + if (_this.isSelectorVisible ()) + { + + ev.consume (); + + return; + + } + + } + + if (ev.getKeyCode () == KeyEvent.VK_TAB) + { + + ev.consume (); + +/* + if (id.hasErrors ()) + { + + _this.hideSelector (); + + return; + + } +*/ + _this.fillMatch ();//m); + + } + + } + + @Override + public void keyReleased (KeyEvent ev) + { + + if ((ev.getKeyCode () == KeyEvent.VK_CLOSE_BRACKET) + && + (ev.isShiftDown ()) + ) + { + + _this.hideSelector (); + + return; + + } + + if (ev.getKeyCode () == KeyEvent.VK_ENTER) + { + + if (_this.isSelectorVisible ()) + { + + ev.consume (); + + _this.fillMatch (); + + return; + + } + + } + + if (ev.getKeyCode () == KeyEvent.VK_UP) + { + + if (_this.isSelectorVisible ()) + { + + ev.consume (); + + _this.updateSelectedMatch (-1); + + return; + + } + + } + + if (ev.getKeyCode () == KeyEvent.VK_DOWN) + { + + if (_this.isSelectorVisible ()) + { + + ev.consume (); + + _this.updateSelectedMatch (1); + + return; + + } + + } + + if (ev.getKeyCode () == KeyEvent.VK_ESCAPE) + { + + ev.consume (); + + _this.hideSelector (); + + return; + + } + + int c = _this.userValue.getEditor ().getCaretPosition (); + + String t = _this.userValue.getEditor ().getText (); + + Id id = BaseStrings.getId (t, c); + + if (id == null) + { + + _this.hideSelector (); + + return; + + } + + Set matches = id.getPartMatches (c, + _this.getEditor ().baseStrings.getStrings ()); + + if ((matches == null) + || + (matches.size () == 0) + ) + { + + _this.hideSelector (); + + return; + + } + + if (matches.size () == 1) + { + + Id.Part p = id.getPart (c); + + if (p == null) + { + + p = id.getLastPart (); + + } + + if (p.part.equals (matches.iterator ().next ())) + { + + _this.hideSelector (); + return; + + } + + } + + try + { + + int ind = c; + + Id.Part pa = id.getPart (c); + + if (pa != null) + { + + ind = pa.start; + + } + + Rectangle r = _this.userValue.getEditor ().modelToView (ind); + + //Point p = r.getLocation (); + //p.y -= 10; + //p.x -= 10; + //p.y += r.height;. + + _this.showSelectionPopup (matches, + r.getLocation ()); + + } catch (Exception e) { + + Environment.logError ("Unable show selection popup", + e); + + } + + } + + }); + + AnyFormItem yourValue = new AnyFormItem ("Your Value", + this.userValue); + + items.add (yourValue); + + items.add (new AnyFormItem (this.previewLabel, + this.previewWrapper)); + + return items; + + } + + public void saveValue () + throws GeneralException + { + + String uv = this.getUserValue (); + + if (uv != null) + { + + if (this.stringsValue != null) + { + + this.stringsValue.setRawText (uv); + + } else { + + this.stringsValue = this.getEditor ().userStrings.insertTextValue (this.baseValue.getId ()); + + //this.stringsValue.setSCount (this.baseValue.getSCount ()); + this.stringsValue.setRawText (uv); + + } + + } else { + + this.getEditor ().userStrings.removeNode (this.baseValue.getId ()); + + } + + } + + public Id getIdAtPoint (Point p) + { + + try + { + + return BaseStrings.getId (this.userValue.getEditor ().getText (), + this.userValue.getEditor ().viewToModel (p)); + + } catch (Exception e) { + + // Can ignore. + + } + + return null; + + } + + public Id getIdAtOffset (int offset) + { + + return BaseStrings.getId (this.userValue.getEditor ().getText (), + offset); +/* + Id id = new Id (this.userValue.getEditor ().getText (), + offset); + + if (id.fullId == null) + { + + return null; + + } + + return id; +*/ + } + + public Id getIdAtCaret () + { + + return this.getIdAtOffset (this.userValue.getEditor ().getCaretPosition ()); + + } + + @Override + public String getUserValue () + { + + StringWithMarkup sm = this.userValue.getTextWithMarkup (); + + if (sm != null) + { + + if (!sm.hasText ()) + { + + return null; + + } + + return sm.getMarkedUpText (); + + } + + return null; + + } + + public void useEnglishValue () + { + + this.userValue.updateText (this.baseValue.getRawText ()); + this.showPreview (); + this.validate (); + this.repaint (); + + } + + public boolean hasErrors () + { + + String s = this.getUserValue (); + + if (s == null) + { + + return false; + + } + + return BaseStrings.getErrors (s, + BaseStrings.toId (this.baseValue.getId ()), + this.baseValue.getSCount (), + this.getEditor ()).size () > 0; + + + } + + public boolean showErrors (boolean requireUserValue) + { + + String s = this.getUserValue (); + + this.hideErrors (); + + if ((s == null) + && + (!requireUserValue) + ) + { + + return false; + + } + + Set errs = null; + + if (s == null) + { + + errs = new LinkedHashSet<> (); + + errs.add ("Cannot show a preview, no value provided."); + + } else { + + errs = BaseStrings.getErrors (s, + BaseStrings.toId (this.baseValue.getId ()), + this.baseValue.getSCount (), + this.getEditor ()); + + } + + if (errs.size () > 0) + { + + return this.showErrors (errs); + + } + + return false; + +/* + Node root = this.baseValue.getRoot (); + + this.editor.updateSideBar (this.baseValue); + + if (errs.size () > 0) + { + + if (this.errors == null) + { + + this.errors = UIUtils.createHelpTextPane ("", + this.editor); + this.errors.setBorder (UIUtils.createPadding (6, 0, 0, 0)); + this.errors.setFocusable (false); + this.errorsWrapper.add (this.errors); + + } + + StringBuilder b = new StringBuilder (); + + for (String e : errs) + { + + if (b.length () > 0) + { + + b.append ("
    "); + + } + + b.append ("- " + e); + + } + + this.errors.setText ("" + b.toString () + ""); + this.errorsLabel.setVisible (true); + this.errorsWrapper.setVisible (true); + + this.editor.updateSideBar (this.baseValue); + + return true; + + } else { + + this.errorsLabel.setVisible (false); + this.errorsWrapper.setVisible (false); + + } +*/ + + } + + public void showPreview () + { + + if (this.showErrors (false)) + { + + return; + + } + + String s = this.getUserValue (); + + if (s == null) + { + + if (this.preview != null) + { + + this.preview.setText (""); + + } + + this.previewWrapper.setVisible (false); + this.previewLabel.setVisible (false); + + this.updateSideBar (this.baseValue); + + return; + + } + + if (this.preview == null) + { + + this.preview = UIUtils.createHelpTextPane ("", + this.getEditor ()); + this.preview.setBorder (UIUtils.createPadding (6, 0, 0, 0)); + this.preview.setFocusable (false); + + this.previewWrapper.add (this.preview); + + UIUtils.addHyperLinkListener (this.preview, + this.getEditor ()); + + } + + String t = this.getEditor ().getPreviewText (s); + + t = Utils.replaceString (t, + "[", + "["); + + t = Utils.replaceString (t, + "]", + "]"); + + this.previewLabel.setVisible (true); + this.preview.setText (t); + this.previewWrapper.setVisible (true); + + this.updateSideBar (this.baseValue); + + this.validate (); + this.repaint (); + + } + + private void fillMatch () + { + + QTextEditor editor = this.userValue.getEditor (); + + int c = editor.getCaretPosition (); + + Id id = BaseStrings.getId (editor.getText (), + c); + + if (id == null) + { + + return; + + } + + String m = this.selections.getSelectedValue (); + + //m = id.getNewFullId (m); + + Id.Part part = id.getPart (c); + + if (part != null) + { + + editor.replaceText (part.start, part.end, m); + editor.setCaretPosition (part.start + m.length ()); + + } else { + + // Is the previous character a . if so append. + if ((editor.getText ().substring (c - 1, c).equals (".")) + || + (c == id.getEnd ()) + ) + { + + editor.replaceText (c, c, m); + editor.setCaretPosition (c + m.length ()); + + } else { + + part = id.getLastPart (); + + editor.replaceText (part.start, part.start + part.end, m); + editor.setCaretPosition (part.start + m.length ()); + + } + + } + + c = editor.getCaretPosition (); + + id = this.getIdAtCaret (); + + // We may be inserting into the middle of an id, check to see if it's valid. +/* + if (id.hasErrors ()) + { + + this.hideSelector (); + + // Update the view to "spell check" the ids. + return; + + } +*/ + // Check to see if the id maps to a string. + if (this.getEditor ().baseStrings.getString (id.getId ()) != null) + { + + if (id.isPartial ()) + { + + editor.replaceText (id.getEnd (), id.getEnd (), "}"); + editor.setCaretPosition (c + 1); + + } + + this.hideSelector (); + + return; + + } + + // Check to see if there are more matches further down the tree. + String nid = id.getId () + "."; + + Set matches = this.getEditor ().baseStrings.getIdMatches (nid); + + if (matches.size () > 0) + { + + c = editor.getCaretPosition (); + + editor.replaceText (c, c, "."); + editor.setCaretPosition (c + 1); + + try + { + + this.showSelectionPopup (matches, + editor.modelToView (id.getPart (c).start).getLocation ()); + + } catch (Exception e) { + + e.printStackTrace (); + + } + + return; + + } else { + + c = editor.getCaretPosition (); + + editor.replaceText (c, c, "}"); + editor.setCaretPosition (c + 1); + + this.hideSelector (); + + return; + + } + + } + + private String updateSelectedMatch (int incr) + { + + int i = this.selections.getSelectedIndex (); + + i += incr; + + int s = this.selections.getModel ().getSize (); + + if (i < 0) + { + + i = s + i; + + } + + if (i > s - 1) + { + + i -= s; + + } + + this.selections.setSelectedIndex (i); + + return this.selections.getSelectedValue (); + + } + + public boolean isSelectorVisible () + { + + if (this.selector != null) + { + + return this.selector.isVisible (); + + } + + return false; + + } + + public void hideSelector () + { + + if (this.selector != null) + { + + this.selector.setVisible (false); + + } + + this.userValue.getEditor ().setFocusTraversalKeysEnabled (true); + + } + + public void showSelectionPopup (Set matches, + Point point) + { + + if (this.selector == null) + { + + this.selector = new Box (BoxLayout.Y_AXIS); + + this.selector.setOpaque (true); + this.selector.setBackground (UIUtils.getComponentColor ()); + this.selector.setBorder (UIUtils.createLineBorder ()); + + } + + if ((matches == null) + || + (matches.size () == 0) + ) + { + + this.hideSelector (); + + return; + + } + + this.userValue.getEditor ().setFocusTraversalKeysEnabled (false); + + this.selector.removeAll (); + + DefaultListModel m = new DefaultListModel<> (); + + for (String o : matches) + { + + m.addElement (o); + + } + + this.selections = new JList (); + final JList l = this.selections; + l.setModel (m); + l.setLayoutOrientation (JList.VERTICAL); + l.setVisibleRowCount (0); + l.setOpaque (true); + l.setBackground (UIUtils.getComponentColor ()); + l.setMaximumSize (new Dimension (Short.MAX_VALUE, + Short.MAX_VALUE)); + UIUtils.setAsButton (l); + + l.setCellRenderer (new DefaultListCellRenderer () + { + + public Component getListCellRendererComponent (JList list, + Object value, + int index, + boolean isSelected, + boolean cellHasFocus) + { + + String obj = (String) value; + + JLabel l = (JLabel) super.getListCellRendererComponent (list, + value, + index, + isSelected, + cellHasFocus); + + l.setText (obj);//.getName ()); + + l.setFont (l.getFont ().deriveFont (UIUtils.getScaledFontSize (10)).deriveFont (Font.PLAIN)); + l.setBorder (UIUtils.createBottomLineWithPadding (5, 5, 5, 5)); + l.setPreferredSize (new Dimension (l.getPreferredSize ().width, 29)); + + return l; + + } + + }); + + l.setSelectedIndex (0); + + int rowHeight = 30; + + l.setAlignmentX (JComponent.LEFT_ALIGNMENT); + + JScrollPane sp = new JScrollPane (l); + + sp.setHorizontalScrollBarPolicy (ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); + sp.getVerticalScrollBar ().setUnitIncrement (rowHeight); + sp.setAlignmentX (JComponent.LEFT_ALIGNMENT); + sp.setOpaque (false); + sp.setBorder (null); + + this.selector.add (sp); + + this.selector.setPreferredSize (new Dimension (300, + rowHeight * (matches.size () > 10 ? 10 : matches.size ()))); + + this.getEditor ().showPopupAt (this.selector, + SwingUtilities.convertPoint (this.userValue, + point, + this.getEditor ()), + false); + + } + + @Override + public Dimension getMaximumSize () + { + + return new Dimension (Short.MAX_VALUE, + this.getPreferredSize ().height); + + } + +} diff --git a/src/com/quollwriter/ui/LayoutImagePanel.java b/src/main/java/com/quollwriter/ui/LayoutImagePanel.java similarity index 100% rename from src/com/quollwriter/ui/LayoutImagePanel.java rename to src/main/java/com/quollwriter/ui/LayoutImagePanel.java diff --git a/src/com/quollwriter/ui/LinkedToAccordionItem.java b/src/main/java/com/quollwriter/ui/LinkedToAccordionItem.java similarity index 100% rename from src/com/quollwriter/ui/LinkedToAccordionItem.java rename to src/main/java/com/quollwriter/ui/LinkedToAccordionItem.java diff --git a/src/com/quollwriter/ui/LinkedToEditPanel.java b/src/main/java/com/quollwriter/ui/LinkedToEditPanel.java similarity index 91% rename from src/com/quollwriter/ui/LinkedToEditPanel.java rename to src/main/java/com/quollwriter/ui/LinkedToEditPanel.java index d17fea2a..45346c43 100644 --- a/src/com/quollwriter/ui/LinkedToEditPanel.java +++ b/src/main/java/com/quollwriter/ui/LinkedToEditPanel.java @@ -26,8 +26,6 @@ import com.gentlyweb.properties.*; -import com.gentlyweb.utils.*; - import com.jgoodies.forms.builder.*; import com.jgoodies.forms.factories.*; import com.jgoodies.forms.layout.*; @@ -48,21 +46,21 @@ public class LinkedToEditPanel extends EditPanel { - + private E obj = null; private V viewer = null; private JTree linkedToEditTree = null; - private JTree linkedToViewTree = null; - + private JTree linkedToViewTree = null; + public LinkedToEditPanel (E obj, V viewer) { - + this.obj = obj; this.viewer = viewer; - + } - + @Override public void refreshViewPanel () { @@ -99,11 +97,11 @@ public void refreshViewPanel () @Override public JComponent getSaveButton () { - + final LinkedToEditPanel _thisep = this; - + IconProvider ip = this.getIconProvider (); - + JButton save = UIUtils.createButton (ip.getIcon (Constants.SAVE_ICON_NAME, Constants.ICON_PANEL_SECTION_ACTION), String.format (Environment.getUIString (LanguageStrings.linkedto, @@ -115,62 +113,62 @@ public JComponent getSaveButton () //"Click to save the details", new ActionListener () { - + @Override public void actionPerformed (ActionEvent ev) { - + _thisep.doSave (); - + } - + }); return save; - + } - + @Override public JComponent getCancelButton () { - + final LinkedToEditPanel _thisep = this; - - IconProvider ip = this.getIconProvider (); - + + IconProvider ip = this.getIconProvider (); + JButton cancel = UIUtils.createButton (ip.getIcon (Constants.CANCEL_ICON_NAME, Constants.ICON_PANEL_SECTION_ACTION), Environment.getUIString (LanguageStrings.linkedto, LanguageStrings.edit, LanguageStrings.buttons, LanguageStrings.cancel, - LanguageStrings.tooltip), + LanguageStrings.tooltip), //"Click to cancel the editing", new ActionListener () { - + @Override public void actionPerformed (ActionEvent ev) { - + _thisep.doCancel (); - + } - + }); return cancel; - + } - + @Override public JComponent getEditButton () { - + final LinkedToEditPanel _thisep = this; - - IconProvider ip = this.getIconProvider (); - + + IconProvider ip = this.getIconProvider (); + return UIUtils.createButton (ip.getIcon (Constants.EDIT_ICON_NAME, Constants.ICON_PANEL_SECTION_ACTION), String.format (Environment.getUIString (LanguageStrings.linkedto, @@ -181,19 +179,19 @@ public JComponent getEditButton () Environment.getObjectTypeName (this.obj)), new ActionListener () { - + @Override public void actionPerformed (ActionEvent ev) { - + _thisep.doEdit (); - + } - + }); - } - + } + @Override public Set getEditItems () { @@ -260,7 +258,7 @@ public boolean handleSave () UIUtils.showErrorMessage (this.viewer, Environment.getUIString (LanguageStrings.linkedto, LanguageStrings.save, - LanguageStrings.actionerror)); + LanguageStrings.actionerror)); //"An internal error has occurred.\n\nUnable to save links."); return false; @@ -308,7 +306,7 @@ public void refreshLinkedToTree () UIUtils.expandAllNodesWithChildren (this.linkedToViewTree); } - + @Override public boolean handleCancel () { @@ -369,7 +367,7 @@ public String getEditTitle () LanguageStrings.title); } - + @Override public String getTitle () { @@ -407,4 +405,4 @@ public JComponent getViewPanel () } -} \ No newline at end of file +} diff --git a/src/com/quollwriter/ui/MessageWindow.java b/src/main/java/com/quollwriter/ui/MessageWindow.java similarity index 98% rename from src/com/quollwriter/ui/MessageWindow.java rename to src/main/java/com/quollwriter/ui/MessageWindow.java index 8458fcff..440061d0 100644 --- a/src/com/quollwriter/ui/MessageWindow.java +++ b/src/main/java/com/quollwriter/ui/MessageWindow.java @@ -10,8 +10,6 @@ import javax.swing.*; import javax.swing.border.*; -import com.gentlyweb.utils.*; - import com.jgoodies.forms.builder.*; import com.jgoodies.forms.factories.*; import com.jgoodies.forms.layout.*; diff --git a/src/com/quollwriter/ui/NamedObjectFindResultsBox.java b/src/main/java/com/quollwriter/ui/NamedObjectFindResultsBox.java similarity index 100% rename from src/com/quollwriter/ui/NamedObjectFindResultsBox.java rename to src/main/java/com/quollwriter/ui/NamedObjectFindResultsBox.java diff --git a/src/com/quollwriter/ui/NamedObjectPreviewPopup.java b/src/main/java/com/quollwriter/ui/NamedObjectPreviewPopup.java similarity index 99% rename from src/com/quollwriter/ui/NamedObjectPreviewPopup.java rename to src/main/java/com/quollwriter/ui/NamedObjectPreviewPopup.java index 8e667b53..a28167bd 100644 --- a/src/com/quollwriter/ui/NamedObjectPreviewPopup.java +++ b/src/main/java/com/quollwriter/ui/NamedObjectPreviewPopup.java @@ -10,8 +10,6 @@ import javax.swing.*; import javax.swing.border.*; -import com.gentlyweb.utils.*; - import com.jgoodies.forms.builder.*; import com.jgoodies.forms.factories.*; import com.jgoodies.forms.layout.*; diff --git a/src/com/quollwriter/ui/NewColorStateChangeEvent.java b/src/main/java/com/quollwriter/ui/NewColorStateChangeEvent.java similarity index 100% rename from src/com/quollwriter/ui/NewColorStateChangeEvent.java rename to src/main/java/com/quollwriter/ui/NewColorStateChangeEvent.java diff --git a/src/main/java/com/quollwriter/ui/NewProjectPanel.java b/src/main/java/com/quollwriter/ui/NewProjectPanel.java new file mode 100644 index 00000000..92425cad --- /dev/null +++ b/src/main/java/com/quollwriter/ui/NewProjectPanel.java @@ -0,0 +1,578 @@ +package com.quollwriter.ui; + +import java.awt.Color; +import java.awt.Container; +import java.awt.Component; +import java.awt.event.*; + +import java.io.*; + +import java.util.*; + +import javax.swing.*; +import javax.swing.border.*; + +import com.jgoodies.forms.builder.*; +import com.jgoodies.forms.factories.*; +import com.jgoodies.forms.layout.*; + +import com.quollwriter.*; + +import com.quollwriter.data.*; +import com.quollwriter.data.comparators.*; + +import com.quollwriter.ui.components.*; + + +public class NewProjectPanel +{ + + private JTextField nameField = null; + private JTextField saveField = null; + private JPasswordField passwordField2 = null; + private JPasswordField passwordField = null; + private JCheckBox encryptField = null; + private JLabel error = null; + private Project project = null; + + public NewProjectPanel() + { + + this.nameField = UIUtils.createTextField (); + + } + + public void setProject (Project p) + { + + this.project = p; + + } + + public JTextField getNameField () + { + + return this.nameField; + + } + + public JComponent createPanel (final Container parent, + final ActionListener onCreate, + boolean createOnReturn, + final ActionListener onCancel, + boolean addButtons) + { + + final NewProjectPanel _this = this; + + String rows = "p, 6px, p, 6px, p, 6px, p"; + + if (addButtons) + { + + rows = rows + ", 6px, p"; + + } + + int row = 1; + + final FormLayout fl = new FormLayout ("right:p, 6px, fill:200px:grow, 2px, p", + rows); + fl.setHonorsVisibility (true); + final PanelBuilder builder = new PanelBuilder (fl); + + final CellConstraints cc = new CellConstraints (); + + builder.addLabel (Environment.getUIString (LanguageStrings.newprojectpanel, + LanguageStrings.labels, + LanguageStrings.name), + //"Name", + cc.xy (1, + row)); + builder.add (this.nameField, + cc.xy (3, + row)); + + row += 2; + + builder.addLabel (Environment.getUIString (LanguageStrings.newprojectpanel, + LanguageStrings.labels, + LanguageStrings.savein), + //"Save In", + cc.xy (1, + row)); + + File defDir = Environment.getDefaultSaveProjectDirPath ().toFile (); + + this.saveField = UIUtils.createTextField (); + this.saveField.setText (defDir.getPath ()); + + // this.nameField.addKeyListener (k); + // this.saveField.addKeyListener (k); + + builder.add (this.saveField, + cc.xy (3, + row)); + + JButton findBut = new JButton (Environment.getIcon ("find", + Constants.ICON_MENU)); + + findBut.addActionListener (new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + JFileChooser f = new JFileChooser (); + f.setDialogTitle (Environment.getUIString (LanguageStrings.newprojectpanel, + LanguageStrings.find, + LanguageStrings.title)); + //"Select a Directory"); + f.setFileSelectionMode (JFileChooser.DIRECTORIES_ONLY); + f.setApproveButtonText (Environment.getUIString (LanguageStrings.newprojectpanel, + LanguageStrings.find, + LanguageStrings.confirm)); + //"Select"); + f.setCurrentDirectory (new File (_this.saveField.getText ())); + + // Need to run: attrib -r "%USERPROFILE%\My Documents" on XP to allow a new directory + // to be created in My Documents. + + if (f.showOpenDialog (parent) == JFileChooser.APPROVE_OPTION) + { + + _this.saveField.setText (f.getSelectedFile ().getPath ()); + + } + + } + + }); + + builder.add (findBut, + cc.xy (5, + row)); + + row += 2; + + this.encryptField = UIUtils.createCheckBox (Environment.getUIString (LanguageStrings.newprojectpanel, + LanguageStrings.labels, + LanguageStrings.encrypt)); + //"Encrypt this {project}? You will be prompted for a password."); + this.encryptField.setBackground (Color.WHITE); + + builder.add (this.encryptField, + cc.xyw (3, + row, + 2)); + + FormLayout pfl = new FormLayout ("right:p, 6px, 100px, 20px, p, 6px, fill:100px", + "p, 6px"); + pfl.setHonorsVisibility (true); + PanelBuilder pbuilder = new PanelBuilder (pfl); + + this.passwordField = new JPasswordField (); + + pbuilder.addLabel (Environment.getUIString (LanguageStrings.newprojectpanel, + LanguageStrings.labels, + LanguageStrings.password), + //"Password", + cc.xy (1, + 1)); + + pbuilder.add (this.passwordField, + cc.xy (3, + 1)); + + this.passwordField2 = new JPasswordField (); + + pbuilder.addLabel (Environment.getUIString (LanguageStrings.newprojectpanel, + LanguageStrings.labels, + LanguageStrings.confirmpassword), + //"Confirm", + cc.xy (5, + 1)); + + pbuilder.add (this.passwordField2, + cc.xy (7, + 1)); + + row += 2; + + final JPanel ppanel = pbuilder.getPanel (); + ppanel.setVisible (false); + ppanel.setOpaque (false); + + builder.add (ppanel, + cc.xyw (3, + row, + 2)); + + this.encryptField.addActionListener (new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + ppanel.setVisible (_this.encryptField.isSelected ()); + + UIUtils.resizeParent (parent); + + } + + }); + + ActionListener createProjectAction = new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + if (!_this.createProject (parent)) + { + + return; + + } + + if (onCreate != null) + { + + onCreate.actionPerformed (new ActionEvent (_this, + 0, + _this.nameField.getText ())); + + } + + if (parent instanceof PopupWindow) + { + + ((PopupWindow) parent).close (); + + } + + if (parent instanceof QPopup) + { + + ((QPopup) parent).removeFromParent (); + + } + + } + + }; + + if (addButtons) + { + + row += 2; + + JButton createBut = new JButton (); + createBut.setText (Environment.getUIString (LanguageStrings.newprojectpanel, + LanguageStrings.buttons, + LanguageStrings.create)); + //"Create"); + + createBut.addActionListener (createProjectAction); + + JButton cancelBut = new JButton (); + cancelBut.setText (Environment.getUIString (LanguageStrings.newprojectpanel, + LanguageStrings.buttons, + LanguageStrings.cancel)); + //"Cancel"); + + if (onCancel != null) + { + + cancelBut.addActionListener (onCancel); + + } + + if (parent instanceof PopupWindow) + { + + cancelBut.addActionListener (((PopupWindow) parent).getCloseAction ()); + + } + + if (parent instanceof QPopup) + { + + cancelBut.addActionListener (((QPopup) parent).getCloseAction ()); + + } + + JButton[] buts = { createBut, cancelBut }; + + JPanel bp = UIUtils.createButtonBar2 (buts, + Component.LEFT_ALIGNMENT); //ButtonBarFactory.buildLeftAlignedBar (buts); + bp.setOpaque (false); + bp.setAlignmentX (Component.LEFT_ALIGNMENT); + + builder.add (bp, + cc.xyw (3, + row, + 3)); + + } + + JPanel p = builder.getPanel (); + p.setOpaque (false); + p.setAlignmentX (JComponent.LEFT_ALIGNMENT); + + if (createOnReturn) + { + + UIUtils.addDoActionOnReturnPressed (this.nameField, + createProjectAction); + UIUtils.addDoActionOnReturnPressed (this.saveField, + createProjectAction); + UIUtils.addDoActionOnReturnPressed (this.passwordField, + createProjectAction); + UIUtils.addDoActionOnReturnPressed (this.passwordField2, + createProjectAction); + + } + + this.error = UIUtils.createErrorLabel (""); + this.error.setVisible (false); + this.error.setBorder (new EmptyBorder (0, + 0, + 5, + 0)); + + Box b = new Box (BoxLayout.Y_AXIS); + + b.add (this.error); + b.add (p); + + return b; + + } + + public boolean createProject (Container parent) + { + + if (!this.checkForm (parent)) + { + + return false; + + } + + Project proj = this.project; + + if (proj == null) + { + + proj = new Project (this.getName ()); + + } else { + + proj.setName (this.getName ()); + + } + + AbstractProjectViewer pj = null; + + try + { + + // TODO pj = Environment.getProjectViewerForType (proj); + + } catch (Exception e) + { + + Environment.logError ("Unable to create new project: " + + proj, + e); + + UIUtils.showErrorMessage (parent, + Environment.getUIString (LanguageStrings.newprojectpanel, + LanguageStrings.actionerror)); + //"Unable to create new project: " + proj.getName ()); + + return false; + + } + + try + { + + pj.newProject (this.getSaveDirectory (), + proj, + this.getPassword ()); + + } catch (Exception e) + { + + Environment.logError ("Unable to create new project: " + + proj, + e); + + UIUtils.showErrorMessage (parent, + Environment.getUIString (LanguageStrings.newprojectpanel, + LanguageStrings.actionerror)); + //"Unable to create new project: " + proj.getName ()); + + return false; + + } + + return true; + + } + + private boolean showError (Container parent, + String text) + { + + this.error.setText (Environment.replaceObjectNames (text)); + + this.error.setVisible (true); + + parent.repaint (); + + UIUtils.resizeParent (parent); + + return false; + + } + + private boolean hideError (Container parent) + { + + this.error.setVisible (false); + + parent.repaint (); + + UIUtils.resizeParent (parent); + + return false; + + } + + public boolean checkForm (Container parent) + { + + java.util.List prefix = new ArrayList (); + prefix.add (LanguageStrings.newprojectpanel); + prefix.add (LanguageStrings.errors); + + this.hideError (parent); + + String n = this.nameField.getText ().trim (); + + if (n.equals ("")) + { + + return this.showError (parent, + Environment.getUIString (prefix, + LanguageStrings.novalue)); + //"Please provide a name for the {project}."); + + } + + // See if the project already exists. + File pf = new File (saveField.getText (), Utils.sanitizeForFilename (n)); + + if (pf.exists ()) + { + + return this.showError (parent, + Environment.getUIString (prefix, + LanguageStrings.valueexists)); + + } + + String pwd = null; + + if (this.encryptField.isSelected ()) + { + + // Make sure a password has been provided. + pwd = new String (this.passwordField.getPassword ()).trim (); + + String pwd2 = new String (this.passwordField2.getPassword ()).trim (); + + if (pwd.equals ("")) + { + + return this.showError (parent, + Environment.getUIString (prefix, + LanguageStrings.nopassword)); + //"Please provide a password for securing the {project}."); + + } + + if (pwd2.equals ("")) + { + + return this.showError (parent, + Environment.getUIString (prefix, + LanguageStrings.confirmpassword)); + //"Please confirm your password."); + + } + + if (!pwd.equals (pwd2)) + { + + return this.showError (parent, + Environment.getUIString (prefix, + LanguageStrings.nomatch)); + //"The passwords do not match."); + + } + + } + + return true; + + } + + public File getSaveDirectory () + { + + return new File (this.saveField.getText ()); + + } + + public String getPassword () + { + + if (!this.encryptField.isSelected ()) + { + + return null; + + } + + String pwd = new String (this.passwordField.getPassword ()); + + if (pwd.trim ().equals ("")) + { + + pwd = null; + + } + + return pwd; + + } + + public void setName (String n) + { + + this.nameField.setText (n); + + } + + public String getName () + { + + return this.nameField.getText (); + + } + +} diff --git a/src/com/quollwriter/ui/NotesAccordionItem.java b/src/main/java/com/quollwriter/ui/NotesAccordionItem.java similarity index 99% rename from src/com/quollwriter/ui/NotesAccordionItem.java rename to src/main/java/com/quollwriter/ui/NotesAccordionItem.java index f4e9c525..550eee3b 100644 --- a/src/com/quollwriter/ui/NotesAccordionItem.java +++ b/src/main/java/com/quollwriter/ui/NotesAccordionItem.java @@ -22,7 +22,7 @@ public class NotesAccordionItem extends ProjectObjectsAccordionItem singular = new HashMap (); private Map plural = new HashMap (); private AbstractViewer viewer = null; - + public ObjectTypeNameChanger (AbstractViewer viewer) { super (BoxLayout.Y_AXIS); - + this.viewer = viewer; } - + private void save () { - + // See if any of the values are changing, if so we need to reopen the project. - + boolean changing = false; - + final Map sing = new HashMap (); final Map plur = new HashMap (); - + Set updateTypes = new HashSet (); for (String ot : this.singular.keySet ()) { - + JTextField f = this.singular.get (ot); - + String s = f.getText ().trim (); - + if (!s.equals (Environment.getObjectTypeName (ot))) { - + sing.put (ot, - s); - + s); + } - + } for (String ot : this.plural.keySet ()) { - + JTextField f = this.plural.get (ot); - + String p = f.getText ().trim (); - + if (!p.equals (Environment.getObjectTypeName (ot))) { @@ -81,7 +81,7 @@ private void save () p); } - + } if ((sing.size () > 0) @@ -89,11 +89,11 @@ private void save () (plur.size () > 0) ) { - + changing = true; - + } - + if (changing) { @@ -101,18 +101,18 @@ private void save () prefix.add (LanguageStrings.objectnames); prefix.add (LanguageStrings.changer); prefix.add (LanguageStrings.confirmchange); - + if (this.viewer instanceof AbstractProjectViewer) { - + AbstractProjectViewer pv = (AbstractProjectViewer) this.viewer; - + final Project proj = pv.getProject (); final ObjectTypeNameChanger _this = this; - + //XXX xxx handle ALL open projects //xxx recreate the landing - + // Offer to reopen project. UIUtils.createQuestionPopup (this.viewer, Environment.getUIString (prefix, @@ -136,150 +136,152 @@ private void save () //null, new ActionListener () { - + public void actionPerformed (ActionEvent ev) { - + try { - +/* +TODO Environment.updateUserObjectTypeNames (sing, plur); - +*/ } catch (Exception e) { - + UIUtils.showErrorMessage (_this, Environment.getUIString (prefix, LanguageStrings.actionerror)); //"Unable to modify names"); - + Environment.logError ("Unable to modify names", e); - + return; - + } - + UIUtils.closePopupParent (_this.getParent ()); - + _this.viewer.close (true, new ActionListener () { - + public void actionPerformed (ActionEvent ev) { - + // Open the project again. try { - + Environment.openProject (proj); - + } catch (Exception e) { - + Environment.logError ("Unable to reopen project: " + proj, e); try { - - Environment.relaunchLanding (); - + + // TODO Probably not needed Environment.relaunchLanding (); + } catch (Exception ee) { - + Environment.logError ("Unable to open landing.", e); - + UIUtils.showErrorMessage (this, Environment.getUIString (LanguageStrings.allprojects, LanguageStrings.actionerror)); - + } - + } - + } - + }); - + } - + }, null, null, null); - + return; - + } else { - + try { - +/* +TODO Environment.updateUserObjectTypeNames (sing, plur); - +*/ } catch (Exception e) { - + UIUtils.showErrorMessage (this, Environment.getUIString (prefix, LanguageStrings.actionerror)); //"Unable to modify names"); - + Environment.logError ("Unable to modify names", e); - + return; - + } - + try { - - Environment.relaunchLanding (); - + + // TODO Not needed? Environment.relaunchLanding (); + } catch (Exception e) { - + UIUtils.showErrorMessage (this, Environment.getUIString (LanguageStrings.allprojects, LanguageStrings.actionerror)); //"Unable to show start window, please contact Quoll Writer support for assistance."); - + Environment.logError ("Unable to show start window", e); - + return; - + } - + } - + } - + UIUtils.closePopupParent (this.getParent ()); //this.close (); - + } private void reset () { - + final ObjectTypeNameChanger _this = this; - + final java.util.List prefix = new ArrayList (); prefix.add (LanguageStrings.objectnames); prefix.add (LanguageStrings.changer); prefix.add (LanguageStrings.resetchange); - + if (this.viewer instanceof AbstractProjectViewer) { - + AbstractProjectViewer pv = (AbstractProjectViewer) this.viewer; - + final Project proj = pv.getProject (); - + // Offer to reopen project. UIUtils.createQuestionPopup (this.viewer, Environment.getUIString (prefix, @@ -303,152 +305,152 @@ private void reset () //null, new ActionListener () { - + public void actionPerformed (ActionEvent ev) { - + try { - + Environment.resetObjectTypeNamesToDefaults (); - + } catch (Exception e) { - + UIUtils.showErrorMessage (_this, Environment.getUIString (prefix, LanguageStrings.actionerror)); //"Unable to modify names"); - + Environment.logError ("Unable to modify names", e); - + return; - + } - + //_this.close (); UIUtils.closePopupParent (_this.getParent ()); - + _this.viewer.close (true, new ActionListener () { - + public void actionPerformed (ActionEvent ev) { - + // Open the project again. try { - + Environment.openProject (proj); - + } catch (Exception e) { - + Environment.logError ("Unable to reopen project: " + proj, - e); + e); try { - - Environment.relaunchLanding (); - + + // TODO Not needed? Environment.relaunchLanding (); + } catch (Exception ee) { - + Environment.logError ("Unable to open landing.", e); - + UIUtils.showErrorMessage (this, Environment.getUIString (LanguageStrings.allprojects, LanguageStrings.actionerror)); - + } } - + } - + }); - + } }, null, null, null); - + } else { - + try { - + Environment.resetObjectTypeNamesToDefaults (); - + } catch (Exception e) { - + UIUtils.showErrorMessage (this, Environment.getUIString (prefix, LanguageStrings.actionerror)); //"Unable to modify names"); - + Environment.logError ("Unable to modify names", e); - + return; - + } - + try { - - Environment.relaunchLanding (); - + + // TODO Not needed? Environment.relaunchLanding (); + } catch (Exception e) { - + UIUtils.showErrorMessage (this, Environment.getUIString (LanguageStrings.allprojects, LanguageStrings.actionerror)); //"Unable to show start window, please contact Quoll Writer support for assistance."); - + Environment.logError ("Unable to show landing.", e); - + return; - + } - + } } - + private boolean addRow (final String objType, PanelBuilder builder, int row) { final ObjectTypeNameChanger _this = this; - + CellConstraints cc = new CellConstraints (); - + ImageIcon ii = Environment.getIcon (objType, Constants.ICON_MENU); - + if (ii == null) { - + return false; - + } - + builder.add (new ImagePanel (ii, null), cc.xy (1, row)); - - final JTextField s = new JTextField (Environment.getObjectTypeName (objType)); - final JTextField p = new JTextField (Environment.getObjectTypeNamePlural (objType)); - + + final JTextField s = new JTextField (Environment.getObjectTypeName (objType).getValue ()); + final JTextField p = new JTextField (Environment.getObjectTypeNamePlural (objType).getValue ()); + this.singular.put (objType, s); - + this.plural.put (objType, p); @@ -457,33 +459,33 @@ private boolean addRow (final String objType, row)); builder.add (p, cc.xy (5, - row)); - + row)); + return true; - + } - + public void init () { final ObjectTypeNameChanger _this = this; - + java.util.List prefix = new ArrayList (); prefix.add (LanguageStrings.objectnames); prefix.add (LanguageStrings.changer); prefix.add (LanguageStrings.popup); - + JTextPane help = UIUtils.createHelpTextPane (Environment.getUIString (prefix, LanguageStrings.text), - //"After saving any changes to names will appear when you next open the {project}.", + //"After saving any changes to names will appear when you next open the {project}.", this.viewer); help.setBorder (null); help.setAlignmentX (Component.LEFT_ALIGNMENT); - + this.add (help); this.add (Box.createVerticalStrut (10)); - + List objTypes = new ArrayList (); objTypes.add (Chapter.OBJECT_TYPE); /* @@ -498,24 +500,24 @@ public void init () objTypes.add (Project.OBJECT_TYPE); objTypes.add (Warmup.OBJECT_TYPE); objTypes.add (EditorEditor.OBJECT_TYPE); - + StringBuilder rows = new StringBuilder ("p, 5px"); - + for (String ot : objTypes) { - + if (Environment.getIcon (ot, Constants.ICON_MENU) != null) { - + rows.append (", center:p, 10px"); - - } - + + } + } rows.append (",p"); - + FormLayout fl = new FormLayout ("p, 6px, 180px:grow, 20px, 180px:grow", rows.toString ()); @@ -524,7 +526,7 @@ public void init () CellConstraints cc = new CellConstraints (); int row = 1; - + builder.addLabel (Environment.getUIString (prefix, LanguageStrings.labels, LanguageStrings.singular), @@ -539,18 +541,18 @@ public void init () row)); row += 2; - + for (String ot : objTypes) { - + this.addRow (ot, builder, row); - + row += 2; - + } - + JButton save = UIUtils.createButton (Environment.getUIString (prefix, LanguageStrings.buttons, LanguageStrings.save)); @@ -563,7 +565,7 @@ public void actionPerformed (ActionEvent ev) { _this.save (); - + } }); @@ -597,26 +599,26 @@ public void actionPerformed (ActionEvent ev) { _this.reset (); - + } }); - + JButton[] buts = { save, reset, cancel }; JPanel bp = UIUtils.createButtonBar2 (buts, - Component.CENTER_ALIGNMENT); + Component.CENTER_ALIGNMENT); bp.setOpaque (false); builder.add (bp, - cc.xywh (1, row, 5, 1)); + cc.xywh (1, row, 5, 1)); JPanel p = builder.getPanel (); p.setBorder (null); p.setAlignmentX (Component.LEFT_ALIGNMENT); - + this.add (p); - + } -} \ No newline at end of file +} diff --git a/src/main/java/com/quollwriter/ui/Options.java b/src/main/java/com/quollwriter/ui/Options.java new file mode 100644 index 00000000..9b3b0656 --- /dev/null +++ b/src/main/java/com/quollwriter/ui/Options.java @@ -0,0 +1,5183 @@ +package com.quollwriter.ui; + +import java.awt.Component; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Toolkit; +import java.awt.Point; +import java.awt.event.*; + +import java.io.*; +import java.net.*; +import java.beans.*; + +import java.util.Arrays; +import java.util.List; +import java.util.Set; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.Map; +import java.util.HashMap; +import java.util.Vector; +import java.util.ArrayList; +import java.util.Date; +import java.util.StringTokenizer; + +import javax.sound.sampled.*; + +import javax.swing.*; +import javax.swing.event.*; +import javax.swing.border.*; +import javax.swing.tree.*; +import javax.swing.filechooser.*; + +import com.gentlyweb.properties.*; + +import com.jgoodies.forms.factories.*; +import com.jgoodies.forms.builder.*; +import com.jgoodies.forms.layout.*; + +import com.quollwriter.data.*; +import com.quollwriter.*; +import com.quollwriter.events.*; +import com.quollwriter.ui.*; +import com.quollwriter.ui.forms.*; +import com.quollwriter.ui.renderers.*; +import com.quollwriter.ui.components.Header; +import com.quollwriter.ui.components.ItemAdapter; +import com.quollwriter.ui.components.ActionAdapter; +import com.quollwriter.ui.components.QPopup; +import com.quollwriter.ui.components.ChangeAdapter; +import com.quollwriter.ui.components.ImagePanel; +import com.quollwriter.ui.components.Accordion; +import com.quollwriter.achievements.*; +import com.quollwriter.achievements.ui.*; +import com.quollwriter.editors.*; +import com.quollwriter.data.editors.*; +import com.quollwriter.ui.panels.*; +import com.quollwriter.text.*; + +import com.quollwriter.editors.messages.*; +import com.quollwriter.editors.ui.*; +import com.quollwriter.uistrings.*; + +import com.quollwriter.ui.fx.ProjectEvent; + +import static com.quollwriter.LanguageStrings.*; +import static com.quollwriter.uistrings.UILanguageStringsManager.getUIString; + +public class Options extends Box +{ + + public enum Section + { + + warmups ("warmups"), + look ("look"), + naming ("naming"), + editing ("editing"), + editors ("editors"), + itemsAndRules ("itemsAndRules"), + achievements ("achievements"), + problems ("problems"), + betas ("betas"), + start ("start"), + landing ("landing"), + assets ("assets"), + project ("project"), + website ("website"); + + private String type = null; + + Section (String type) + { + + this.type = type; + + } + + public String getType () + { + + return this.type; + + } + + } + + private Header header = null; + private AbstractViewer viewer = null; + private Accordion accordion = null; + private JScrollPane scrollPane = null; + private JCheckBox sendErrorsToSupport = null; + + private Map sections = new HashMap (); + + private Set
    sectIds = null; + + public Options (AbstractViewer viewer, + Section... sectIds) + throws GeneralException + { + + super (BoxLayout.Y_AXIS); + + this.viewer = viewer; + + this.sectIds = new LinkedHashSet (new ArrayList ((List
    ) Arrays.asList (sectIds))); + + this.header = UIUtils.createHeader (getUIString (options,title), + //"Options", + Constants.PANEL_TITLE, + Constants.OPTIONS_ICON_NAME, + null); + + } + + public class SectionInfo + { + + public String title = null; + public String help = null; + public JComponent content = null; + public String iconType = null; + + public SectionInfo (String title, + String iconType, + String help, + JComponent content) + { + + this.title = title; + this.iconType = iconType; + this.help = help; + this.content = content; + + } + + } + + public Header getHeader () + { + + return this.header; + + } + + public void init () + { + + this.add (this.header); + + Box b = new Box (BoxLayout.Y_AXIS); + + final Options _this = this; + + this.accordion = new Accordion (BoxLayout.Y_AXIS); + + this.accordion.setBorder (new EmptyBorder (0, + 10, + 10, + 10)); + + this.scrollPane = new JScrollPane (this.accordion); + this.scrollPane.setBorder (new EmptyBorder (1, 0, 0, 0)); + this.scrollPane.setOpaque (false); + this.scrollPane.getViewport ().setBorder (null); + this.scrollPane.getViewport ().setOpaque (false); + this.scrollPane.getVerticalScrollBar ().setUnitIncrement (50); + this.scrollPane.setAlignmentX (Component.LEFT_ALIGNMENT); + + this.scrollPane.getVerticalScrollBar ().addAdjustmentListener (new AdjustmentListener () + { + + public void adjustmentValueChanged (AdjustmentEvent ev) + { + + if (_this.scrollPane.getVerticalScrollBar ().getValue () > 0) + { + + _this.scrollPane.setBorder (new MatteBorder (1, 0, 0, 0, + UIUtils.getInnerBorderColor ())); + + } else { + + _this.scrollPane.setBorder (new EmptyBorder (1, 0, 0, 0)); + + } + + } + + }); + + this.add (this.scrollPane); + + this.accordion.setOpaque (false); + + for (Section sect : this.sectIds) + { + + SectionInfo inf = this.getSectionInfo (sect); + + if (inf == null) + { + + continue; + + } + + this.setContentBorder (inf.content); + + Accordion.Item item = this.accordion.add (this.createHeader (inf.title, + inf.iconType), + null, + inf.content, + UIUtils.createHelpTextPane (inf.help, + this.viewer)); + + this.sections.put (sect, + item); + + } + + this.accordion.add (Box.createVerticalGlue ()); + + this.accordion.setAllSectionsOpen (false); + + SwingUtilities.invokeLater (new Runnable () + { + + public void run () + { + + _this.scrollPane.getVerticalScrollBar ().setValue (0); + + } + + }); + + } + + public void showSection (String name) + { + + if (name == null) + { + + return; + + } + + this.showSection (Section.valueOf (name)); + + } + + public void showSection (Section name) + { + + final Options _this = this; + final Accordion.Item item = this.sections.get (name); + + if (item != null) + { + + item.setOpenContentVisible (true); + + this.validate (); + this.repaint (); + + final Border origBorder = item.getBorder (); + + final Color col = UIUtils.getBorderHighlightColor (); + + final int r = col.getRed (); + final int g = col.getGreen (); + final int b = col.getBlue (); + + PropertyChangeListener l = new PropertyChangeListener () + { + + @Override + public void propertyChange (PropertyChangeEvent ev) + { + + Color c = new Color (r, + g, + b, + ((Number) ev.getNewValue ()).intValue ()); + + item.setBorder (new CompoundBorder (new MatteBorder (3, 3, 3, 3, c), + UIUtils.createPadding (3, 3, 3, 3))); + + } + + }; + + final Timer cycle = UIUtils.createCyclicAnimator (l, + l, + 60, + 1500, + 0, + 255, + 2, + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + item.setBorder (origBorder); + + } + + }); + + UIUtils.doLater (new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + _this.scrollPane.scrollRectToVisible (SwingUtilities.convertRectangle (item, + item.getBounds (), + _this.scrollPane)); + + cycle.start (); + + } + + }); + + } + + } + + public SectionInfo getSectionInfo (Section sect) + { + + if (sect == Section.start) + { + + return this.createStartSection (); + + } + + if (sect == Section.warmups) + { + + return this.createWarmupsSection (); + + } + + if (sect == Section.project) + { + + return this.createProjectSection (); + + } + + if (sect == Section.assets) + { + + return this.createAssetsSection (); + + } + + if (sect == Section.look) + { + + return this.createLookSection (); + + } + + if (sect == Section.naming) + { + + return this.createNamingSection (); + + } + + if (sect == Section.editing) + { + + return this.createEditingSection (); + + } + + if (sect == Section.editors) + { + + return this.createEditorsSection (); + + } + + if (sect == Section.itemsAndRules) + { + + return this.createItemsAndRulesSection (); + + } + + if (sect == Section.achievements) + { + + return this.createAchievementsSection (); + + } + + if (sect == Section.problems) + { + + return this.createProblemsSection (); + + } + + if (sect == Section.betas) + { + + return this.createBetasSection (); + + } + + if (sect == Section.website) + { + + return this.createWebsiteSection (); + + } + + return null; + + } + + private SectionInfo createWebsiteSection () + { + + final Options _this = this; +/* +xxx + Box lb = new Box (BoxLayout.X_AXIS); + + uiLangSel.setMaximumSize (uiLangSel.getPreferredSize ()); + + lb.add (uiLangSel); + lb.add (Box.createHorizontalStrut (10)); + + lb.add (feedback); + lb.add (Box.createHorizontalGlue ()); + + c = this.createWrapper (lb); + + box.add (Box.createVerticalStrut (5)); + this.setAsSubItem (c); + + box.add (c); +*/ + Box box = new Box (BoxLayout.Y_AXIS); + + JButton createTrans = UIUtils.createButton (getUIString (options,website,labels,createtranslation), + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + UIUtils.showAddNewWebsiteLanguageStringsPopup (_this.viewer); + + } + + }); + + box.add (Box.createVerticalStrut (10)); + + JButton editTrans = UIUtils.createButton (getUIString (options,lookandsound,labels,edittranslation), + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + UIUtils.showEditWebsiteLanguageStringsSelectorPopup (_this.viewer); + + } + + }); + + JButton[] tbuts = { createTrans, editTrans }; + + JComponent c = this.createWrapper (UIUtils.createButtonBar2 (tbuts, + JComponent.LEFT_ALIGNMENT)); + this.setAsSubItem (c); + + box.add (c); + + return new SectionInfo (getUIString (options,website,title), + "website", + getUIString (options,website,text), + box); + + } + + private SectionInfo createStartSection () + { + + final Options _this = this; + + Box box = new Box (BoxLayout.Y_AXIS); + + final JCheckBox showTips = UIUtils.createCheckBox (getUIString (options,qwstart,labels,showtips)); + //("Show useful tips")); + + final JCheckBox lastCB = UIUtils.createCheckBox (getUIString (options,qwstart,labels,showlastedited)); + // ("Open the last edited {project}")); + + final JCheckBox showCB = UIUtils.createCheckBox (getUIString (options,qwstart,labels,showprojectswindow)); + // ("Show the {Projects} window")); + + showTips.setSelected (UserProperties.getAsBoolean (Constants.SHOW_TIPS_PROPERTY_NAME)); + lastCB.setSelected (UserProperties.getAsBoolean (Constants.OPEN_LAST_EDITED_PROJECT_PROPERTY_NAME)); + showCB.setSelected (UserProperties.getAsBoolean (Constants.SHOW_LANDING_ON_START_PROPERY_NAME)); + + showTips.addItemListener (new ItemAdapter () + { + + public void itemStateChanged (ItemEvent ev) + { + + _this.updateUserProperty (Constants.SHOW_TIPS_PROPERTY_NAME, + showTips.isSelected ()); + + } + + }); + + JComponent c = this.createWrapper (showTips); + this.setAsMainItem (c); + + box.add (c); + + box.add (Box.createVerticalStrut (15)); + + lastCB.addActionListener (new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + if (!lastCB.isSelected ()) + { + + showCB.setSelected (true); + + UserProperties.set (Constants.SHOW_LANDING_ON_START_PROPERY_NAME, + showCB.isSelected ()); + + } + + UserProperties.set (Constants.OPEN_LAST_EDITED_PROJECT_PROPERTY_NAME, + lastCB.isSelected ()); + + } + + }); + + c = this.createWrapper (lastCB); + + this.setAsMainItem (c); + + box.add (c); + + box.add (Box.createVerticalStrut (15)); + + showCB.addActionListener (new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + if (!showCB.isSelected ()) + { + + lastCB.setSelected (true); + + UserProperties.set (Constants.OPEN_LAST_EDITED_PROJECT_PROPERTY_NAME, + lastCB.isSelected ()); + + } + + UserProperties.set (Constants.SHOW_LANDING_ON_START_PROPERY_NAME, + showCB.isSelected ()); + + } + + }); + + c = this.createWrapper (showCB); + + this.setAsMainItem (c); + + box.add (c); + + return new SectionInfo (getUIString (options,qwstart,title), + //"When {QW} starts", + "start", + getUIString (options,qwstart,text), + //"Want to see some tips when {QW} starts? Or maybe open the {project} you last edited? Look no further!", + box); + + } + + private SectionInfo createBetasSection () + { + + final Options _this = this; + + //box.add (this.createHeader (UIUtils.formatForUser ("When something goes wrong"))); + //box.add (Box.createVerticalStrut (5)); + + Box box = new Box (BoxLayout.Y_AXIS); + + final JCheckBox optinToBetas = UIUtils.createCheckBox (getUIString (options,betas,labels,optin)); + //"Opt-in to beta versions (enables auto-send of errors to Quoll Writer support)"); + optinToBetas.setSelected (UserProperties.getAsBoolean (Constants.OPTIN_TO_BETA_VERSIONS_PROPERTY_NAME)); + + optinToBetas.addActionListener (new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + if (optinToBetas.isSelected ()) + { + + UIUtils.showMessage ((PopupsSupported) _this.viewer, + getUIString (options,betas,about,popup,title), + //"About Betas", + getUIString (options,betas,about,popup,text)); + //"Quoll Writer betas are opt-in and are designed to elicit feedback from users. They will be functionally complete and as bug free as possible. However they won't be without issues, so please beware and report any problems you find.

    You can opt out at any time although this will not revert back to a previous version (that is potentially dangerous).

    Note: opting into betas will enable the Send errors to Quoll Writer support option, you can switch this off if you like to prevent errors being sent."); + + _this.sendErrorsToSupport.setSelected (true); + _this.updateUserProperty (Constants.AUTO_SEND_ERRORS_TO_SUPPORT_PROPERTY_NAME, + true); + + + } + + _this.updateUserProperty (Constants.OPTIN_TO_BETA_VERSIONS_PROPERTY_NAME, + optinToBetas.isSelected ()); + + } + + }); + + JComponent c = this.createWrapper (optinToBetas); + + this.setAsMainItem (c); + + box.add (c); + + return new SectionInfo (getUIString (options,betas,title), + //"Beta versions", + Constants.ABOUT_ICON_NAME, + getUIString (options,betas,text), + //"Want to get ahead of the crowd? Or maybe help improve Quoll Writer? This section lets you opt-in to beta versions. But be warned, betas aren't perfect.", + box); + + } + + private SectionInfo createProblemsSection () + { + + final Options _this = this; + + //box.add (this.createHeader (UIUtils.formatForUser ("When something goes wrong"))); + //box.add (Box.createVerticalStrut (5)); + + Box box = new Box (BoxLayout.Y_AXIS); + + this.sendErrorsToSupport = UIUtils.createCheckBox (getUIString (options,errors,labels,send)); + //"Send errors to Quoll Writer support"); + this.sendErrorsToSupport.setSelected (UserProperties.getAsBoolean (Constants.AUTO_SEND_ERRORS_TO_SUPPORT_PROPERTY_NAME)); + + this.sendErrorsToSupport.addActionListener (new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + _this.updateUserProperty (Constants.AUTO_SEND_ERRORS_TO_SUPPORT_PROPERTY_NAME, + sendErrorsToSupport.isSelected ()); + + } + + }); + + JComponent c = this.createWrapper (this.sendErrorsToSupport); + + this.setAsMainItem (c); + + box.add (c); + + return new SectionInfo (getUIString (options,errors,title), + //"When something goes wrong", + Constants.BUG_ICON_NAME, + getUIString (options,errors,text), + //"Quoll Writer isn't perfect and it would be good to know when things cluck up. If you open this section you'll find a single setting that will let you send errors back to the magical worker elfs at Quoll Writer Headquarters located in deepest, darkest suburban Australia. Did you know that every error sent will prevent a Drop Bear attack. It's a serious and very real threat to our native elves.", + box); + + } + + private SectionInfo createAchievementsSection () + { + + java.util.List prefix = Arrays.asList (options,achievements); + + Box box = new Box (BoxLayout.Y_AXIS); + + final AchievementsManager man = Environment.getAchievementsManager (); + + final JCheckBox achievementsOn = UIUtils.createCheckBox (getUIString (prefix,labels,enable)); + //"Enable achievements"); + achievementsOn.setSelected (man.isAchievementsEnabled ()); + + achievementsOn.addActionListener (new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + man.setAchievementsEnabled (achievementsOn.isSelected ()); + + } + + }); + + JComponent c = this.createWrapper (achievementsOn); + + this.setAsMainItem (c); + + box.add (c); + + final JCheckBox achievementSounds = Achievements.createAchievementsSoundEnabledCheckbox (); + //"Play a sound when an achievement is reached"); + achievementSounds.setSelected (man.isSoundEnabled ()); + + final JCheckBox fullScreenSoundsOn = Achievements.createAchievementsSoundEnabledInFullScreenCheckbox (); + //"Play the sound in full screen mode"); + + achievementSounds.addActionListener (new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + man.setSoundEnabled (achievementSounds.isSelected ()); + + fullScreenSoundsOn.setEnabled (achievementSounds.isSelected ()); + + } + + }); + + box.add (Box.createVerticalStrut (15)); + + c = this.createWrapper (achievementSounds); + + this.setAsMainItem (c); + + box.add (c); + + fullScreenSoundsOn.setSelected (man.isSoundsInFullScreenEnabled ()); + + fullScreenSoundsOn.addActionListener (new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + man.setSoundsInFullScreenEnabled (fullScreenSoundsOn.isSelected ()); + + } + + }); + + //box.add (Box.createVerticalStrut (5)); + + c = this.createWrapper (fullScreenSoundsOn); + + this.setAsSubItem (c); + + box.add (c); + + return new SectionInfo (getUIString (prefix,title), + //"Achievements", + Constants.ACHIEVEMENT_ICON_NAME, + getUIString (prefix,text), + //"Are the achievements annoying you? Use this section to switch them off and they will bug you no more you underachiever.", + box); + + } + + private SectionInfo createItemsAndRulesSection () + { + + final Options _this = this; + + //box.add (this.createHeader ("Manage Items & Rules")); + //box.add (Box.createVerticalStrut (10)); + + Box box = new Box (BoxLayout.Y_AXIS); + + // Gaaah.... + boolean isAPV = (this.viewer instanceof AbstractProjectViewer); + + JButton[] buts = new JButton[ (isAPV ? 3 : 2) ]; + + JButton b = UIUtils.createButton (getUIString (objectnames,plural, Note.NOTE_TYPE_OBJECT_TYPE)); + //"{Note} Types")); + + b.addActionListener (new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + _this.viewer.showEditNoteTypes (); + + } + + }); + + buts[0] = b; + + b = UIUtils.createButton (getUIString (objectnames,plural, Tag.OBJECT_TYPE)); + //"Tags"); + + b.addActionListener (new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + _this.viewer.showEditTags (); + + } + + }); + + buts[1] = b; + + if (isAPV) + { + + b = UIUtils.createButton (getUIString (options,itemsandrules,labels,problemfinderrules)); + //"Problem Finder Rules"); + + b.addActionListener (new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + ((ProjectViewer) _this.viewer).showProblemFinderRuleConfig (); + + } + + }); + + buts[2] = b; + + } + + JPanel bp = UIUtils.createButtonBar2 (buts, + Component.LEFT_ALIGNMENT);//ButtonBarFactory.buildLeftAlignedBar (buts); + bp.setOpaque (false); + + JComponent c = this.createWrapper (bp); + + this.setAsMainItem (c); + + box.add (c); + + return new SectionInfo (getUIString (options,itemsandrules,title), + //"Manage Items & Rules", + Constants.EDIT_ICON_NAME, + getUIString (options,itemsandrules,text), + //"Set up the problem finder rules and manage the note and item types. A dull description but it does exactly what it says on the tin, well screen.", + box); + + } + + private SectionInfo createEditorsSection () + { + + if (EditorsEnvironment.getUserAccount () == null) + { + + return null; + + } + + final Options _this = this; + + Box box = new Box (BoxLayout.Y_AXIS); + + final JCheckBox autoLogin = UIUtils.createCheckBox (getUIString (options,editors,labels,autologin)); + //"Automatically login/go online whenever Quoll Writer starts"); + + autoLogin.setSelected (EditorsEnvironment.getEditorsPropertyAsBoolean (Constants.QW_EDITORS_SERVICE_LOGIN_AT_QW_START_PROPERTY_NAME)); + + autoLogin.addItemListener (new ItemAdapter () + { + + public void itemStateChanged (ItemEvent ev) + { + + try + { + + EditorsEnvironment.setEditorsProperty (Constants.QW_EDITORS_SERVICE_LOGIN_AT_QW_START_PROPERTY_NAME, + autoLogin.isSelected ()); + + } catch (Exception e) { + + Environment.logError ("Unable to set to login at start", + e); + + } + + } + + }); + + JComponent c = this.createWrapper (autoLogin); + this.setAsMainItem (c); + + box.add (c); + + box.add (Box.createVerticalStrut (15)); + + c = this.createHelpText (getUIString (options,editors,labels,defaultstatus)); + //"My default status when I go online is"); + this.setAsMainItem (c); + + box.add (c); + + Vector statuses = new Vector (); + + statuses.add (EditorEditor.OnlineStatus.online); + statuses.add (EditorEditor.OnlineStatus.busy); + statuses.add (EditorEditor.OnlineStatus.away); + statuses.add (EditorEditor.OnlineStatus.snooze); + + final JComboBox defStatus = new JComboBox (statuses); + + String defOnlineStatus = EditorsEnvironment.getEditorsProperty (Constants.QW_EDITORS_SERVICE_DEFAULT_ONLINE_STATUS_PROPERTY_NAME); + + if (defOnlineStatus != null) + { + + defStatus.setSelectedItem (EditorEditor.OnlineStatus.valueOf (defOnlineStatus)); + + } + + defStatus.addItemListener (new ItemAdapter () + { + + public void itemStateChanged (ItemEvent ev) + { + + if (ev.getStateChange () != ItemEvent.SELECTED) + { + + return; + + } + + try + { + + EditorsEnvironment.setEditorsProperty (Constants.QW_EDITORS_SERVICE_DEFAULT_ONLINE_STATUS_PROPERTY_NAME, + ((EditorEditor.OnlineStatus) defStatus.getSelectedItem ()).getType ()); + + } catch (Exception e) { + + Environment.logError ("Unable to set default online status", + e); + + } + + } + + }); + + defStatus.setRenderer (new DefaultListCellRenderer () + { + + public Component getListCellRendererComponent (JList list, + Object value, + int index, + boolean isSelected, + boolean cellHasFocus) + { + + JLabel l = (JLabel) super.getListCellRendererComponent (list, + value, + index, + isSelected, + cellHasFocus); + + EditorEditor.OnlineStatus status = (EditorEditor.OnlineStatus) value; + + String iconName = status.getType (); + + l.setText (status.getName ()); + l.setBorder (UIUtils.createPadding (3, 3, 3, 3)); + l.setIcon (Environment.getIcon (Constants.ONLINE_STATUS_ICON_NAME_PREFIX + iconName, + Constants.ICON_POPUP)); + + return l; + + } + + }); + + c = this.createWrapper (defStatus); + this.setAsSubItem (c); + + box.add (c); + + box.add (Box.createVerticalStrut (15)); + + final JCheckBox fullScreen = UIUtils.createCheckBox (getUIString (options,editors,labels,fullscreenbusystatus)); + //"Set my status to Busy when I enter full screen mode"); + + fullScreen.setSelected (EditorsEnvironment.getEditorsPropertyAsBoolean (Constants.QW_EDITORS_SERVICE_SET_BUSY_ON_FULL_SCREEN_ENTERED_PROPERTY_NAME)); + + fullScreen.addItemListener (new ItemAdapter () + { + + public void itemStateChanged (ItemEvent ev) + { + + try + { + + EditorsEnvironment.setEditorsProperty (Constants.QW_EDITORS_SERVICE_SET_BUSY_ON_FULL_SCREEN_ENTERED_PROPERTY_NAME, + fullScreen.isSelected ()); + + if (fullScreen.isSelected ()) + { + + if (Environment.isInFullScreen ()) + { + + EditorsEnvironment.fullScreenEntered (); + + } + + } + + } catch (Exception e) { + + Environment.logError ("Unable to set to busy on full screen entered", + e); + + } + + } + + }); + + c = this.createWrapper (fullScreen); + this.setAsMainItem (c); + + box.add (c); + + box.add (Box.createVerticalStrut (15)); + + final JCheckBox logMessages = UIUtils.createCheckBox (getUIString (options,editors,labels,logmessages,text)); + //"Log messages I send/receive (debug only)"); + + logMessages.addItemListener (new ItemAdapter () + { + + public void itemStateChanged (ItemEvent ev) + { + + EditorsEnvironment.logEditorMessages (logMessages.isSelected ()); + + } + + }); + + c = this.createWrapper (logMessages); + this.setAsMainItem (c); + + box.add (c); + + c = this.createHelpText (getUIString (options,editors,labels,logmessages,help)); + //"Save messages sent/received to a log file. You should only check this box if Quoll Writer support asks you to. Note: this value is not saved and must be activated everytime you run Quoll Writer."); + this.setAsSubItem (c); + + box.add (c); + + return new SectionInfo (getUIString (options,editors,title), + //"{Editors} Service", + Constants.EDITORS_ICON_NAME, + getUIString (options,editors,text), + //"Options related to the Editors service and how you interact with your {contacts}.", + box); + + } + + private SectionInfo createEditingSection () + { + + final Options _this = this; + + //final AbstractProjectViewer pv = (AbstractProjectViewer) this.viewer; + + //box.add (this.createHeader (UIUtils.formatForUser ("Editing {Chapters}"))); + //box.add (Box.createVerticalStrut (5)); + + Box box = new Box (BoxLayout.Y_AXIS); + + Vector chapterA = new Vector (); + chapterA.add (getUIString (times,mins5)); //Constants.MINS_5); + chapterA.add (getUIString (times,mins10)); //Constants.MINS_10); + chapterA.add (getUIString (times,mins20)); //Constants.MINS_20); + chapterA.add (getUIString (times,mins30)); //Constants.MINS_30); + chapterA.add (getUIString (times,hour1)); //Constants.HOUR_1); + + final JComboBox autosaveAmount = new JComboBox (chapterA); + + final JCheckBox enableAutosave = UIUtils.createCheckBox (getUIString (options,editingchapters,labels,autosave)); + //"Enable {Chapter} Auto-save")); + enableAutosave.setOpaque (false); + enableAutosave.setAlignmentX (Component.LEFT_ALIGNMENT); + + JComponent c = this.createWrapper (enableAutosave); + this.setAsMainItem (c); + + box.add (c); + + final Properties props = Environment.getDefaultProperties (Project.OBJECT_TYPE); + + boolean autosaveEnabled = props.getPropertyAsBoolean (Constants.CHAPTER_AUTO_SAVE_ENABLED_PROPERTY_NAME); + enableAutosave.setSelected (autosaveEnabled); + + long autosaveTime = Utils.getTimeAsMillis (props.getProperty (Constants.CHAPTER_AUTO_SAVE_INTERVAL_PROPERTY_NAME)); + + int selInd = 0; // 5 mins + + if (autosaveTime == (10 * Constants.MIN_IN_MILLIS)) + { + + selInd = 1; + + } + + if (autosaveTime == (20 * Constants.MIN_IN_MILLIS)) + { + + selInd = 2; + + } + + if (autosaveTime == (30 * Constants.MIN_IN_MILLIS)) + { + + selInd = 3; + + } + + if (autosaveTime == (60 * Constants.MIN_IN_MILLIS)) + { + + selInd = 4; + + } + + autosaveAmount.setSelectedIndex (selInd); + //props.getProperty (Constants.CHAPTER_AUTO_SAVE_INTERVAL_PROPERTY_NAME)); + autosaveAmount.setEnabled (enableAutosave.isSelected ()); + + enableAutosave.addItemListener (new ItemAdapter () + { + + public void itemStateChanged (ItemEvent ev) + { + + autosaveAmount.setEnabled (enableAutosave.isSelected ()); + + props.setProperty (Constants.CHAPTER_AUTO_SAVE_ENABLED_PROPERTY_NAME, + new BooleanProperty (Constants.CHAPTER_AUTO_SAVE_ENABLED_PROPERTY_NAME, + enableAutosave.isSelected ())); + + // For all the ProjectViewers (where text is editable) update the auto save settings. + // TODO Change to use a property on the AbstractProjectViewer. + /* + Environment.doForOpenProjects (Project.NORMAL_PROJECT_TYPE, + new ProjectViewerAction () + { + + public void doAction (ProjectViewer pv) + { + + pv.scheduleAutoSaveForAllEditors (); + + } + + }); +*/ + _this.updateDefaultProjectProperty (Constants.CHAPTER_AUTO_SAVE_ENABLED_PROPERTY_NAME, + enableAutosave.isSelected ()); + + Environment.fireUserProjectEvent (_this, + ProjectEvent.Type.autosave, + (enableAutosave.isSelected () ? ProjectEvent.Action.on : ProjectEvent.Action.off)); + + } + + }); + + autosaveAmount.addItemListener (new ItemAdapter () + { + + public void itemStateChanged (ItemEvent ev) + { + + if (ev.getStateChange () != ItemEvent.SELECTED) + { + + return; + + } + + long time = 5 * Constants.MIN_IN_MILLIS; + + int selInd = autosaveAmount.getSelectedIndex (); + + if (selInd == 1) + { + + time = 10 * Constants.MIN_IN_MILLIS; + + } + + if (selInd == 2) + { + + time = 20 * Constants.MIN_IN_MILLIS; + + } + + if (selInd == 3) + { + + time = 30 * Constants.MIN_IN_MILLIS; + + } + + if (selInd == 4) + { + + time = 60 * Constants.MIN_IN_MILLIS; + + } + + _this.updateDefaultProjectProperty (Constants.CHAPTER_AUTO_SAVE_INTERVAL_PROPERTY_NAME, + String.valueOf (time)); + //(String) autosaveAmount.getSelectedItem ()); + + // For all the ProjectViewers (where text is editable) update the auto save settings. + /* + TODO Change to use a property. + Environment.doForOpenProjects (Project.NORMAL_PROJECT_TYPE, + new ProjectViewerAction () + { + + public void doAction (ProjectViewer pv) + { + + pv.scheduleAutoSaveForAllEditors (); + + } + + }); +*/ + } + + }); + + box.add (Box.createVerticalStrut (15)); + + c = this.createHelpText (getUIString (options,editingchapters,labels,autosavewhen)); + //"Auto-save every"); + this.setAsMainItem (c); + + box.add (c); + + c = this.createWrapper (autosaveAmount); + this.setAsSubItem (c); + + box.add (c); + + box.add (Box.createVerticalStrut (15)); + + c = this.createHelpText (getUIString (options,editingchapters,labels,showicon)); + //"Show an icon against a {chapter} in the {chapter} list when"); + this.setAsMainItem (c); + + box.add (c); + + final JCheckBox showEditPos = UIUtils.createCheckBox (getUIString (options,editingchapters,labels,haseditposition)); + //"it has an edit position")); + showEditPos.setSelected (UserProperties.getAsBoolean (Constants.SHOW_EDIT_POSITION_ICON_IN_CHAPTER_LIST_PROPERTY_NAME)); + showEditPos.setOpaque (false); + showEditPos.setAlignmentX (Component.LEFT_ALIGNMENT); + + showEditPos.addItemListener (new ItemAdapter () + { + + public void itemStateChanged (ItemEvent ev) + { +/* +TODO Change to use a property. + Environment.doForOpenProjects (Project.NORMAL_PROJECT_TYPE, + new ProjectViewerAction () + { + + public void doAction (ProjectViewer pv) + { + + pv.reloadChapterTree (); + + } + + }); +*/ + _this.updateUserProperty (Constants.SHOW_EDIT_POSITION_ICON_IN_CHAPTER_LIST_PROPERTY_NAME, + showEditPos.isSelected ()); + + } + + }); + + c = this.createWrapper (showEditPos); + this.setAsSubItem (c); + + box.add (c); + + final JCheckBox showEdited = UIUtils.createCheckBox (getUIString (options,editingchapters,labels,editcomplete)); + //new JCheckBox (Environment.replaceObjectNames ("it is set as edit complete")); + showEdited.setSelected (UserProperties.getAsBoolean (Constants.SHOW_EDIT_COMPLETE_ICON_IN_CHAPTER_LIST_PROPERTY_NAME)); + showEdited.setOpaque (false); + showEdited.setAlignmentX (Component.LEFT_ALIGNMENT); + + showEdited.addItemListener (new ItemAdapter () + { + + public void itemStateChanged (ItemEvent ev) + { +/* +TODO Change to use a property. + Environment.doForOpenProjects (Project.NORMAL_PROJECT_TYPE, + new ProjectViewerAction () + { + + public void doAction (ProjectViewer pv) + { + + pv.reloadChapterTree (); + + } + + }); +*/ + _this.updateUserProperty (Constants.SHOW_EDIT_COMPLETE_ICON_IN_CHAPTER_LIST_PROPERTY_NAME, + showEdited.isSelected ()); + + } + + }); + + c = this.createWrapper (showEdited); + this.setAsSubItem (c); + + box.add (c); + + box.add (Box.createVerticalStrut (5)); + + final JComponent label = UIUtils.createClickableLabel (getUIString (actions,viewexample), + //"View an example", + null); + + label.addMouseListener (new MouseEventHandler () + { + + public void handlePress (MouseEvent ev) + { + + QPopup popup = _this.viewer.getPopupByName ("edit-complete-example-popup"); + + if (popup == null) + { + + // Create a fake chapter tree. + JTree tree = UIUtils.createTree (); + + tree.setCellRenderer (new ProjectTreeCellRenderer (false) + { + + public boolean showEditPositionIcon () + { + + return true; + + } + + public boolean showEditCompleteIcon () + { + + return true; + + } + + }); + + Book testBook = null; + + try + { + + testBook = Environment.createTestBook (); + + } catch (Exception e) { + + Environment.logError ("Unable to create test book", + e); + + return; + + } + + for (Chapter c : testBook.getChapters ()) + { + + if (testBook.getChapterIndex (c) % 2 == 0) + { + + c.setEditComplete (true); + + } else { + + c.setEditPosition (1); + + } + + } + + tree.setModel (new DefaultTreeModel (UIUtils.createTree (testBook, + null, + null, + false))); + + popup = UIUtils.createClosablePopup (getUIString (names,example), + //"Example", + null, + null); + + popup.setName ("edit-complete-example-popup"); + tree.setBorder (new EmptyBorder (10, 10, 10, 10)); + + popup.setContent (tree); + + popup.setPreferredSize (new Dimension (250, + popup.getPreferredSize ().height)); + + } + + _this.viewer.showPopupAt (popup, + label, + true); + + } + + }); + + c = this.createWrapper (label); + this.setAsSubItem (c); + + box.add (c); + + box.add (Box.createVerticalStrut (15)); + + final JCheckBox showEditMarker = UIUtils.createCheckBox (getUIString (options,editingchapters,labels,showeditposition)); + //"Show the edit position in a {chapter}")); + showEditMarker.setSelected (UserProperties.getAsBoolean (Constants.SHOW_EDIT_MARKER_IN_CHAPTER_PROPERTY_NAME)); + showEditMarker.setOpaque (false); + showEditMarker.setAlignmentX (Component.LEFT_ALIGNMENT); + + showEditMarker.addItemListener (new ItemAdapter () + { + + public void itemStateChanged (ItemEvent ev) + { + + _this.updateUserProperty (Constants.SHOW_EDIT_MARKER_IN_CHAPTER_PROPERTY_NAME, + showEditMarker.isSelected ()); +/* +TODO Change to use a property. + Environment.doForOpenProjectViewers (AbstractProjectViewer.class, + new ProjectViewerAction () + { + + public void doAction (AbstractProjectViewer pv) + { + + pv.doForPanels (QuollEditorPanel.class, + new DefaultQuollPanelAction () + { + + public void doAction (QuollPanel qp) + { + + try + { + + ((QuollEditorPanel) qp).reinitIconColumn (); + + } catch (Exception e) { + + Environment.logError ("Unable to reinit icon column for panel", + e); + + } + + } + + }); + + } + + }); +*/ + } + + }); + + c = this.createWrapper (showEditMarker); + this.setAsMainItem (c); + + box.add (c); + + box.add (Box.createVerticalStrut (5)); + + c = this.createHelpText (getUIString (options,editingchapters,labels,seteditpositioncolor,text)); + //"Use the following color for the edit position indicator"); + this.setAsSubItem (c); + + box.add (c); + + final Color col = UIUtils.getColor (UserProperties.get (Constants.EDIT_MARKER_COLOR_PROPERTY_NAME)); + + final JPanel cSwatch = QColorChooser.getSwatch (col); + + UIUtils.setAsButton (cSwatch); + + cSwatch.addMouseListener (new MouseAdapter () + { + + public void mouseReleased (MouseEvent ev) + { + + QPopup popup = QColorChooser.getColorChooserPopup (getUIString (options,editingchapters,labels,seteditpositioncolor, LanguageStrings.popup,title), + //"Select the edit indicator color", + col, + Constants.EDIT_MARKER_COLOR_PROPERTY_NAME, + new ChangeAdapter () + { + + public void stateChanged (ChangeEvent ev) + { + + Color c = (Color) ev.getSource (); + + _this.updateUserProperty (Constants.EDIT_MARKER_COLOR_PROPERTY_NAME, + UIUtils.colorToHex (c)); + +/* +TODO Remove, now handled by a listener in the icon column and a property in UserProperties. + Environment.doForOpenProjectViewers (AbstractProjectViewer.class, + new ProjectViewerAction () + { + + public void doAction (AbstractProjectViewer pv) + { + + pv.doForPanels (QuollEditorPanel.class, + new DefaultQuollPanelAction () + { + + public void doAction (QuollPanel qp) + { + + try + { + + ((QuollEditorPanel) qp).reinitIconColumn (); + + } catch (Exception e) { + + Environment.logError ("Unable to reinit icon column for panel", + e); + + } + + } + + }); + + } + + }); +*/ + cSwatch.setBackground (c); + + } + + }, + new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { +/* + QPopup p = _this.popups.remove ("textcolor"); + + p.removeFromParent (); + */ + } + + }); + + popup.setDraggable (_this.viewer); + + _this.viewer.showPopupAt (popup, + cSwatch, + true); + + } + + }); + + c = this.createWrapper (cSwatch); + this.setAsSubItem (c); + + box.add (c); + + box.add (Box.createVerticalStrut (5)); + + final JComponent label2 = UIUtils.createClickableLabel (getUIString (actions,viewexample), + //"View an example", + null); + + label2.addMouseListener (new MouseEventHandler () + { + + @Override + public void handlePress (MouseEvent ev) + { + + QPopup popup = _this.viewer.getPopupByName ("edit-position-example-popup"); + + if (popup == null) + { + + popup = UIUtils.createClosablePopup (getUIString (names,example), + //"Example", + null, + null); + + popup.setName ("edit-position-example-popup"); + ImagePanel ip = new ImagePanel (Environment.getImage (Constants.EDIT_POSITION_TEST_IMAGE), + null); + + popup.setContent (ip); + + } + + _this.viewer.showPopupAt (popup, + label2, + true); + + } + + }); + + c = this.createWrapper (label2); + this.setAsSubItem (c); + + box.add (c); + + box.add (Box.createVerticalStrut (15)); + + final JCheckBox markEdited = UIUtils.createCheckBox (getUIString (options,editingchapters,labels,seteditcompleteatchapterend)); + //"Set a {chapter} as edit complete when the edit position is at the end of the {chapter}")); + markEdited.setOpaque (false); + markEdited.setSelected (UserProperties.getAsBoolean (Constants.SET_CHAPTER_AS_EDIT_COMPLETE_WHEN_EDIT_POSITION_IS_AT_END_OF_CHAPTER_PROPERTY_NAME)); + markEdited.setAlignmentX (Component.LEFT_ALIGNMENT); + + markEdited.addItemListener (new ItemAdapter () + { + + public void itemStateChanged (ItemEvent ev) + { + + _this.updateUserProperty (Constants.SET_CHAPTER_AS_EDIT_COMPLETE_WHEN_EDIT_POSITION_IS_AT_END_OF_CHAPTER_PROPERTY_NAME, + markEdited.isSelected ()); +/* +TODO Change to use a property. + Environment.doForOpenProjectViewers (AbstractProjectViewer.class, + new ProjectViewerAction () + { + + public void doAction (final AbstractProjectViewer pv) + { + + pv.doForPanels (AbstractEditorPanel.class, + new DefaultQuollPanelAction () + { + + public void doAction (QuollPanel qp) + { + + AbstractEditorPanel p = (AbstractEditorPanel) qp; + + if (p == null) + { + + return; + + } + + try + { + + Chapter c = p.getChapter (); + + if (c.getEditPosition () > 0) + { + + pv.setChapterEditPosition (c, + c.getEditPosition ()); + + } + + } catch (Exception e) { + + Environment.logError ("Unable to set edit position for chapter: " + + p.getChapter (), + e); + + } + + } + + }); + + } + + }); +*/ + } + + }); + + c = this.createWrapper (markEdited); + this.setAsMainItem (c); + + box.add (c); + + box.add (Box.createVerticalStrut (15)); + + final JCheckBox compressMenu = UIUtils.createCheckBox (getUIString (options,editingchapters,labels,compressrightclickmenu)); + //"Compress the {chapter} right click menu")); + compressMenu.setOpaque (false); + compressMenu.setSelected (UserProperties.getAsBoolean (Constants.COMPRESS_CHAPTER_CONTEXT_MENU_PROPERTY_NAME)); + compressMenu.setAlignmentX (Component.LEFT_ALIGNMENT); + + compressMenu.addItemListener (new ItemAdapter () + { + + public void itemStateChanged (ItemEvent ev) + { + + _this.updateUserProperty (Constants.COMPRESS_CHAPTER_CONTEXT_MENU_PROPERTY_NAME, + compressMenu.isSelected ()); + + } + + }); + + c = this.createWrapper (compressMenu); + this.setAsMainItem (c); + + box.add (c); + + box.add (Box.createVerticalStrut (5)); + + final JLabel label3 = UIUtils.createClickableLabel (getUIString (actions,viewexample), + //"View an example", + null); + + label3.addMouseListener (new MouseEventHandler () + { + + @Override + public void handlePress (MouseEvent ev) + { + + String img = Constants.COMPRESSED_CHAPTER_CONTEXT_MENU_IMAGE; + String name = "compress-chapter-menu-example-popup"; + + if (!compressMenu.isSelected ()) + { + + img = Constants.NONE_COMPRESSED_CHAPTER_CONTEXT_MENU_IMAGE; + + name = "no-compress-chapter-menu-example-popup"; + + } + + QPopup popup = _this.viewer.getPopupByName (name); + + if (popup == null) + { + + popup = UIUtils.createClosablePopup (getUIString (names,example), + //"Example", + null, + null); + + ImagePanel ip = new ImagePanel (Environment.getImage (img), + null); + + popup.setName (name); + popup.setContent (ip); + + popup.setDraggable (_this.viewer); + + } + + _this.viewer.showPopupAt (popup, + label3, + true); + + } + + }); + + c = this.createWrapper (label3); + + this.setAsSubItem (c); + + box.add (c); + + box.add (Box.createVerticalStrut (15)); + + c = this.createHelpText (getUIString (options,editingchapters,labels,setspellcheckerlanguage)); + //"Use the following language for the spellchecker"); + this.setAsMainItem (c); + + box.add (c); + + final JComponent downloadFiles = UIUtils.createClickableLabel (getUIString (options,editingchapters,labels,downloadlanguagefiles), + //"Download the language files", + null); + + if (this.viewer instanceof AbstractProjectViewer) + { + + AbstractProjectViewer pv = (AbstractProjectViewer) this.viewer; + + try + { + + downloadFiles.setVisible (!DictionaryProvider.isLanguageInstalled (pv.getSpellCheckLanguage ())); + + } catch (Exception e) { + + // Ignore. + + } + + } else { + + downloadFiles.setVisible (!DictionaryProvider.isLanguageInstalled (UserProperties.get (Constants.SPELL_CHECK_LANGUAGE_PROPERTY_NAME))); + + } + + final JCheckBox defLang = UIUtils.createCheckBox (getUIString (options,editingchapters,labels,setasdefaultlanguage)); + //"Set as default language")); + + final JComboBox spellcheckLang = new JComboBox (); + + // Get the languages supported by the spellchecker. + new Thread (new Runnable () + { + + public void run () + { + + String l = null; + + try + { + + l = Utils.getUrlFileAsString (new URL (Environment.getQuollWriterWebsite () + "/" + UserProperties.get (Constants.QUOLL_WRITER_SUPPORTED_LANGUAGES_URL_PROPERTY_NAME))); + + } catch (Exception e) { + + // Something gone wrong, so just add english. + l = Constants.ENGLISH; + + Environment.logError ("Unable to get language files url", + e); + + } + + StringTokenizer t = new StringTokenizer (l, + String.valueOf ('\n')); + + final Vector langs = new Vector (); + + while (t.hasMoreTokens ()) + { + + String lang = t.nextToken ().trim (); + + if (lang.equals ("")) + { + + continue; + + } + + langs.add (lang); + + } + + UIUtils.doLater (new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + spellcheckLang.setModel (new DefaultComboBoxModel (langs)); + + String def = UserProperties.get (Constants.SPELL_CHECK_LANGUAGE_PROPERTY_NAME); + + if (_this.viewer instanceof AbstractProjectViewer) + { + + AbstractProjectViewer pv = (AbstractProjectViewer) _this.viewer; + + spellcheckLang.setSelectedItem (pv.getProject ().getProperty (Constants.SPELL_CHECK_LANGUAGE_PROPERTY_NAME)); + + } else { + + spellcheckLang.setSelectedItem (def); + + } + + spellcheckLang.setEnabled (true); + + boolean isDef = def.equals (spellcheckLang.getSelectedItem ().toString ()); + + defLang.setSelected (isDef); + + } + + }); + + } + + }).start (); + + final ActionListener setLang = new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + String lang = ev.getActionCommand (); + + if (_this.viewer instanceof AbstractProjectViewer) + { + + AbstractProjectViewer pv = (AbstractProjectViewer) _this.viewer; + + _this.updateProjectProperty (Constants.SPELL_CHECK_LANGUAGE_PROPERTY_NAME, + lang); + + try + { + + pv.setSpellCheckLanguage (lang, + true); + + } catch (Exception e) + { + + // Not good but not fatal either. + Environment.logError ("Unable to set spell check language to: " + + lang, + e); + + return; + + } + + if (!lang.equals (pv.getSpellCheckLanguage ())) + { +/* +TODO + pv.fireProjectEventLater (ProjectEvent.Type.spellcheck, + ProjectEvent.Action.changelanguage); +*/ + } + + } + + } + + }; + + downloadFiles.addMouseListener (new MouseEventHandler () + { + + @Override + public void handlePress (MouseEvent ev) + { + + final String lang = spellcheckLang.getSelectedItem ().toString (); + + UIUtils.downloadDictionaryFiles (lang, + _this.viewer, + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + setLang.actionPerformed (new ActionEvent (_this, 0, lang)); + + // Add a notification saying that the language has been set. + // We do this "later" so that the previous notification is removed + // and we don't get an unwanted border. + UIUtils.doLater (new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + _this.viewer.addNotification (String.format (getUIString (options,editingchapters,downloaddictionaryfiles,notification,text), + //"The language files for %s have been downloaded and the project language set.", + lang), + Constants.INFO_ICON_NAME, + 30); + + } + + }); + + } + + }); + + } + + }); + + spellcheckLang.addItemListener (new ItemAdapter () + { + + public void itemStateChanged (ItemEvent ev) + { + + if (ev.getStateChange () != ItemEvent.SELECTED) + { + + return; + + } + + final String lang = spellcheckLang.getSelectedItem ().toString (); + + String def = UserProperties.get (Constants.SPELL_CHECK_LANGUAGE_PROPERTY_NAME); + + final String currLang = def; + + if (UILanguageStrings.isEnglish (def)) + { + + def = Constants.ENGLISH; + + } + + defLang.setSelected (def.equals (lang)); + + if (_this.viewer instanceof AbstractProjectViewer) + { + + AbstractProjectViewer pv = (AbstractProjectViewer) _this.viewer; + + def = pv.getSpellCheckLanguage (); + + } + + if ((!UILanguageStrings.isEnglish (lang)) + && + (!def.equals (lang)) + ) + { + + UIUtils.showMessage (_this.viewer, + getUIString (options,editingchapters,labels,nonenglishwarning)); + //"Please note: when changing the spell check language to something other
    than English the following features will be disabled:
    • Synonym lookups
    • The Problem Finder
    • Readability Indices
    "); + + } + + downloadFiles.setVisible (false); + + // Check to see if the files are available. + try + { + + if (!DictionaryProvider.isLanguageInstalled (lang)) + { + + downloadFiles.setVisible (true); + + java.util.List prefix = Arrays.asList (options,editingchapters,downloaddictionaryfiles,popup); + + UIUtils.createQuestionPopup (_this.viewer, + getUIString (prefix,title), + //"Download dictionary files?", + Constants.DOWNLOAD_ICON_NAME, + String.format (getUIString (prefix,text), + lang), + //"The dictionary files for " + + //lang + + //" need to be downloaded from the Quoll Writer server.

    Would you like to download them now?", + getUIString (prefix,buttons,confirm), + //"Yes, download them", + getUIString (prefix,buttons,cancel), + //null, + new ActionListener () + { + + public void actionPerformed (ActionEvent ev) + { + + UIUtils.downloadDictionaryFiles (lang, + _this.viewer, + setLang); + + } + + }, + new ActionListener () + { + + public void actionPerformed (ActionEvent ev) + { + + spellcheckLang.setSelectedItem (currLang); + + } + + }, + null, + null); + + return; + + } + + } catch (Exception e) { + + Environment.logError ("Unable to get language files for: " + + lang, + e); + + UIUtils.showErrorMessage (_this.viewer, + getUIString (options,editingchapters,downloaddictionaryfiles,actionerror)); + //"Unable to check for dictionary files, please contact Quoll Writer support."); + + return; + + } + + setLang.actionPerformed (new ActionEvent (this, 0, lang)); + + } + + }); + + c = this.createWrapper (spellcheckLang); + this.setAsSubItem (c); + + box.add (c); + + box.add (Box.createVerticalStrut (5)); + + defLang.setOpaque (false); + defLang.setAlignmentX (Component.LEFT_ALIGNMENT); + + defLang.addItemListener (new ItemAdapter () + { + + public void itemStateChanged (ItemEvent ev) + { + + if (!defLang.isSelected ()) + { + + return; + + } + + String lang = spellcheckLang.getSelectedItem ().toString (); + + _this.updateUserProperty (Constants.SPELL_CHECK_LANGUAGE_PROPERTY_NAME, + lang); + + } + + }); + + c = this.createWrapper (defLang); + this.setAsSubItem (c); + + box.add (c); + + box.add (Box.createVerticalStrut (5)); + + c = this.createWrapper (downloadFiles); + this.setAsSubItem (c); + + box.add (c); + + box.add (Box.createVerticalStrut (15)); + + JButton b = UIUtils.createButton (getUIString (options,editingchapters,labels,managedictionary)); + //"Manage your Personal Dictionary"); + + b.addActionListener (new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + _this.viewer.showDictionaryManager (); + + } + + }); + + c = this.createWrapper (b); + this.setAsMainItem (c); + + box.add (c); + + return new SectionInfo (getUIString (options,editingchapters,title), + //"Editing {Chapters}", + Chapter.OBJECT_TYPE, + getUIString (options,editingchapters,text), + //"Everything to do with editing {chapters}. Manage your personal dictionary, the language for the project, set up auto save and how edit positions behave. All this and more for the low, low price of a few clicks.", + box); + + } + + private SectionInfo createNamingSection () + { + + final Options _this = this; + + Box box = new Box (BoxLayout.Y_AXIS); + + final JButton b = UIUtils.createButton (getUIString (options,naming,labels,changenames), + //"Change names", + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + _this.viewer.showObjectTypeNameChanger (); + + } + + }); + + JComponent c = this.createWrapper (b); + + this.setAsMainItem (c); + + box.add (c); + + return new SectionInfo (getUIString (options,naming,title), + //"What things are called", + Constants.CONFIG_ICON_NAME, + getUIString (options,naming,text), + //"Not happy with what things are called? Want to change {chapter} to sausage? What are you waiting for crack this section open and get changing. Yes that's a phrase now.", + box); + + } + + private SectionInfo createLookSection () + { + + final Options _this = this; + + //box.add (this.createHeader ("How things look and sound")); + //box.add (Box.createVerticalStrut (5)); + + Box box = new Box (BoxLayout.Y_AXIS); + + final JButton feedback = UIUtils.createButton (getUIString (options,lookandsound,labels,LanguageStrings.feedback), + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + _this.showSendFeedbackToUIStringsCreator (); + + } + + }); + + boolean showFeedbackB = true; + + UILanguageStrings currUIL = UILanguageStringsManager.getCurrentUILanguageStrings (); + + if ((currUIL.isEnglish ()) + || + (currUIL.isUser ()) + ) + { + + showFeedbackB = false; + + } + + feedback.setVisible (showFeedbackB); + + final JComboBox uiLangSel = UIUtils.getUILanguagesSelector (new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + final String uid = ev.getActionCommand (); + + feedback.setVisible ((!UILanguageStrings.isEnglish (uid)) && (!uid.startsWith ("user-"))); + + if (uid.equals (UserProperties.get (Constants.USER_UI_LANGUAGE_PROPERTY_NAME))) + { + + return; + + } + + UILanguageStrings ls = null; + + try + { + + ls = UILanguageStringsManager.getUILanguageStrings (uid); + + } catch (Exception e) { + + Environment.logError ("Unable to get ui language for: " + uid, + e); + + UIUtils.showErrorMessage (_this, + getUIString (uilanguage,set,actionerror)); + + return; + + } + + ActionListener setLang = new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + try + { + + Environment.setUILanguage (uid); + + UIUtils.showMessage ((PopupsSupported) _this.viewer, + getUIString (uilanguage,set,restartwarning,title), + getUIString (uilanguage,set,restartwarning,text)); + + } catch (Exception e) { + + Environment.logError ("Unable to set ui language to: " + uid, + e); + + UIUtils.showErrorMessage (_this, + getUIString (uilanguage,set,actionerror)); + + } + + } + + }; + + if (ls == null) + { + + UIUtils.showMessage ((PopupsSupported) _this.viewer, + getUIString (uilanguage,set,downloading,title), + getUIString (uilanguage,set,downloading,text)); +/* +TODO + UILanguageStringsManager.downloadUILanguageFile (uid, + setLang, + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + UIUtils.showErrorMessage (_this, + getUIString (uilanguage,set,actionerror)); + + } + + }); +*/ + } else { + + setLang.actionPerformed (new ActionEvent (_this, 0, "set")); + + } + + } + + }, + UserProperties.get (Constants.USER_UI_LANGUAGE_PROPERTY_NAME)); + + JComponent c = this.createHelpText (getUIString (options,lookandsound,labels,uilanguage)); + this.setAsMainItem (c); + + box.add (c); + + Box lb = new Box (BoxLayout.X_AXIS); + + uiLangSel.setMaximumSize (uiLangSel.getPreferredSize ()); + + lb.add (uiLangSel); + lb.add (Box.createHorizontalStrut (10)); + + lb.add (feedback); + lb.add (Box.createHorizontalGlue ()); + + c = this.createWrapper (lb); + + box.add (Box.createVerticalStrut (5)); + this.setAsSubItem (c); + + box.add (c); + + JButton createTrans = UIUtils.createButton (getUIString (options,lookandsound,labels,createtranslation), + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + UIUtils.showAddNewUILanguageStringsPopup (_this.viewer); + + } + + }); + + box.add (Box.createVerticalStrut (10)); + + JButton editTrans = UIUtils.createButton (getUIString (options,lookandsound,labels,edittranslation), + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + UIUtils.showEditUILanguageStringsSelectorPopup (_this.viewer); + + } + + }); + + JButton[] tbuts = { createTrans, editTrans }; + + c = this.createWrapper (UIUtils.createButtonBar2 (tbuts, + JComponent.LEFT_ALIGNMENT)); + this.setAsSubItem (c); + + box.add (c); + + box.add (Box.createVerticalStrut (15)); + + final JCheckBox keepCB = UIUtils.createCheckBox (getUIString (options,lookandsound,labels,keepprojectswindowsopen)); + // ("Keep the {Projects} window open when a {project} is opened")); + + keepCB.setSelected (!UserProperties.getAsBoolean (Constants.CLOSE_PROJECTS_WINDOW_WHEN_PROJECT_OPENED_PROPERTY_NAME)); + + keepCB.addItemListener (new ItemAdapter () + { + + public void itemStateChanged (ItemEvent ev) + { + + _this.updateUserProperty (Constants.CLOSE_PROJECTS_WINDOW_WHEN_PROJECT_OPENED_PROPERTY_NAME, + !keepCB.isSelected ()); + + } + + }); + + c = this.createWrapper (keepCB); + this.setAsMainItem (c); + + box.add (c); + + box.add (Box.createVerticalStrut (15)); + + final JCheckBox openPWCB = UIUtils.createCheckBox (getUIString (options,lookandsound,labels,showprojectswindownoopenproject)); + //"Show the {Projects} window when I have no open {projects}")); + + openPWCB.setSelected (UserProperties.getAsBoolean (Constants.SHOW_PROJECTS_WINDOW_WHEN_NO_OPEN_PROJECTS_PROPERTY_NAME)); + + openPWCB.addItemListener (new ItemAdapter () + { + + public void itemStateChanged (ItemEvent ev) + { + + _this.updateUserProperty (Constants.SHOW_PROJECTS_WINDOW_WHEN_NO_OPEN_PROJECTS_PROPERTY_NAME, + openPWCB.isSelected ()); + + } + + }); + + c = this.createWrapper (openPWCB); + this.setAsMainItem (c); + + box.add (c); + + box.add (Box.createVerticalStrut (15)); + + final JCheckBox showPrev = UIUtils.createCheckBox (getUIString (options,lookandsound,labels,showpreview)); + //"Show a brief preview of the object when you mouse over its name in the {project} sidebar")); + showPrev.setSelected (UserProperties.getAsBoolean (Constants.SHOW_QUICK_OBJECT_PREVIEW_IN_PROJECT_SIDEBAR_PROPERTY_NAME)); + + showPrev.addItemListener (new ItemAdapter () + { + + public void itemStateChanged (ItemEvent ev) + { + + _this.updateUserProperty (Constants.SHOW_QUICK_OBJECT_PREVIEW_IN_PROJECT_SIDEBAR_PROPERTY_NAME, + showPrev.isSelected ()); + + } + + }); + + c = this.createWrapper (showPrev); + this.setAsMainItem (c); + + box.add (c); + + box.add (Box.createVerticalStrut (5)); + + JButton but = UIUtils.createButton (getUIString (options,lookandsound,labels,changedisplay), + //"Change what is displayed", + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + _this.showEditChapterInfo (); + + } + + }); + + c = this.createWrapper (but); + this.setAsSubItem (c); + + box.add (c); + + box.add (Box.createVerticalStrut (15)); + + final JCheckBox showNotesInChapterList = UIUtils.createCheckBox (getUIString (options,lookandsound,labels,shownotes)); + showNotesInChapterList.setSelected (UserProperties.getAsBoolean (Constants.SHOW_NOTES_IN_CHAPTER_LIST_PROPERTY_NAME)); + + showNotesInChapterList.addItemListener (new ItemAdapter () + { + + public void itemStateChanged (ItemEvent ev) + { + + _this.updateUserProperty (Constants.SHOW_NOTES_IN_CHAPTER_LIST_PROPERTY_NAME, + showNotesInChapterList.isSelected ()); + + // TODO Change to use a property. + /* + Environment.doForOpenProjects (pv -> pv.reloadChapterTree ()); +*/ + } + + }); + + c = this.createWrapper (showNotesInChapterList); + this.setAsMainItem (c); + + box.add (c); + + box.add (Box.createVerticalStrut (15)); + + c = this.createHelpText (getUIString (options,lookandsound,labels,interfacelayout,text)); + this.setAsMainItem (c); + + box.add (c); + + String selLayout = UserProperties.get (Constants.UI_LAYOUT_PROPERTY_NAME); + + final JLabel layoutSel = new JLabel (new LayoutImagePanel (selLayout)); + + UIUtils.setAsButton (layoutSel); + + layoutSel.addMouseListener (new MouseEventHandler () + { + + @Override + public void handlePress (MouseEvent ev) + { + + String selLayout = UserProperties.get (Constants.UI_LAYOUT_PROPERTY_NAME); + + final QPopup qp = UIUtils.createClosablePopup (getUIString (options,lookandsound,labels,interfacelayout,popup,title), + //"Select a layout", + Environment.getIcon (Constants.EDIT_ICON_NAME, + Constants.ICON_POPUP), + null); + + Box content = new Box (BoxLayout.Y_AXIS); + + Vector layoutTypes = new Vector (); + layoutTypes.add (Constants.LAYOUT_PS_CH); + layoutTypes.add (Constants.LAYOUT_CH_PS); + layoutTypes.add (Constants.LAYOUT_PS_CH_OS); + layoutTypes.add (Constants.LAYOUT_OS_CH_PS); + layoutTypes.add (Constants.LAYOUT_PS_OS_CH); + layoutTypes.add (Constants.LAYOUT_CH_OS_PS); + + final JList layoutL = new JList (layoutTypes); + + layoutL.setSelectedValue (selLayout, + false); + + layoutL.setToolTipText (getUIString (options,lookandsound,labels,interfacelayout,popup,tooltip)); + //"Click to select a layout"); + layoutL.addListSelectionListener (new ListSelectionListener () + { + + public void valueChanged (ListSelectionEvent ev) + { + + final String layout = layoutL.getSelectedValue (); + + layoutSel.setIcon (new LayoutImagePanel (layout)); + + qp.removeFromParent (); + + _this.updateUserProperty (Constants.UI_LAYOUT_PROPERTY_NAME, + layout); + +/* +TODO Remove, should be handled by the viewer. + Environment.doForOpenProjectViewers (AbstractProjectViewer.class, + new ProjectViewerAction () + { + + public void doAction (AbstractProjectViewer pv) + { + + pv.setUILayout (layout); + + } + + }); +*/ + Environment.fireUserProjectEvent (_this, + ProjectEvent.Type.layout, + ProjectEvent.Action.changed); + + } + + }); + + layoutL.setCellRenderer (new DefaultListCellRenderer () + { + + private Map images = new HashMap (); + + public Component getListCellRendererComponent (JList list, + Object value, + int index, + boolean isSelected, + boolean cellHasFocus) + { + + super.getListCellRendererComponent (list, + value, + index, + isSelected, + cellHasFocus); + + String imName = value.toString (); + + this.setIcon (new LayoutImagePanel (imName)); + this.setText (String.format ("%s", + getUIString (options,lookandsound,interfacelayouts,imName))); + //Environment.replaceObjectNames (text))); + this.setBorder (UIUtils.createPadding (5, 3, 5, 3)); + this.setVerticalTextPosition (SwingConstants.TOP); + + if (isSelected) + { + + this.setBorder (new CompoundBorder (UIUtils.createLineBorder (), + this.getBorder ())); + + } + + return this; + + } + + }); + + UIUtils.setAsButton (layoutL); + + content.add (layoutL); + content.setBorder (UIUtils.createPadding (10, 10, 10, 10)); + qp.setContent (content); + + content.setPreferredSize (new Dimension (UIUtils.getPopupWidth (), + content.getPreferredSize ().height)); + + _this.viewer.showPopupAt (qp, + UIUtils.getCenterShowPosition (_this.viewer, + qp), + false); + + qp.setDraggable (_this.viewer); + + } + + }); + + c = this.createWrapper (layoutSel); + + box.add (Box.createVerticalStrut (5)); + + this.setAsSubItem (c); + + box.add (c); + + box.add (Box.createVerticalStrut (15)); + + c = this.createHelpText (getUIString (options,lookandsound,labels,showtoolbar)); + //"Show the toolbar"); + this.setAsMainItem (c); + + box.add (c); + + Vector v = new Vector (); + v.add (getUIString (options,lookandsound,labels,abovesidebar)); + //"Above the sidebar")); + v.add (getUIString (options,lookandsound,labels,belowsidebar)); + //"Below the sidebar")); + + final JComboBox toolbarLoc = new JComboBox (v); + + String loc = UserProperties.get (Constants.TOOLBAR_LOCATION_PROPERTY_NAME); + + int ind = 0; + + if (loc.equals (Constants.BOTTOM)) + { + + ind = 1; + + } + + toolbarLoc.setSelectedIndex (ind); + + toolbarLoc.addItemListener (new ItemAdapter () + { + + public void itemStateChanged (ItemEvent ev) + { + + if (ev.getStateChange () != ItemEvent.SELECTED) + { + + return; + + } + + String loc = Constants.TOP; + + if (toolbarLoc.getSelectedIndex () == 1) + { + + loc = Constants.BOTTOM; + + } + + if (loc.equals (UserProperties.get (Constants.TOOLBAR_LOCATION_PROPERTY_NAME))) + { + + return; + + } + + final String _loc = loc; + + _this.updateUserProperty (Constants.TOOLBAR_LOCATION_PROPERTY_NAME, + loc); +/* +TODO Remove should be handled by the property in UserProperties. + Environment.doForOpenProjectViewers (AbstractProjectViewer.class, + new ProjectViewerAction () + { + + public void doAction (AbstractProjectViewer pv) + { + + pv.setToolbarLocation (_loc); + + } + + }); +*/ + Environment.fireUserProjectEvent (_this, + ProjectEvent.Type.toolbar, + ProjectEvent.Action.move); + + } + + }); + + c = this.createWrapper (toolbarLoc); + this.setAsSubItem (c); + + box.add (c); + + box.add (Box.createVerticalStrut (15)); + + // Sidebar location + c = this.createHelpText (getUIString (options,lookandsound,labels,showtabs)); + //"Show the tabs"); + this.setAsMainItem (c); + + box.add (c); + + v = new Vector (); + v.add (getUIString (options,lookandsound,labels,showtabstop)); + // ("At the top")); + v.add (getUIString (options,lookandsound,labels,showtabsbottom)); + // ("At the bottom")); + + final JComboBox tabsLoc = new JComboBox (v); + + loc = UserProperties.get (Constants.TABS_LOCATION_PROPERTY_NAME); + + ind = 0; + + if (loc.equals (Constants.BOTTOM)) + { + + ind = 1; + + } + + tabsLoc.setSelectedIndex (ind); + + tabsLoc.addItemListener (new ItemAdapter () + { + + public void itemStateChanged (ItemEvent ev) + { + + if (ev.getStateChange () != ItemEvent.SELECTED) + { + + return; + + } + + String loc = Constants.TOP; + + if (tabsLoc.getSelectedIndex () == 1) + { + + loc = Constants.BOTTOM; + + } + + if (tabsLoc.getSelectedIndex () == 2) + { + + loc = Constants.LEFT; + + } + + if (tabsLoc.getSelectedIndex () == 3) + { + + loc = Constants.RIGHT; + + } + + if (loc.equals (UserProperties.get (Constants.TABS_LOCATION_PROPERTY_NAME))) + { + + return; + + } + + final String _loc = loc; + + _this.updateUserProperty (Constants.TABS_LOCATION_PROPERTY_NAME, + loc); + +/* + TODO Change to use a property in the environment that viewers can listen to. + Environment.doForOpenProjectViewers (AbstractProjectViewer.class, + new ProjectViewerAction () + { + + public void doAction (AbstractProjectViewer pv) + { + + pv.setTabsLocation (_loc); + + } + + }); +*/ + Environment.fireUserProjectEvent (_this, + ProjectEvent.Type.tabs, + ProjectEvent.Action.move); + + } + + }); + + c = this.createWrapper (tabsLoc); + this.setAsSubItem (c); + + box.add (c); + + box.add (Box.createVerticalStrut (15)); + + c = this.createHelpText (getUIString (options,lookandsound,labels,whenfind)); + //"When I do a find"); + this.setAsMainItem (c); + + box.add (c); + + final JRadioButton eachChap = UIUtils.createRadioButton (getUIString (options,lookandsound,labels,expandall)); + //"Expand all {chapters} to show all results"); + final JRadioButton justChap = UIUtils.createRadioButton (getUIString (options,lookandsound,labels,justchapter)); + //"Just show the {chapter}"); + + boolean showEachChapResult = UserProperties.getAsBoolean (Constants.SHOW_EACH_CHAPTER_FIND_RESULT_PROPERTY_NAME); + + eachChap.setSelected (showEachChapResult); + justChap.setSelected (!showEachChapResult); + + ButtonGroup g = new ButtonGroup (); + g.add (eachChap); + g.add (justChap); + + eachChap.addItemListener (new ItemAdapter () + { + + public void itemStateChanged (ItemEvent ev) + { + + UserProperties.set (Constants.SHOW_EACH_CHAPTER_FIND_RESULT_PROPERTY_NAME, + true); + + } + + }); + + justChap.addItemListener (new ItemAdapter () + { + + public void itemStateChanged (ItemEvent ev) + { + + UserProperties.set (Constants.SHOW_EACH_CHAPTER_FIND_RESULT_PROPERTY_NAME, + false); + + } + + }); + + c = this.createWrapper (eachChap); + this.setAsSubItem (c); + + box.add (c); + + c = this.createWrapper (justChap); + this.setAsSubItem (c); + + box.add (c); + + box.add (Box.createVerticalStrut (10)); + + final JCheckBox playSound = UIUtils.createCheckBox (getUIString (options,lookandsound,labels,playtypewritersound,text)); + //"Play a typewriter sound when editing a {chapter}.")); + + boolean playSoundEnabled = UserProperties.getAsBoolean (Constants.PLAY_SOUND_ON_KEY_STROKE_PROPERTY_NAME); + + final FileFinder f = new FileFinder (); + final JButton useB = UIUtils.createButton (getUIString (options,lookandsound,labels,playtypewritersound,buttons,usesound)); + //"Use Sound"); + final JButton testB = UIUtils.createButton (getUIString (options,lookandsound,labels,playtypewritersound,buttons,playsound)); + //"Play Sound"); + + f.setEnabled (playSoundEnabled); + playSound.setOpaque (false); + playSound.addItemListener (new ItemAdapter () + { + + public void itemStateChanged (ItemEvent ev) + { + + boolean sel = playSound.isSelected (); + + f.setEnabled (sel); + + if ((sel) + && + (f.getSelectedFile () != null) + && + (f.getSelectedFile ().exists ()) + ) + { + + useB.setEnabled (true); + + } else { + + useB.setEnabled (false); + + } + + UserProperties.setPlaySoundOnKeyStroke (sel); + + _this.updateUserProperty (Constants.PLAY_SOUND_ON_KEY_STROKE_PROPERTY_NAME, + sel); + + } + + }); + + playSound.setSelected (playSoundEnabled); + + box.add (Box.createVerticalStrut (5)); + + c = this.createWrapper (playSound); + this.setAsMainItem (c); + + box.add (c); + + box.add (Box.createVerticalStrut (5)); + + c = this.createHelpText (getUIString (options,lookandsound,labels,playtypewritersound,selectownwavfile)); + //"Or, select your own WAV file that will be played instead. (Note: only .wav files are supported.)"); + this.setAsSubItem (c); + + box.add (c); + + String sf = UserProperties.get (Constants.KEY_STROKE_SOUND_FILE_PROPERTY_NAME); + + if (sf == null) + { + + sf = ""; + + } + + final String sfv = sf; + + f.setFile (new File (sfv)); + + f.setApproveButtonText (getUIString (options,lookandsound,labels,playtypewritersound,finder,button)); + //"Select"); + f.setFinderSelectionMode (JFileChooser.FILES_ONLY); + f.setFinderTitle (getUIString (options,lookandsound,labels,playtypewritersound,finder,title)); + //"Select a File"); + + f.setFileFilter (new FileNameExtensionFilter (getUIString (options,lookandsound,labels,playtypewritersound,finder,filter), + //"Supported Files (wav)", + "wav")); + + f.setFindButtonToolTip (getUIString (options,lookandsound,labels,playtypewritersound,finder,tooltip)); + //"Click to find a wav file"); + f.setClearOnCancel (true); + f.setMaximumSize (new Dimension (400, + f.getPreferredSize ().height)); + + f.setOnSelectHandler (new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + useB.setEnabled (true); + testB.setEnabled (true); + + } + + }); + + f.showCancel (true, + new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + UserProperties.remove (Constants.KEY_STROKE_SOUND_FILE_PROPERTY_NAME); + + // Reset to the default. + // TODO Environment.setKeyStrokeSoundFile (null); + + useB.setEnabled (false); + testB.setEnabled (false); + + } + + }); + + f.init (); + + boolean sel = (f.getSelectedFile ().exists () && playSoundEnabled); + useB.setEnabled (sel); + testB.setEnabled (sel); + + c = this.createWrapper (f); + this.setAsSubItem (c); + + box.add (c); + + useB.addActionListener (new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + File file = f.getSelectedFile (); + + if ((file != null) + && + (file.exists ()) + ) + { + + try + { + + // TODO Environment.setKeyStrokeSoundFile (file); + + } catch (Exception e) + { + + Environment.logError ("Unable to set key stroke sound file to: " + + file.getPath (), + e); + + UIUtils.showErrorMessage (_this, + getUIString (options,lookandsound,labels,playtypewritersound,actionerror)); + //file.getName () + " is not a valid .wav file."); + + } + + } + + } + + }); + + testB.addActionListener (new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + File file = f.getSelectedFile (); + + try + { + + InputStream is = null; + + if (file != null) + { + + if ((file.exists ()) && + (file.getName ().toLowerCase ().endsWith (".wav"))) + { + + is = new BufferedInputStream (new FileInputStream (file)); + + } else + { + + UIUtils.showErrorMessage (_this, + getUIString (options,lookandsound,labels,playtypewritersound,actionerror)); + //file.getName () + " is not a valid .wav file."); + + return; + + } + + } + + if (is == null) + { + + // Play the default. + is = Utils.getResourceStream (Constants.DEFAULT_KEY_STROKE_SOUND_FILE); + + } + + // Get the clip. + AudioInputStream ais = AudioSystem.getAudioInputStream (is); + + Clip c = AudioSystem.getClip (); + + c.open (ais); + + c.start (); + + } catch (Exception e) + { + + Environment.logError ("Unable to play sound file: " + + file, + e); + + UIUtils.showErrorMessage (_this, + getUIString (options,lookandsound,labels,playtypewritersound,actionerror)); + //"Unable to play sound file."); + + } + + } + + }); + + JButton buts[] = new JButton[2]; + + buts[0] = useB; + buts[1] = testB; + + JPanel bp = UIUtils.createButtonBar2 (buts, + Component.LEFT_ALIGNMENT); //ButtonBarFactory.buildLeftAlignedBar (buts); + bp.setOpaque (false); + + c = this.createWrapper (bp); + + box.add (Box.createVerticalStrut (5)); + + this.setAsSubItem (c); + + box.add (c); + + final JCheckBox highlightSPDivs = UIUtils.createCheckBox (getUIString (options,lookandsound,labels,highlightdividers,text)); + //"Highlight dividers when I move the mouse over them"); + highlightSPDivs.setToolTipText (getUIString (options,lookandsound,labels,highlightdividers,tooltip)); + //"This is for dividers that allow you to slide panels left and right or up and down. It allows you to more easily see the divider."); + + boolean highlight = UserProperties.getAsBoolean (Constants.HIGHLIGHT_SPLITPANE_DIVIDERS_PROPERTY_NAME); + + highlightSPDivs.setSelected (highlight); + + highlightSPDivs.addItemListener (new ItemAdapter () + { + + public void itemStateChanged (ItemEvent ev) + { + + UserProperties.set (Constants.HIGHLIGHT_SPLITPANE_DIVIDERS_PROPERTY_NAME, + highlightSPDivs.isSelected ()); + + } + + }); + + box.add (Box.createVerticalStrut (10)); + + c = this.createWrapper (highlightSPDivs); + this.setAsMainItem (c); + + box.add (c); + + return new SectionInfo (getUIString (options,lookandsound,title), + //"How things look and sound", + "eye", + getUIString (options,lookandsound,text), + //"Want a sound to play whenever a key is pressed? Want to move the tabs or sidebar around? Want to show useful tips when Quoll Writer starts? This is the section for you.", + box); + + } + + private SectionInfo createAssetsSection () + { +/* + if (!(this.viewer instanceof ProjectViewer)) + { + + return null; + + } + */ + final Options _this = this; + + Box box = new Box (BoxLayout.Y_AXIS); + + JComponent c = this.createHelpText (getUIString (options,assets,labels,newasset,text)); + //"Add new Assets ({Characters}, {Locations}, etc) in"); + this.setAsMainItem (c); + + box.add (c); + + final JRadioButton rbAssetInPopup = UIUtils.createRadioButton (getUIString (options,assets,labels,newasset,options,alwayspopup,text)); + //"Always use a Popup"); + rbAssetInPopup.setToolTipText (getUIString (options,assets,labels,newasset,options,alwayspopup,tooltip)); + //"If the Asset has more than just a name and description field then a link will be shown to add the Asset, and thus see all the fields, in a tab instead."); + final JRadioButton rbAssetTryPopup = UIUtils.createRadioButton (getUIString (options,assets,labels,newasset,options,popupifpossible,text)); + //"Use a Popup if possible"); + rbAssetTryPopup.setToolTipText (getUIString (options,assets,labels,newasset,options,popupifpossible,tooltip)); + //"If the Asset only has a name and a description field then a popup will be used, otherwise a tab will be used."); + final JRadioButton rbAssetInTab = UIUtils.createRadioButton (getUIString (options,assets,labels,newasset,options,owntab,text)); + //"Their own tab"); + + String addAsset = UserProperties.get (Constants.ADD_ASSETS_PROPERTY_NAME); + + if (addAsset == null) + { + + addAsset = "popup"; + + } + + rbAssetInPopup.setSelected (addAsset.equals ("popup")); + rbAssetTryPopup.setSelected (addAsset.equals ("trypopup")); + rbAssetInTab.setSelected (addAsset.equals ("tab")); + + ButtonGroup g = new ButtonGroup (); + g.add (rbAssetInPopup); + g.add (rbAssetTryPopup); + g.add (rbAssetInTab); + + rbAssetInPopup.addItemListener (new ItemAdapter () + { + + public void itemStateChanged (ItemEvent ev) + { + + UserProperties.set (Constants.ADD_ASSETS_PROPERTY_NAME, + "popup"); + + } + + }); + + rbAssetTryPopup.addItemListener (new ItemAdapter () + { + + public void itemStateChanged (ItemEvent ev) + { + + UserProperties.set (Constants.ADD_ASSETS_PROPERTY_NAME, + "trypopup"); + + } + + }); + + rbAssetInTab.addItemListener (new ItemAdapter () + { + + public void itemStateChanged (ItemEvent ev) + { + + UserProperties.set (Constants.ADD_ASSETS_PROPERTY_NAME, + "tab"); + + } + + }); + + c = this.createWrapper (rbAssetInPopup); + this.setAsSubItem (c); + + box.add (c); + + c = this.createWrapper (rbAssetTryPopup); + this.setAsSubItem (c); + + box.add (c); + + c = this.createWrapper (rbAssetInTab); + this.setAsSubItem (c); + + box.add (c); + + box.add (Box.createVerticalStrut (15)); + + c = this.createHelpText (getUIString (options,assets,labels,editassetconfig)); + //"Edit the Asset configuration (Layout, Fields, Name, Icon etc)"); + this.setAsMainItem (c); + + box.add (c); + + Vector v = new Vector (); + + for (UserConfigurableObjectType t : Environment.getAssetUserConfigurableObjectTypes (true)) + { + + v.add (t); + + } + + final JComboBox assetTypes = new JComboBox (v); + assetTypes.setEditable (false); + + assetTypes.setRenderer (new DefaultListCellRenderer () + { + + @Override + public Component getListCellRendererComponent (JList list, + Object value, + int index, + boolean isSelected, + boolean cellHasFocus) + { + + super.getListCellRendererComponent (list, + value, + index, + isSelected, + cellHasFocus); + + UserConfigurableObjectType t = (UserConfigurableObjectType) value; + + this.setText (t.getObjectTypeNamePlural ()); + // TODO this.setIcon (t.getIcon16x16 ()); + this.setBorder (UIUtils.createPadding (3, 3, 3, 3)); + + return this; + + } + + }); + + assetTypes.setMaximumSize (assetTypes.getPreferredSize ()); + + Box bb = new Box (BoxLayout.X_AXIS); + + bb.add (assetTypes); + bb.add (Box.createHorizontalStrut (5)); + + JButton editType = UIUtils.createButton (getUIString (buttons,edit), + //"Edit", + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + UserConfigurableObjectType t = (UserConfigurableObjectType) assetTypes.getSelectedItem (); + + UIUtils.showObjectTypeEdit (t, + _this.viewer); + + } + + }); + + bb.add (editType); + bb.add (Box.createHorizontalGlue ()); + + c = this.createWrapper (bb); + this.setAsSubItem (c); + + box.add (c); + + box.add (Box.createVerticalStrut (15)); + +/* + JButton tags = new JButton ("Manage the Tags"); + + tags.addActionListener (new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + _this.viewer.showEditTags (); + + } + + }); +*/ + JButton addType = UIUtils.createButton (getUIString (options,assets,labels,addtype)); + //"Add Type"); + + addType.addActionListener (new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + UIUtils.showAddNewObjectType (_this.viewer); + + } + + }); + + JButton buts[] = new JButton[] { addType }; + + JPanel bp = UIUtils.createButtonBar2 (buts, + Component.LEFT_ALIGNMENT); + bp.setOpaque (false); + + c = this.createWrapper (bp); + + //c = this.createWrapper (mb); + this.setAsMainItem (c); + + box.add (c); + + return new SectionInfo (getUIString (options,assets,title), + //"Assets", + Constants.ASSETS_ICON_NAME, + getUIString (options,assets,text), + ////"Need to add another field to an asset? Manage the tags? Change the names of things, change the icons? This section has you covered, you can also right click on the section header in the sidebar to do this stuff as well.", + box); + + } + + private SectionInfo createProjectSection () + { + + if (!(this.viewer instanceof AbstractProjectViewer)) + { + + return null; + + } + + final Options _this = this; + + final Project proj = ((AbstractProjectViewer) this.viewer).getProject (); + + Box box = new Box (BoxLayout.Y_AXIS); + + final JButton b = UIUtils.createButton (getUIString (options,projectandbackup,labels,selectprojectdir,finder,label)); + //"Change"); + + final FileFinder f = UIUtils.createFileFind (proj.getProjectDirectory ().getParentFile ().getPath (), + getUIString (options,projectandbackup,labels,selectprojectdir,finder,title), + //"Select a Directory", + JFileChooser.DIRECTORIES_ONLY, + getUIString (options,projectandbackup,labels,selectprojectdir,finder,button), + //"Select", + null); + f.setFindButtonToolTip (getUIString (options,projectandbackup,labels,selectprojectdir,finder,tooltip)); + //"Click to find a new {project} directory")); + f.setMaximumSize (new Dimension (400, + f.getPreferredSize ().height)); + + f.setOnSelectHandler (new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + b.setEnabled (!f.getSelectedFile ().getPath ().equals (proj.getProjectDirectory ().getParentFile ().getPath ())); + + } + + }); + + JComponent c = this.createHelpText (getUIString (options,projectandbackup,labels,selectprojectdir,text)); + //"Select the directory where your {project} is stored"); + this.setAsMainItem (c); + + box.add (c); + + c = this.createWrapper (f); + this.setAsSubItem (c); + + box.add (c); + + box.add (Box.createVerticalStrut (5)); + + b.setEnabled (false); + + b.addActionListener (new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + _this.handleProjectDirChange (f); + + } + + }); + + c = this.createWrapper (b); + this.setAsSubItem (c); + + box.add (c); + + box.add (Box.createVerticalStrut (15)); + + Vector backupsA = new Vector (); + backupsA.add (getUIString (times,hours12)); //Constants.HOURS_12); + backupsA.add (getUIString (times,hours24)); //Constants.HOURS_24); + backupsA.add (getUIString (times,days2)); //Constants.DAYS_2); + backupsA.add (getUIString (times,days5)); //Constants.DAYS_5); + backupsA.add (getUIString (times,week1)); //Constants.WEEK_1); + + final JComboBox backupsAmount = new JComboBox (backupsA); + + Vector vals = new Vector (); + vals.add (Environment.formatNumber (10)); //Constants.COUNT_10); + vals.add (Environment.formatNumber (20)); //Constants.COUNT_20); + vals.add (Environment.formatNumber (50)); //Constants.COUNT_50); + vals.add (getUIString (options,projectandbackup,labels,all)); //Constants.COUNT_ALL); + + final JComboBox backupsCount = new JComboBox (vals); + + int count = -1; + + String backupsKeep = proj.getProperty (Constants.BACKUPS_TO_KEEP_COUNT_PROPERTY_NAME); + + // Pre 2.6.5 + if ((backupsKeep != null) + && + (backupsKeep.equals ("All")) + ) + { + + try + { + + count = Integer.parseInt (backupsKeep); + + } catch (Exception e) { + + Environment.logError ("Unable to convert property: " + + Constants.BACKUPS_TO_KEEP_COUNT_PROPERTY_NAME + + " with value: " + + backupsKeep + + " to an int.", + e); + + } + + } + + int selInd = 3; + + if (count == 10) + { + + selInd = 0; + + } + + if (count == 20) + { + + selInd = 1; + + } + + if (count == 50) + { + + selInd = 2; + + } + + backupsCount.setSelectedIndex (selInd); + //proj.getProperty (Constants.BACKUPS_TO_KEEP_COUNT_PROPERTY_NAME)); + + backupsCount.addItemListener (new ItemAdapter () + { + + public void itemStateChanged (ItemEvent ev) + { + + if (ev.getStateChange () != ItemEvent.SELECTED) + { + + return; + + } + + int selInd = backupsCount.getSelectedIndex (); + + int count = 10; + + if (selInd == 1) + { + + count = 20; + + } + + if (selInd == 2) + { + + count = 50; + + } + + if (selInd == 3) + { + + count = -1; + + } + + _this.updateDefaultProjectProperty (Constants.BACKUPS_TO_KEEP_COUNT_PROPERTY_NAME, + String.valueOf (count)); + //(String) backupsCount.getSelectedItem ()); + + if (count > -1) + { + + try + { + + AbstractProjectViewer pv = (AbstractProjectViewer) _this.viewer; + + pv.getObjectManager ().pruneBackups (pv.getProject (), + count); + //Utils.getCountAsInt ((String) backupsCount.getSelectedItem ())); + + } catch (Exception e) { + + Environment.logError ("Unable to prune backups for project: " + + proj, + e); + + } + + } + + } + + }); + + final JCheckBox enableBackups = UIUtils.createCheckBox (getUIString (options,projectandbackup,labels,autobackup)); + //"Automatically create backups of the {project}"); + enableBackups.setOpaque (false); + + c = this.createWrapper (enableBackups); + this.setAsMainItem (c); + + box.add (c); + + box.add (Box.createVerticalStrut (5)); + + boolean backupsEnabled = proj.getPropertyAsBoolean (Constants.AUTO_SNAPSHOTS_ENABLED_PROPERTY_NAME); + enableBackups.setSelected (backupsEnabled); + + long backupsTime = Utils.getTimeAsMillis (proj.getProperty (Constants.AUTO_SNAPSHOTS_TIME_PROPERTY_NAME)); + + int btInd = 0; // 12 hours + + if (backupsTime == (24 * Constants.HOUR_IN_MILLIS)) + { + + btInd = 1; + + } + + if (backupsTime == (2 * Constants.DAY_IN_MILLIS)) + { + + btInd = 2; + + } + + if (backupsTime == (5 * Constants.DAY_IN_MILLIS)) + { + + btInd = 3; + + } + + if (backupsTime == (7 * Constants.DAY_IN_MILLIS)) + { + + btInd = 4; + + } + + backupsAmount.setSelectedIndex (btInd); + // (proj.getProperty (Constants.AUTO_SNAPSHOTS_TIME_PROPERTY_NAME)); + backupsAmount.setEnabled (backupsEnabled); + + backupsAmount.addItemListener (new ItemAdapter () + { + + public void itemStateChanged (ItemEvent ev) + { + + if (ev.getStateChange () != ItemEvent.SELECTED) + { + + return; + + } + + int selInd = backupsAmount.getSelectedIndex (); + + long time = 0; + + if (selInd == 0) + { + + time = 12 * Constants.HOUR_IN_MILLIS; + + } + + if (selInd == 1) + { + + time = 24 * Constants.HOUR_IN_MILLIS; + + } + + if (selInd == 2) + { + + time = 2 * Constants.DAY_IN_MILLIS; + + } + + if (selInd == 3) + { + + time = 5 * Constants.DAY_IN_MILLIS; + + } + + if (selInd == 4) + { + + time = 7 * Constants.DAY_IN_MILLIS; + + } + + _this.updateDefaultProjectProperty (Constants.AUTO_SNAPSHOTS_TIME_PROPERTY_NAME, + String.valueOf (time)); + + } + + }); + + c = this.createHelpText (getUIString (options,projectandbackup,labels,createbackupafter)); + //"Create a new backup after the following time between sessions or during a session"); + this.setAsSubItem (c); + + box.add (c); + + c = this.createWrapper (backupsAmount); + this.setAsSubItem2 (c); + + box.add (c); + + box.add (Box.createVerticalStrut (10)); + + c = this.createHelpText (getUIString (options,projectandbackup,labels,nobackupstokeep)); + //"Number of backups to keep (oldest are deleted first)"); + this.setAsMainItem (c); + + box.add (c); + + c = this.createWrapper (backupsCount); + this.setAsSubItem (c); + + box.add (c); + + final JButton bb = UIUtils.createButton (getUIString (options,projectandbackup,labels,selectbackupdir,finder,label)); + //"Change"); + + final FileFinder bf = UIUtils.createFileFind (proj.getBackupDirectory ().getPath (), + getUIString (options,projectandbackup,labels,selectbackupdir,finder,title), + //"Select a Directory", + JFileChooser.DIRECTORIES_ONLY, + getUIString (options,projectandbackup,labels,selectbackupdir,finder,button), + //"Select", + null); + bf.setFindButtonToolTip (getUIString (options,projectandbackup,labels,selectbackupdir,finder,tooltip)); + // ("Click to find a new backup directory")); + bf.setMaximumSize (new Dimension (400, + bf.getPreferredSize ().height)); + + bf.setOnSelectHandler (new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + bb.setEnabled (!bf.getSelectedFile ().getPath ().equals (proj.getBackupDirectory ().getPath ())); + + } + + }); + + enableBackups.addItemListener (new ItemAdapter () + { + + public void itemStateChanged (ItemEvent ev) + { + + boolean sel = enableBackups.isSelected (); + + backupsAmount.setEnabled (sel); + + _this.updateDefaultProjectProperty (Constants.AUTO_SNAPSHOTS_ENABLED_PROPERTY_NAME, + sel); + + } + + }); + + box.add (Box.createVerticalStrut (10)); + + c = this.createHelpText (getUIString (options,projectandbackup,labels,selectbackupdir,text)); + //"Select the directory where {project} backups are stored"); + this.setAsMainItem (c); + + box.add (c); + + c = this.createWrapper (bf); + this.setAsSubItem (c); + + box.add (c); + + box.add (Box.createVerticalStrut (5)); + + bb.setEnabled (false); + + bb.addActionListener (new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + _this.handleBackupsDirChange (bf); + + } + + }); + + c = this.createWrapper (bb); + this.setAsSubItem (c); + + box.add (c); + + box.add (Box.createVerticalStrut (10)); + + JButton create = UIUtils.createButton (getUIString (options,projectandbackup,labels,createbackup), + //Constants.CREATE_BACKUP_BUTTON_LABEL_ID, + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + UIUtils.showCreateBackup (proj, + null, + _this.viewer); + + } + + }); + + JButton manage = UIUtils.createButton (getUIString (options,projectandbackup,labels,managebackups), + //"Manage Backups", + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + UIUtils.showManageBackups (Environment.getProjectInfo (proj), + _this.viewer); + + } + + }); + + JButton buts[] = new JButton[] { create, manage }; + + JPanel bp = UIUtils.createButtonBar2 (buts, + Component.LEFT_ALIGNMENT); + bp.setOpaque (false); + + c = this.createWrapper (bp); + + //c = this.createWrapper (mb); + this.setAsMainItem (c); + + box.add (c); + + return new SectionInfo (getUIString (options,projectandbackup,title), + //"{Project} & Backups", + Constants.PROJECT_ICON_NAME, + getUIString (options,projectandbackup,text), + //"Click the title above to open this section. You can then change where your {project} is stored and how often backups are created and where they are stored.", + box); + + } + + private SectionInfo createWarmupsSection () + { + + final Options _this = this; + + //box.add (this.createHeader (UIUtils.formatForUser ("{Warmups}"))); + //box.add (Box.createVerticalStrut (5)); + + Box box = new Box (BoxLayout.Y_AXIS); + + JComponent c = this.createWrapper (WarmupPromptSelect.getDoWarmupOnStartupCheckbox ()); + this.setAsMainItem (c); + + box.add (c); + + box.add (Box.createVerticalStrut (5)); + + // Use the standard warmup strings. + + c = this.createHelpText (getUIString (options,warmups,labels,dofor)); + //"And do the {warmup} for"); + this.setAsSubItem (c); + + box.add (c); + + FormLayout fl = new FormLayout ("p, 6px, p, 6px, p, 6px, p", + "p"); + + PanelBuilder builder = new PanelBuilder (fl); + + CellConstraints cc = new CellConstraints (); + + final JComboBox words = WarmupPromptSelect.getWordsOptions (); + + builder.add (words, + cc.xy (1, + 1)); + + builder.addLabel (getUIString (options,warmups,labels,andor), + //"and/or", + cc.xy (3, + 1)); + + final JComboBox mins = WarmupPromptSelect.getTimeOptions (); + + builder.add (mins, + cc.xy (5, + 1)); + + builder.addLabel (getUIString (options,warmups,labels,whicheverfirst), + //"(whichever is reached first)", + cc.xy (7, + 1)); + + JPanel p = builder.getPanel (); + p.setOpaque (false); + p.setAlignmentX (Component.LEFT_ALIGNMENT); + + c = this.createWrapper (p); + this.setAsSubItem (c); + + box.add (c); + + //this.setContentBorder (box); + + SectionInfo info = new SectionInfo (getUIString (options,warmups,title), + //"{Warmups}", + Warmup.OBJECT_TYPE, + getUIString (options,warmups,text), + //"Want to flex your writing muscles everytime Quoll Writer starts? You'd better click the title above and get things set up while you still have time.", + box); + + return info; + + } + + private void setContentBorder (JComponent box) + { + + box.setBorder (UIUtils.createPadding (7, 0, 10, 0)); + + } + + private void updateUserProperty (String name, + boolean value) + { + + UserProperties.set (name, + value); + + if (this.viewer instanceof AbstractProjectViewer) + { + + ((AbstractProjectViewer) this.viewer).getProject ().getProperties ().removeProperty (name); + + } + + } + + private void updateUserProperty (String name, + String value) + { + + UserProperties.set (name, + value); + + if (this.viewer instanceof AbstractProjectViewer) + { + + ((AbstractProjectViewer) this.viewer).getProject ().getProperties ().removeProperty (name); + + } + + } + + private void updateDefaultProjectProperty (String name, + String value) + { + + Properties props = Environment.getDefaultProperties (Project.OBJECT_TYPE); + + props.setProperty (name, + new StringProperty (name, + value)); + + try + { + + Environment.saveDefaultProperties (Project.OBJECT_TYPE, + props); + + } catch (Exception e) + { + + Environment.logError ("Unable to save default project properties", + e); + + UIUtils.showErrorMessage (this, + getUIString (options,savepropertyerror)); + //"Unable to save default project properties"); + + } + + } + + private void updateDefaultProjectProperty (String name, + boolean value) + { + + Properties props = Environment.getDefaultProperties (Project.OBJECT_TYPE); + + props.setProperty (name, + new BooleanProperty (name, + value)); + + try + { + + Environment.saveDefaultProperties (Project.OBJECT_TYPE, + props); + + } catch (Exception e) + { + + Environment.logError ("Unable to save default project properties", + e); + + UIUtils.showErrorMessage (this, + getUIString (options,savepropertyerror)); + //"Unable to save default project properties"); + + } + + } + + private void updateProjectProperty (String name, + String value) + { + + AbstractProjectViewer pv = (AbstractProjectViewer) this.viewer; + + Properties props = pv.getProject ().getProperties (); + + props.setProperty (name, + new StringProperty (name, + value)); + + try + { + + pv.saveProject (); + + } catch (Exception e) + { + + Environment.logError ("Unable to save project", + e); + + UIUtils.showErrorMessage (this, + getUIString (options,savepropertyerror)); + //"Unable to save."); + + return; + + } + + } + + private boolean handleProjectDirChange (final FileFinder f) + { + + final Options _this = this; + + AbstractProjectViewer pv = (AbstractProjectViewer) this.viewer; + + final Project proj = pv.getProject (); + + final File oldProjDir = proj.getProjectDirectory (); + + final File newDir = f.getSelectedFile (); + + final File newProjDir = new File (newDir, + Utils.sanitizeForFilename (proj.getName ())); + + boolean backupIsSubDir = false; + + File _newBackupDir = null; + + if (Utils.isSubDir (proj.getProjectDirectory (), + proj.getBackupDirectory ())) + { + + backupIsSubDir = true; + + try + { + + _newBackupDir = new File (newProjDir.getPath () + proj.getBackupDirectory ().getCanonicalPath ().substring (proj.getProjectDirectory ().getCanonicalPath ().length ())); + + } catch (Exception e) { + + Environment.logError ("Unable to determine new backups directory for: " + + proj.getBackupDirectory () + + " to: " + + newProjDir); + + UIUtils.showErrorMessage (null, + getUIString (project,actions,changeprojectdir,actionerror)); + //"Unable to change project directory, please contact Quoll Writer support for assistance."); + + return false; + + } + + if (!Utils.isDirectoryEmpty (_newBackupDir)) + { + + UIUtils.showErrorMessage (this.viewer, + String.format (getUIString (project,actions,changeprojectdir,errors,backupdirnotempty), + _newBackupDir.getPath ())); + //"New backups directory: " + + //_newBackupDir + + //" is not empty."); + + f.setFile (oldProjDir); + + return false; + + } + + } + + final File newBackupDir = _newBackupDir; + + // See if the project directory is changing. + if (!newProjDir.equals (oldProjDir)) + { + + if (!Utils.isDirectoryEmpty (newProjDir)) + { + + UIUtils.showErrorMessage (this.viewer, + String.format (getUIString (project,actions,changeprojectdir,errors,dirnotempty), + newProjDir.getPath ())); + //"Unable to change {project} directory to: " + + //newProjDir + + //" directory is not empty."); + + f.setFile (oldProjDir); + + return false; + + } + + // Is changing so need to close the project. + Point p = SwingUtilities.convertPoint (f, + 0, + 0, + this.viewer); + + // Inception! Don't you just love asynchronous programming! + ActionListener confirmAction = new ActionListener () + { + + public void actionPerformed (ActionEvent ev) + { + + if (newBackupDir != null) + { + + // Need to change the backup dir first. + proj.setBackupDirectory (newBackupDir); + + } + + _this.viewer.close (true, + new ActionListener () + { + + public void actionPerformed (ActionEvent ev) + { + + if (!proj.getProjectDirectory ().renameTo (newProjDir)) + { + + Environment.logError ("Unable to rename project directory: " + + proj.getProjectDirectory () + + " to: " + + newProjDir); + + UIUtils.showErrorMessage (null, + getUIString (project,actions,changeprojectdir,actionerror)); + //"Unable to change project directory, please contact Quoll Writer support for assistance."); + + } else { + + proj.setProjectDirectory (newProjDir); + + } + + // Open the project again. + try + { + + Environment.openProject (proj, + () -> + { +/* +TODO + Environment.getProjectViewer (proj).fireProjectEvent (ProjectEvent.Type.projectobject, + ProjectEvent.Action.changeddirectory, + proj.getObjectType ()); +*/ + }); + + } catch (Exception e) + { + + // Show the projects window. + Environment.showAllProjectsViewer (); + + Environment.logError ("Unable to reopen project: " + + proj, + e); + + UIUtils.showErrorMessage (null, + getUIString (project,actions,changeprojectdir,errors,reopenproject)); + //"Unable to reopen project, please contact Quoll Writer support for assistance."); + + return; + + } + + // Finally, delete the old project directory. + //Utils.deleteDir (oldDir); + + } + + }); + + } + + }; + + ActionListener onCancel = new ActionListener () + { + + public void actionPerformed (ActionEvent ev) + { + + // Reset the file. + f.setFile (oldProjDir.getParentFile ()); + + } + + }; + + String extra = ""; + + if (backupIsSubDir) + { + + extra = getUIString (project,actions,changeprojectdir,confirmpopup,backupdirchangewarning); + //"Warning! The backups directory for this {project} will also be changed.

    "; + + } + + UIUtils.createQuestionPopup (this.viewer, + getUIString (project,actions,changeprojectdir,confirmpopup,title), + //"Confirm change to {project} directory?", + Project.OBJECT_TYPE, + String.format (getUIString (project,actions,changeprojectdir,confirmpopup,text), + extra), + //"To change the directory of a {project} it must first be saved and closed. Once the directory has been changed the {project} will be reopened.

    " + extra + "Do you wish to continue?", + getUIString (project,actions,changeprojectdir,confirmpopup,buttons,confirm), + //"Yes, change it", + getUIString (project,actions,changeprojectdir,confirmpopup,buttons,cancel), + //null, + confirmAction, + onCancel, + onCancel, + p); + + } + + return false; + + } + + private void handleBackupsDirChange (final FileFinder f) + { + + final Options _this = this; + + AbstractProjectViewer pv = (AbstractProjectViewer) this.viewer; + + final Project proj = pv.getProject (); + + final File oldDir = proj.getBackupDirectory (); + + final File newDir = f.getSelectedFile (); + + // See if the project directory is changing. + if (!newDir.equals (oldDir)) + { + + if (!Utils.isDirectoryEmpty (newDir)) + { + + UIUtils.showErrorMessage (this.viewer, + String.format (getUIString (project,actions,changebackupdir,errors,dirnotempty), + newDir.getPath ())); + //"Unable to change backup directory to: " + + //newDir + + //", directory is not empty."); + + return; + + } + + // Do a trick, delete the directory then rename to it. + if (newDir.exists ()) + { + + newDir.delete (); + + } + + // Just rename it. + if (!oldDir.renameTo (newDir)) + { + + UIUtils.showErrorMessage (this.viewer, + getUIString (project,actions,changebackupdir,actionerror)); + //"Unable to change backup directory to: " + + //newDir); + + return; + + } + + proj.setBackupDirectory (newDir); + + UIUtils.showMessage ((PopupsSupported) this.viewer, + getUIString (project,actions,changebackupdir,confirmpopup,title), + //"Backups directory changed", + String.format (getUIString (project,actions,changebackupdir,confirmpopup,text), + //"The backups directory for the {project} has been changed to %s.", + newDir.getPath ())); + + } + + } + + private Header createHeader (String title) + { + + return this.createHeader (title, + null); + + } + + private Header createHeader (String title, + String iconType) + { + + Header h = UIUtils.createHeader (title, + Constants.SUB_PANEL_TITLE, + iconType, + null); + + h.setBorder (UIUtils.createBottomLineWithPadding (0, 0, 3, 0)); + + return h; + + } + + private void setAsMainItem (JComponent c) + { + + c.setAlignmentX (Component.LEFT_ALIGNMENT); + c.setAlignmentY (Component.TOP_ALIGNMENT); + + c.setBorder (new CompoundBorder (new EmptyBorder (0, 5, 0, 10), + c.getBorder ())); + + } + + private void setAsSubItem (JComponent c) + { + + c.setAlignmentX (Component.LEFT_ALIGNMENT); + c.setAlignmentY (Component.TOP_ALIGNMENT); + + c.setBorder (new CompoundBorder (new EmptyBorder (0, 15, 0, 10), + c.getBorder ())); + + } + + private void setAsSubItem2 (JComponent c) + { + + c.setAlignmentX (Component.LEFT_ALIGNMENT); + c.setAlignmentY (Component.TOP_ALIGNMENT); + + c.setBorder (new CompoundBorder (new EmptyBorder (0, 20, 0, 10), + c.getBorder ())); + + } + + private JComponent createWrapper (JComponent c) + { + + if ((c instanceof JComboBox) + || + (c instanceof JCheckBox) + ) + { + + c.setMaximumSize (c.getPreferredSize ()); + + } + + c.setAlignmentX (Component.LEFT_ALIGNMENT); + c.setAlignmentY (Component.TOP_ALIGNMENT); + + if (!(c instanceof Box)) + { + + Box _b = new Box (BoxLayout.X_AXIS); + _b.add (Box.createHorizontalStrut (5)); + _b.add (c); + _b.add (Box.createHorizontalGlue ()); + _b.setAlignmentX (Component.LEFT_ALIGNMENT); + _b.setAlignmentY (Component.TOP_ALIGNMENT); + + c = _b; + + } else { + + c.setBorder (new EmptyBorder (0, 5, 0, 0)); + + } + + return c; + + } + + private JTextPane createHelpText (String text) + { + + JTextPane t = UIUtils.createHelpTextPane (text, + this.viewer); + t.setBorder (new EmptyBorder (0, + 5, + 5, + 5)); + + return t; + + } + + public void setState (final Map s) + { + + final Options _this = this; + + this.accordion.setState (s.get ("sections")); + + SwingUtilities.invokeLater (new Runnable () + { + + public void run () + { + + int o = 0; + + try + { + + o = Integer.parseInt (s.get ("scroll")); + + } catch (Exception e) { + + return; + + } + + _this.scrollPane.getVerticalScrollBar ().setValue (o); + + //_this.setReadyForUse (true); + + } + + }); + + } + + public void getState (Map m) + { + + m.put ("sections", + this.accordion.getState ()); + m.put ("scroll", + this.scrollPane.getVerticalScrollBar ().getValue ()); + + } + + public void showEditChapterInfo () + { + + final Options _this = this; + + String popupName = "editchapterinfo"; + final QPopup popup = UIUtils.createClosablePopup (getUIString (project,sidebar,chapters,preview,edit, LanguageStrings.popup,title), + //"Change what is displayed", + Environment.getIcon (Constants.EDIT_ICON_NAME, + Constants.ICON_POPUP), + null); + + popup.setPopupName (popupName); + + OptionsBox bb = new OptionsBox (this.viewer); + + final TextArea status = new TextArea (getUIString (project,sidebar,chapters,preview,edit, LanguageStrings.popup,tooltip), + //"Enter the format here...", + 3, + -1); + status.setMaximumSize (new Dimension (Short.MAX_VALUE, 100)); + status.setText (UserProperties.get (Constants.CHAPTER_INFO_PREVIEW_FORMAT, + Constants.DEFAULT_CHAPTER_INFO_PREVIEW_FORMAT)); + + final Chapter _bogus = new Chapter (); + _bogus.setKey (1L); + _bogus.setDescription (new StringWithMarkup (getUIString (project,sidebar,chapters,preview,edit, LanguageStrings.popup,examplechapter,description))); + //"This chapter will be really, really good once I actually start to write it.")); + _bogus.setText (new StringWithMarkup (getUIString (project,sidebar,chapters,preview,edit, LanguageStrings.popup,examplechapter,text))); + //"Once upon a time there was a little chapter that wanted to be written.")); + + final ProjectViewer _bogusPV = new ProjectViewer () + { + + public ChapterCounts getChapterCounts (Chapter c) + { + + ChapterCounts cc = new ChapterCounts (_bogus.getChapterText ()); + + return cc; + + } + + public Set getSpellingErrors (Chapter c) + { + + Set ret = new HashSet (); + return ret; + + } + + public Set getProblems (Chapter c) + { + + Set ret = new HashSet (); + return ret; + + } + + }; + + final JComponent pb = UIUtils.getChapterInfoPreview (_bogus, + null, + _bogusPV); + + bb.addMain (getUIString (project,sidebar,chapters,preview,edit, LanguageStrings.popup,text), + //"Use the following format for {chapter} information. Click here for help on the format/tags that can be used.", + status); + + Box pbb = new Box (BoxLayout.X_AXIS); + + int BOX_WIDTH = 380; + + pbb.setMaximumSize (new Dimension (BOX_WIDTH, + Short.MAX_VALUE)); + + final Box previewWrapper = new Box (BoxLayout.Y_AXIS); + + previewWrapper.add (pb); + pbb.add (previewWrapper); + + status.addCaretListener (new CaretListener () + { + + @Override + public void caretUpdate (CaretEvent ev) + { + + UIUtils.doLater (new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + previewWrapper.removeAll (); + + previewWrapper.add (UIUtils.getChapterInfoPreview (_bogus, + status.getText (), + _bogusPV)); + + popup.resize (); + + } + + }); + + } + + }); + + bb.addMain (UIUtils.createBoldSubHeader (getUIString (project,sidebar,chapters,preview,edit, LanguageStrings.popup,examplechapter,title), + //"Example", + null), + pbb); + + Box content = new Box (BoxLayout.Y_AXIS); + + content.add (bb); + content.add (pbb); + content.add (Box.createVerticalStrut (15)); + + //content.add (Box.createVerticalGlue ()); + + JButton save = UIUtils.createButton (getUIString (project,sidebar,chapters,preview,edit, LanguageStrings.popup,buttons, LanguageStrings.save), + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + UserProperties.set (Constants.CHAPTER_INFO_PREVIEW_FORMAT, + status.getText ()); + + previewWrapper.removeAll (); + + previewWrapper.add (UIUtils.getChapterInfoPreview (_bogus, + status.getText (), + _bogusPV)); + + popup.resize (); + + } + + }); + + JButton cancel = UIUtils.createButton (getUIString (project,sidebar,chapters,preview,edit, LanguageStrings.popup,buttons, LanguageStrings.cancel), + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + UserProperties.set (Constants.CHAPTER_INFO_PREVIEW_FORMAT, + status.getText ()); + + popup.removeFromParent (); + + } + + }); + + JButton reset = UIUtils.createButton (getUIString (project,sidebar,chapters,preview,edit, LanguageStrings.popup,usedefault)); + //"Use default"); + + reset.addActionListener (new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + status.setText (UserProperties.get (Constants.DEFAULT_CHAPTER_INFO_PREVIEW_FORMAT)); + + previewWrapper.removeAll (); + + previewWrapper.add (UIUtils.getChapterInfoPreview (_bogus, + status.getText (), + _bogusPV)); + + popup.resize (); + + UserProperties.set (Constants.CHAPTER_INFO_PREVIEW_FORMAT, + status.getText ()); + + } + + }); + + JButton[] buts = { save, reset, cancel }; + + JPanel bp = UIUtils.createButtonBar2 (buts, + Component.CENTER_ALIGNMENT); + bp.setOpaque (false); + bp.setAlignmentX (JComponent.LEFT_ALIGNMENT); + content.add (bp); + + Box _content = new Box (BoxLayout.Y_AXIS); + _content.add (content); + + content.setBorder (UIUtils.createPadding (10, 10, 10, 10)); + + _content.setPreferredSize (new Dimension (UIUtils.getPopupWidth (), + _content.getPreferredSize ().height)); + + popup.setContent (_content); + + this.viewer.showPopupAt (popup, + UIUtils.getCenterShowPosition (this, + popup), + false); + + popup.setDraggable (this.viewer); + + } + + private void showSendFeedbackToUIStringsCreator () + { + + final Options _this = this; + + java.util.List prefix = Arrays.asList (uilanguage,feedback); + + String popupName = "contactuilangstrings-" + UserProperties.get (Constants.USER_UI_LANGUAGE_PROPERTY_NAME); + QPopup popup = this.viewer.getNamedPopup (popupName); + + if (popup == null) + { + + popup = UIUtils.createClosablePopup (getUIString (prefix, LanguageStrings.popup, LanguageStrings.title), + Environment.getIcon (Constants.EMAIL_ICON_NAME, + Constants.ICON_POPUP), + null); + + final QPopup qp = popup; + + popup.setPopupName (popupName); + + this.viewer.addNamedPopup (popupName, + popup); + + Box content = new Box (BoxLayout.Y_AXIS); + + JTextPane help = UIUtils.createHelpTextPane (String.format (getUIString (prefix, LanguageStrings.popup,text), + UILanguageStringsManager.getCurrentUILanguageStrings ().getNativeName ()), + this.viewer); + + help.setBorder (null); + + content.add (help); + content.add (Box.createVerticalStrut (10)); + + String errText = getUIString (prefix, LanguageStrings.popup,errorlabel); + + final JLabel error = UIUtils.createErrorLabel (errText); + error.setVisible (false); + error.setBorder (UIUtils.createPadding (0, 0, 5, 5)); + + content.add (error); + + final MultiLineTextFormItem desc = new MultiLineTextFormItem (getUIString (prefix, LanguageStrings.popup,message,text), + getUIString (prefix, LanguageStrings.popup,message,tooltip), + 10, + 10000, + false, + null); + + final TextFormItem email = new TextFormItem (getUIString (prefix, LanguageStrings.popup, LanguageStrings.email,text), + null); + + Set items = new LinkedHashSet (); + + items.add (desc); + items.add (email); + + ActionListener sendAction = new ActionListener () + { + + public void actionPerformed (ActionEvent ev) + { + + error.setVisible (false); + + String emErr = Utils.checkEmail2 (email.getText ()); + + if (emErr != null) + { + + error.setText (emErr); + + error.setVisible (true); + + qp.resize (); + + return; + + } + + if (desc.getText ().trim ().equals ("")) + { + + error.setText (errText); + error.setVisible (true); + + qp.resize (); + + return; + + } + + qp.resize (); + + // Send the message. + Map details = new HashMap (); + details.put ("details", + desc.getText ()); + details.put ("email", + email.getText ()); + details.put ("uilanguageid", + UILanguageStringsManager.getCurrentUILanguageStrings ().getId ()); + + try + { + + Environment.sendMessageToSupport ("uilanguage", + details, + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + desc.setText (""); + + UIUtils.showMessage ((PopupsSupported) _this.viewer, + getUIString (prefix,confirmpopup, LanguageStrings.title), + getUIString (prefix,confirmpopup,text)); + + } + + }); + + } catch (Exception e) + { + + Environment.logError ("Unable to send message to support", + e); + + UIUtils.showErrorMessage (_this, + getUIString (prefix,actionerror)); + //"Unable to send message."); + + } + + qp.removeFromParent (); + + } + + }; + + UIUtils.addDoActionOnReturnPressed (desc.getTextArea (), + sendAction); + UIUtils.addDoActionOnReturnPressed (email.getTextField (), + sendAction); + + JButton send = UIUtils.createButton (getUIString (prefix, LanguageStrings.popup, LanguageStrings.buttons, LanguageStrings.send), + sendAction); + JButton cancel = UIUtils.createButton (getUIString (prefix, LanguageStrings.popup, LanguageStrings.buttons, LanguageStrings.cancel), + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + qp.removeFromParent (); + + } + + }); + + Set buttons = new LinkedHashSet (); + buttons.add (send); + buttons.add (cancel); + + Form f = new Form (Form.Layout.stacked, + items, + buttons); + + content.add (f); + + content.setSize (new Dimension (UIUtils.getPopupWidth () - 20, + content.getPreferredSize ().height)); + content.setBorder (UIUtils.createPadding (10, 10, 10, 10)); + + popup.setContent (content); + + popup.setDraggable (this); + + popup.resize (); + this.viewer.showPopupAt (popup, + UIUtils.getCenterShowPosition (this.viewer, + popup), + false); + + UIUtils.doLater (new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + desc.grabFocus (); + + } + + }); + + } else { + + popup.setVisible (true); + + + } + + } + +} diff --git a/src/com/quollwriter/ui/OptionsBox.java b/src/main/java/com/quollwriter/ui/OptionsBox.java similarity index 100% rename from src/com/quollwriter/ui/OptionsBox.java rename to src/main/java/com/quollwriter/ui/OptionsBox.java diff --git a/src/com/quollwriter/ui/PasswordInputWindow.java b/src/main/java/com/quollwriter/ui/PasswordInputWindow.java similarity index 99% rename from src/com/quollwriter/ui/PasswordInputWindow.java rename to src/main/java/com/quollwriter/ui/PasswordInputWindow.java index 9466a6de..7b3b58d7 100644 --- a/src/com/quollwriter/ui/PasswordInputWindow.java +++ b/src/main/java/com/quollwriter/ui/PasswordInputWindow.java @@ -7,8 +7,6 @@ import javax.swing.border.*; import javax.swing.event.*; -import com.gentlyweb.utils.*; - import com.jgoodies.forms.factories.*; import com.quollwriter.*; diff --git a/src/com/quollwriter/ui/PopupWindow.java b/src/main/java/com/quollwriter/ui/PopupWindow.java similarity index 89% rename from src/com/quollwriter/ui/PopupWindow.java rename to src/main/java/com/quollwriter/ui/PopupWindow.java index a2d70647..2fd7de31 100644 --- a/src/com/quollwriter/ui/PopupWindow.java +++ b/src/main/java/com/quollwriter/ui/PopupWindow.java @@ -7,8 +7,6 @@ import javax.swing.border.*; import javax.swing.event.*; -import com.gentlyweb.utils.*; - import com.jgoodies.forms.factories.*; import com.quollwriter.*; @@ -26,7 +24,7 @@ public abstract class PopupWindow extends JFrame private Box content = null; private Point showAt = null; private JTextPane helpP = null; - + public PopupWindow() { @@ -37,20 +35,20 @@ public PopupWindow(AbstractViewer pv, { this (pv); - + this.viewer = pv; - + this.buttonAlignment = buttonAlignment; - + } - + public PopupWindow(AbstractViewer pv) { super (); - + this.setModalExclusionType (Dialog.ModalExclusionType.APPLICATION_EXCLUDE); - + this.viewer = pv; if (pv != null) @@ -76,55 +74,55 @@ public void windowClosing (WindowEvent ev) public void setShowAt (Point p) { - + this.showAt = p; - + if ((this.inited) && (this.showAt != null) ) { - + this.setLocation (this.showAt.x, this.showAt.y); - + } - + } - + public Point getShowAt () { - + return this.showAt; - + } - + public AbstractViewer getViewer () { - + return this.viewer; - + } public ActionListener getCloseAction () { - + final PopupWindow _this = this; - + return new ActionListener () { - + public void actionPerformed (ActionEvent ev) { - + _this.close (); - + } - + }; - + } - + public void init () { @@ -147,21 +145,21 @@ public void init () final PopupWindow _this = this; this.setDefaultCloseOperation (WindowConstants.DISPOSE_ON_CLOSE); - + this.content = new Box (BoxLayout.PAGE_AXIS); this.content.setOpaque (true); this.content.setBackground (UIUtils.getComponentColor ()); this.content.setBorder (UIUtils.createPadding (10, 10, 10, 10)); - + String headerTitle = (this.getHeaderTitle () != null) ? this.getHeaderTitle () : this.getWindowTitle (); - + if (headerTitle != null) { - + this.header = UIUtils.createHeader (headerTitle, Constants.POPUP_WINDOW_TITLE); - + this.content.add (this.header); } @@ -169,14 +167,14 @@ public void init () Box helpWrapper = new Box (BoxLayout.Y_AXIS); helpWrapper.setAlignmentX (JComponent.LEFT_ALIGNMENT); helpWrapper.setBorder (UIUtils.createPadding (5, 5, 0, 0)); - + this.helpP = UIUtils.createHelpTextPane (this.viewer); this.helpP.setBorder (null); this.helpP.setSize (new Dimension (UIUtils.getPopupWidth () - 20, Short.MAX_VALUE)); - + helpWrapper.add (this.helpP); - + this.content.add (helpWrapper); this.setHelpText (this.getHelpText ()); @@ -221,33 +219,33 @@ public void init () this.getContentPane ().add (this.content); this.setResizable (false); - + this.pack (); - + this.resize (); - + if (this.showAt == null) { - + //UIUtils.setCenterOfScreenLocation (this); - + // Let the windows manager decide where to show. this.setLocationByPlatform (true); } else { - + this.setLocation (this.showAt.x, this.showAt.y); - + } - + this.inited = true; - + this.setVisible (true); - + this.toFront (); this.pack (); - + } public void resize () @@ -255,34 +253,34 @@ public void resize () this.getContentPane ().setPreferredSize (new Dimension (UIUtils.getPopupWidth (), this.content.getPreferredSize ().height)); - + this.validate (); this.repaint (); - + final PopupWindow _this = this; - + UIUtils.doLater (new ActionListener () { - + @Override public void actionPerformed (ActionEvent ev) { - + _this.pack (); - + } - + }); - + } - + public void setButtonAlignment (float v) { - + this.buttonAlignment = v; - + } - + public void setVisible (boolean v) { @@ -297,11 +295,11 @@ public void setVisible (boolean v) if (v) { - + this.resize (); - + } - + } public void close () @@ -321,11 +319,11 @@ public void setHeaderTitle (String t) public Header getHeader () { - + return this.header; - + } - + public void setHelpText (String t) { @@ -342,16 +340,16 @@ public void setHelpText (String t) this.helpP.setSize (new Dimension (UIUtils.getPopupWidth () - 20, Short.MAX_VALUE)); - + //this.helpP.setText (UIUtils.formatTextForHelpPane (t)); this.helpP.setVisible (true); } - + this.resize (); this.resize (); - + } public abstract String getWindowTitle (); diff --git a/src/com/quollwriter/ui/PopupWizard.java b/src/main/java/com/quollwriter/ui/PopupWizard.java similarity index 99% rename from src/com/quollwriter/ui/PopupWizard.java rename to src/main/java/com/quollwriter/ui/PopupWizard.java index c130e5a8..91f3fbd0 100644 --- a/src/com/quollwriter/ui/PopupWizard.java +++ b/src/main/java/com/quollwriter/ui/PopupWizard.java @@ -10,8 +10,6 @@ import javax.swing.border.*; import javax.swing.event.*; -import com.gentlyweb.utils.*; - import com.jgoodies.forms.factories.*; import com.quollwriter.*; @@ -65,7 +63,7 @@ public void init () 0, 1, 0, - Environment.getBorderColor ()), + UIUtils.getBorderColor ()), new EmptyBorder (0, 0, 2, diff --git a/src/com/quollwriter/ui/PopupsSupported.java b/src/main/java/com/quollwriter/ui/PopupsSupported.java similarity index 100% rename from src/com/quollwriter/ui/PopupsSupported.java rename to src/main/java/com/quollwriter/ui/PopupsSupported.java diff --git a/src/com/quollwriter/ui/PositionActionAdapter.java b/src/main/java/com/quollwriter/ui/PositionActionAdapter.java similarity index 100% rename from src/com/quollwriter/ui/PositionActionAdapter.java rename to src/main/java/com/quollwriter/ui/PositionActionAdapter.java diff --git a/src/com/quollwriter/ui/ProblemFinderRuleConfig.java b/src/main/java/com/quollwriter/ui/ProblemFinderRuleConfig.java similarity index 98% rename from src/com/quollwriter/ui/ProblemFinderRuleConfig.java rename to src/main/java/com/quollwriter/ui/ProblemFinderRuleConfig.java index 81ad1e28..32ea091c 100644 --- a/src/com/quollwriter/ui/ProblemFinderRuleConfig.java +++ b/src/main/java/com/quollwriter/ui/ProblemFinderRuleConfig.java @@ -38,6 +38,8 @@ import com.quollwriter.ui.panels.*; import com.quollwriter.text.*; import com.quollwriter.text.rules.*; +import com.quollwriter.ui.fx.ProjectEvent; +import com.quollwriter.ui.fx.ProjectEventListener; import com.quollwriter.ui.forms.*; import com.quollwriter.ui.components.ScrollableBox; @@ -230,8 +232,8 @@ public void actionPerformed (ActionEvent ev) } Environment.fireUserProjectEvent (conf, - ProjectEvent.PROBLEM_FINDER, - ProjectEvent.REMOVE_RULE, + ProjectEvent.Type.problemfinder, + ProjectEvent.Action.removerule, _this.rule); } @@ -294,18 +296,18 @@ public ProblemFinderRuleConfig (ProjectViewer pv) public void eventOccurred (ProjectEvent ev) { - if (!ev.getType ().equals (ProjectEvent.PROBLEM_FINDER)) + if (!ev.getType ().equals (ProjectEvent.Type.problemfinder)) { return; } - if ((!ev.getAction ().equals (ProjectEvent.NEW_RULE)) + if ((!ev.getAction ().equals (ProjectEvent.Action.newrule)) && - (!ev.getAction ().equals (ProjectEvent.EDIT_RULE)) + (!ev.getAction ().equals (ProjectEvent.Action.editrule)) && - (!ev.getAction ().equals (ProjectEvent.REMOVE_RULE)) + (!ev.getAction ().equals (ProjectEvent.Action.removerule)) ) { @@ -354,7 +356,7 @@ private void createSentenceWrapper () 0, 1, 0, - Environment.getBorderColor ()), + UIUtils.getBorderColor ()), new EmptyBorder (3, 3, 3, @@ -548,7 +550,7 @@ private void createParagraphWrapper () 0, 1, 0, - Environment.getBorderColor ()), + UIUtils.getBorderColor ()), new EmptyBorder (3, 3, 3, @@ -1120,8 +1122,8 @@ public void actionPerformed (ActionEvent ev) add); Environment.fireUserProjectEvent (_this, - ProjectEvent.PROBLEM_FINDER, - (add ? ProjectEvent.NEW_RULE : ProjectEvent.EDIT_RULE), + ProjectEvent.Type.problemfinder, + (add ? ProjectEvent.Action.newrule : ProjectEvent.Action.editrule), r); } diff --git a/src/main/java/com/quollwriter/ui/ProgressPopup.java b/src/main/java/com/quollwriter/ui/ProgressPopup.java new file mode 100644 index 00000000..61f36d83 --- /dev/null +++ b/src/main/java/com/quollwriter/ui/ProgressPopup.java @@ -0,0 +1,53 @@ +package com.quollwriter.ui; + +import java.awt.Dimension; + +import javax.swing.*; + +import com.quollwriter.*; +import com.quollwriter.ui.components.QPopup; + +public class ProgressPopup extends QPopup +{ + + JProgressBar progress = null; + + public ProgressPopup (AbstractViewer viewer, + String title, + String icon, + String text) + { + + super (title, + Environment.getIcon (icon, + -1), + null); + + this.progress = new JProgressBar (); + this.progress.setPreferredSize (new Dimension (300, + 20)); + this.progress.setMaximumSize (new Dimension (500, + 20)); + this.progress.setAlignmentX (this.LEFT_ALIGNMENT); + + Box b = new Box (BoxLayout.Y_AXIS); + + b.add (UIUtils.createHelpTextPane (text, + viewer)); + b.add (Box.createVerticalStrut (10)); + b.add (this.progress); + + b.setBorder (UIUtils.createPadding (10, 10, 10, 10)); + + this.setContent (b); + + } + + public void update (int perc) + { + + this.progress.setValue (perc); + + } + +} diff --git a/src/com/quollwriter/ui/ProjectEvent.java b/src/main/java/com/quollwriter/ui/ProjectEvent.java similarity index 100% rename from src/com/quollwriter/ui/ProjectEvent.java rename to src/main/java/com/quollwriter/ui/ProjectEvent.java diff --git a/src/com/quollwriter/ui/ProjectEventListener.java b/src/main/java/com/quollwriter/ui/ProjectEventListener.java similarity index 100% rename from src/com/quollwriter/ui/ProjectEventListener.java rename to src/main/java/com/quollwriter/ui/ProjectEventListener.java diff --git a/src/com/quollwriter/ui/ProjectObjectEvent.java b/src/main/java/com/quollwriter/ui/ProjectObjectEvent.java similarity index 100% rename from src/com/quollwriter/ui/ProjectObjectEvent.java rename to src/main/java/com/quollwriter/ui/ProjectObjectEvent.java diff --git a/src/com/quollwriter/ui/ProjectObjectsAccordionItem.java b/src/main/java/com/quollwriter/ui/ProjectObjectsAccordionItem.java similarity index 100% rename from src/com/quollwriter/ui/ProjectObjectsAccordionItem.java rename to src/main/java/com/quollwriter/ui/ProjectObjectsAccordionItem.java diff --git a/src/com/quollwriter/ui/ProjectTextProperties.java b/src/main/java/com/quollwriter/ui/ProjectTextProperties.java similarity index 100% rename from src/com/quollwriter/ui/ProjectTextProperties.java rename to src/main/java/com/quollwriter/ui/ProjectTextProperties.java diff --git a/src/main/java/com/quollwriter/ui/ProjectViewer.java b/src/main/java/com/quollwriter/ui/ProjectViewer.java new file mode 100644 index 00000000..cefbc4d9 --- /dev/null +++ b/src/main/java/com/quollwriter/ui/ProjectViewer.java @@ -0,0 +1,3813 @@ +package com.quollwriter.ui; + +import java.awt.*; +import java.awt.dnd.*; +import java.awt.event.*; + +import java.io.*; + +import java.net.*; + +import java.security.*; + +import java.text.*; + +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.TreeSet; +import java.util.Map; +import java.util.Set; +import java.util.StringTokenizer; +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.LinkedHashMap; +import java.util.WeakHashMap; +import java.util.Collections; +import java.util.Arrays; + +import javax.swing.*; +import javax.swing.border.*; +import javax.swing.event.*; +import javax.swing.text.*; +import javax.swing.tree.*; + +import com.gentlyweb.properties.*; + +import com.jgoodies.forms.builder.*; +import com.jgoodies.forms.factories.*; +import com.jgoodies.forms.layout.*; + +import com.quollwriter.*; + +import com.quollwriter.data.*; + +import com.quollwriter.data.editors.*; +import com.quollwriter.db.*; + +import com.quollwriter.events.*; +import com.quollwriter.data.comparators.*; +import com.quollwriter.text.*; +import com.quollwriter.ui.sidebars.*; +import com.quollwriter.ui.panels.*; + +import com.quollwriter.ui.actionHandlers.*; +import com.quollwriter.ui.components.*; +import com.quollwriter.ui.events.*; +import com.quollwriter.ui.renderers.*; +import com.quollwriter.editors.*; +import com.quollwriter.editors.ui.*; +import com.quollwriter.editors.ui.panels.*; +import com.quollwriter.editors.ui.sidebars.*; + +import com.quollwriter.text.*; + +import static com.quollwriter.LanguageStrings.*; +import static com.quollwriter.Environment.getUIString; + +public class ProjectViewer extends AbstractProjectViewer implements DocumentListener, ProjectEventListener +{ + + public static final String IDEA_BOARD_HEADER_CONTROL_ID = "ideaBoard"; + + public static final String TAB_OBJECT_TYPE = "tab"; + public static final int NEW_CHAPTER_ACTION = 102; // "newChapter"; + public static final int NEW_NOTE_ACTION = 103; // "newNote"; + public static final int VIEW_CHAPTER_INFO_ACTION = 105; // "viewChapterInfo"; + + // public static final int DELETE_CHAPTER_ACTION = 106; + public static final int NEW_BOOK_ACTION = 108; // "newBook"; + public static final int NEW_PLOT_OUTLINE_ITEM_ACTION = 116; // "newPlotOutlineItem"; + public static final int NEW_PLOT_OUTLINE_ITEM_BELOW_ACTION = 117; // "newPlotOutlineItemBelow"; + public static final int DELETE_PLOT_OUTLINE_ITEM_ACTION = 118; // "deletePlotOutlineItem"; + public static final int EDIT_PLOT_OUTLINE_ITEM_ACTION = 119; // "editPlotOutlineItem"; + public static final int DELETE_NOTE_ACTION = 120; // "deleteNote"; + public static final int EDIT_NOTE_ACTION = 121; // "editNote"; + //public static final int NEW_SCENE_ACTION = 122; // "newScene"; + public static final int NEW_SCENE_BELOW_ACTION = 123; // "newSceneBelow"; + public static final int DELETE_SCENE_ACTION = 124; // "deleteScene"; + public static final int EDIT_SCENE_ACTION = 125; // "editScene"; + public static final int MANAGE_NOTE_TYPES_ACTION = 126; // "manageNoteTypes" + public static final int NEW_NOTE_TYPE_ACTION = 127; // "newNoteType" + //public static final int MANAGE_ITEM_TYPES_ACTION = 128; // "manageItemTypes" + //public static final int NEW_ITEM_TYPE_ACTION = 129; // "newItemType" + + private Date sessionStart = new Date (); + private ProjectSideBar sideBar = null; + private ChapterItemViewPopupProvider chapterItemViewPopupProvider = null; + private IconProvider iconProvider = null; + private ImportTransferHandlerOverlay importOverlay = null; + private PropertyChangedListener objectTypePropChangedListener = null; + private PropertyChangedListener noteTypePropChangedListener = null; + private Map chapterDocumentListeners = Collections.synchronizedMap (new WeakHashMap ()); + private static final Object listenerFillObj = new Object (); + private ProblemFinderSideBar problemFinderSideBar = null; + private ProblemFinderRuleConfig problemFinderRuleConfig = null; + + public ProjectViewer () + { + + final ProjectViewer _this = this; + + this.iconProvider = new DefaultIconProvider (); + this.chapterItemViewPopupProvider = new DefaultChapterItemViewPopupProvider (); + + // TODO Environment.addUserProjectEventListener (this); + + this.problemFinderRuleConfig = new ProblemFinderRuleConfig (this); + + InputMap im = this.getInputMap (JComponent.WHEN_IN_FOCUSED_WINDOW); + ActionMap actions = this.getActionMap (); + + ProjectViewer.addAssetActionMappings (this, + im, + actions); + + im.put (KeyStroke.getKeyStroke ("ctrl shift H"), + "new" + Chapter.OBJECT_TYPE); + + actions.put ("new" + Chapter.OBJECT_TYPE, + new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + Chapter ch = _this.getChapterCurrentlyEdited (); + + NamedObject o = ch; + + if (ch == null) + { + + // Get the last chapter. + Book b = _this.proj.getBooks ().get (0); + + ch = b.getLastChapter (); + + o = ch; + + if (ch == null) + { + + o = b; + + } + + } + + Action a = _this.getAction (ProjectViewer.NEW_CHAPTER_ACTION, + o); + + if (a != null) + { + + a.actionPerformed (ev); + + } + + } + + }); + + this.sideBar = new ProjectSideBar (this); + + this.importOverlay = new ImportTransferHandlerOverlay (); + + this.importOverlay.addMouseListener (new MouseEventHandler () + { + + public void handlePress (MouseEvent ev) + { + + _this.importOverlay.setVisible (false); + + _this.validate (); + _this.repaint (); + + } + + }); + + /* + * Disabled for now, drag-n-drop importing throws a bizarre exception: + * + * Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException + * at javax.swing.TransferHandler$DropHandler.drop(TransferHandler.java:1521) + * at java.awt.dnd.DropTarget.drop(DropTarget.java:455) + * at javax.swing.TransferHandler$SwingDropTarget.drop(TransferHandler.java:1282) + * at sun.awt.dnd.SunDropTargetContextPeer.processDropMessage(SunDropTargetContextPeer.java:538) + * + * This problem seems to have been introduced in Java8, it definitely worked in Java7, grr... + * + this.setTransferHandler (new ImportTransferHandler (new ActionListener () + { + + public void actionPerformed (ActionEvent ev) + { + + _this.importOverlay.setDisplayText ("Drop the file to begin the import"); + + File f = (File) ev.getSource (); + + QuollPanel qp = _this.getCurrentlyVisibleTab (); + + if (qp instanceof ProjectObjectQuollPanel) + { + + ProjectObjectQuollPanel pqp = (ProjectObjectQuollPanel) qp; + + if (pqp.getForObject () instanceof Asset) + { + + _this.importOverlay.setDisplayText (String.format ("Drop the file to add it to %s's {documents}.", + pqp.getForObject ().getName ())); + + } + + } + + _this.importOverlay.setFile (f); + + _this.setGlassPane (_this.importOverlay); + + _this.importOverlay.setVisible (true); + _this.validate (); + _this.repaint (); + + } + + }, + new ActionListener () + { + + public void actionPerformed (ActionEvent ev) + { + + _this.importOverlay.setVisible (false); + _this.validate (); + _this.repaint (); + + File f = (File) ev.getSource (); + + QuollPanel qp = _this.getCurrentlyVisibleTab (); + + if (qp instanceof AssetViewPanel) + { + + AssetViewPanel vp = (AssetViewPanel) qp; + + vp.getObjectDocumentsEditPanel ().addFile (f, + false); + + } else { + + _this.showImportProject (f); + + } + + } + + }, + new ActionListener () + { + + public void actionPerformed (ActionEvent ev) + { + + _this.importOverlay.setVisible (false); + _this.validate (); + _this.repaint (); + + } + + }, + new FileFilter () + { + + @Override + public boolean accept (File f) + { + + QuollPanel qp = _this.getCurrentlyVisibleTab (); + + if (qp instanceof ProjectObjectQuollPanel) + { + + ProjectObjectQuollPanel pqp = (ProjectObjectQuollPanel) qp; + + if (pqp.getForObject () instanceof Asset) + { + + return true; + + } + + } + + return ImportProject.isSupportedFileType (f); + + } + + })); + + this.importOverlay.setTransferHandler (this.getTransferHandler ()); + */ + } + + public IconProvider getIconProvider () + { + + return this.iconProvider; + + } + + public ChapterItemViewPopupProvider getChapterItemViewPopupProvider () + { + + return this.chapterItemViewPopupProvider; + + } + + public void initActionMappings (ActionMap am) + { + + final ProjectViewer _this = this; + + super.initActionMappings (am); + + am.put ("ideaboard-show", + new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + _this.viewIdeaBoard (); + + } + + }); + + } + + public void initKeyMappings (InputMap im) + { + + super.initKeyMappings (im); + + im.put (KeyStroke.getKeyStroke (KeyEvent.VK_F2, + 0), + "ideaboard-show"); + + } + + public AbstractSideBar getMainSideBar () + { + + return this.sideBar; + + } +/* + private static Action getAddAssetActionListener (final UserConfigurableObjectType type, + final ProjectViewer pv) + { + + return new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + Asset as = null; + + try + { + + as = Asset.createAsset (type); + + } catch (Exception e) { + + Environment.logError ("Unable to create new asset of type: " + + type, + e); + + UIUtils.showErrorMessage (pv, + String.format ("Unable to create new %s.", + type.getObjectTypeName ())); + + return; + + } + + String addAsset = UserProperties.get (Constants.ADD_ASSETS_PROPERTY_NAME); + + // Should we use a popup? + if (((addAsset.equals ("trypopup")) + && + (type.getNonCoreFieldCount () == 0) + ) + || + (addAsset.equals ("popup")) + ) + { + + AssetActionHandler aah = new AssetActionHandler (as, + pv); + + aah.setPopupOver (pv); + + aah.actionPerformed (ev); + + return; + + } + + pv.showAddAsset (as, + null); + + } + + }; + + } + */ +/* + public TypesHandler getObjectTypesHandler (String objType) + { + + if (objType.equals (Note.OBJECT_TYPE)) + { + + return this.noteTypeHandler; + + } + + if (objType.equals (QObject.OBJECT_TYPE)) + { + + return this.itemTypeHandler; + + } + + return null; + + } + */ + public static void addAssetActionMappings (final PopupsSupported parent, + InputMap im, + ActionMap actions) + { + + ProjectViewer pv = null; + PopupsSupported ps = null; + + if (parent instanceof ProjectViewer) + { + + pv = (ProjectViewer) parent; + + } + + if (parent instanceof QuollPanel) + { + + AbstractViewer v = ((QuollPanel) parent).getViewer (); + + if (v instanceof ProjectViewer) + { + + pv = (ProjectViewer) v; + + } + + } + + if (parent instanceof FullScreenFrame) + { + + // TODO: A little dangerous to do this, fix in future. + pv = (ProjectViewer) ((FullScreenFrame) parent).getProjectViewer (); + + } + + final ProjectViewer ppv = pv; + + Set assetObjTypes = Environment.getAssetUserConfigurableObjectTypes (true); + + for (UserConfigurableObjectType type : assetObjTypes) + { + + if (type.getCreateShortcutKeyStroke () != null) + { + + String id = "newuserobject" + type.getKey (); + + im.put (type.getCreateShortcutKeyStroke (), + id); + actions.put (id, + UIUtils.createAddAssetActionListener (type, + pv, + null, + null)); +/* + ProjectViewer.getAddAssetActionListener (type, + ppv)); +*/ + } + + } + + } + + public void fillFullScreenTitleToolbar (JToolBar toolbar) + { + + final ProjectViewer _this = this; + + toolbar.add (UIUtils.createButton (Constants.IDEA_ICON_NAME, + Constants.ICON_TITLE_ACTION, + getUIString (fullscreen,title, LanguageStrings.toolbar,buttons,ideaboard,tooltip), + //"Click to open the Idea Board", + new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + _this.viewIdeaBoard (); + + } + + })); + + WordCountTimerBox b = new WordCountTimerBox (this.getFullScreenFrame (), + Constants.ICON_FULL_SCREEN_ACTION, + this.getWordCountTimer ()); + + b.setBarHeight (20); + + toolbar.add (b); + + } + + public void fillSettingsPopup (JPopupMenu titlePopup) + { + + final ProjectViewer _this = this; + + java.util.List prefix = Arrays.asList (project,settingsmenu,items); + + JMenuItem mi = null; + + // Open project. + titlePopup.add (this.createMenuItem (getUIString (prefix,openproject), + //"Open {Project}", + Constants.OPEN_PROJECT_ICON_NAME, + ProjectViewer.OPEN_PROJECT_ACTION)); + + titlePopup.add (this.createMenuItem (getUIString (prefix,newproject), + //"New {Project}", + Constants.NEW_ICON_NAME, + ProjectViewer.NEW_PROJECT_ACTION)); + + titlePopup.addSeparator (); + + // Rename project + titlePopup.add (this.createMenuItem (getUIString (prefix,renameproject), + //"Rename this {Project}", + Constants.RENAME_ICON_NAME, + ProjectViewer.RENAME_PROJECT_ACTION)); + + titlePopup.add (this.createMenuItem (getUIString (prefix,statistics), + //"Statistics", + Constants.CHART_ICON_NAME, + AbstractProjectViewer.SHOW_STATISTICS_ACTION)); + + titlePopup.add (this.createMenuItem (getUIString (prefix,targets), + //"Targets", + Constants.TARGET_ICON_NAME, + ProjectViewer.SHOW_TARGETS_ACTION)); + + // Create Project Snapshot + titlePopup.add (this.createMenuItem (getUIString (prefix,createbackup), + //"Create a Backup", + Constants.SNAPSHOT_ICON_NAME, + ProjectViewer.CREATE_PROJECT_SNAPSHOT_ACTION)); + + // Close Project + titlePopup.add (this.createMenuItem (getUIString (prefix,closeproject), + //"Close {Project}", + Constants.CLOSE_ICON_NAME, + ProjectViewer.CLOSE_PROJECT_ACTION)); + + // Delete Project + titlePopup.add (this.createMenuItem (getUIString (prefix,deleteproject), + //"Delete {Project}", + Constants.DELETE_ICON_NAME, + ProjectViewer.DELETE_PROJECT_ACTION)); + + titlePopup.addSeparator (); + + // Idea Board + titlePopup.add (this.createMenuItem (getUIString (prefix,ideaboard), + //"Idea Board", + Constants.IDEA_ICON_NAME, + new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + _this.viewIdeaBoard (); + + } + + })); + + // Do a Warm-up Exercise + titlePopup.add (this.createMenuItem (getUIString (prefix,dowarmup), + //String.format ("Do a {Warmup} Exercise", Warmup.OBJECT_TYPE), + Constants.WARMUPS_ICON_NAME, + AbstractProjectViewer.WARMUP_EXERCISE_ACTION)); + + titlePopup.addSeparator (); + + // Import File + titlePopup.add (this.createMenuItem (Environment.getUIString (prefix, + LanguageStrings.importfileorproject), + //"Import File/{Project}", + Constants.PROJECT_IMPORT_ICON_NAME, + new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + _this.showImportProject (); + + } + + })); + + // Export Project + titlePopup.add (this.createMenuItem (Environment.getUIString (prefix, + LanguageStrings.exportproject), + //String.format ("Export {Project}", Project.OBJECT_TYPE), + Constants.PROJECT_EXPORT_ICON_NAME, + new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + _this.showExportProject (); + + } + + })); + + } + + public void showExportProject () + { + + QPopup popup = UIUtils.createWizardPopup (Environment.getUIString (LanguageStrings.exportproject, + LanguageStrings.popup, + LanguageStrings.title), + //"Export {Project}", + Constants.PROJECT_EXPORT_ICON_NAME, + null, + new ExportProject (this)); + + popup.setDraggable (this); + + popup.resize (); + this.showPopupAt (popup, + UIUtils.getCenterShowPosition (this, + popup), + false); + + } + + public void showImportProject () + { + + this.showImportProject (null); + + } + + public void showImportProject (File f) + { + + this.removeNamedPopup ("import-project"); + + try + { + + ImportProject im = new ImportProject (this); + + if (f != null) + { + + im.setFile (f); + im.setAddToProjectOnly (true); + + } + + QPopup popup = UIUtils.createWizardPopup (Environment.getUIString (LanguageStrings.importproject, + LanguageStrings.popup, + LanguageStrings.title), + //"Import a File or {Project}", + Constants.PROJECT_IMPORT_ICON_NAME, + null, + im); + + popup.setDraggable (this); + + popup.resize (); + this.showPopupAt (popup, + UIUtils.getCenterShowPosition (this, + popup), + false); + + this.addNamedPopup ("import-project", + popup); + + } catch (Exception e) { + + Environment.logError ("Unable to show import project for file: " + + f, + e); + + UIUtils.showErrorMessage (this, + Environment.getUIString (LanguageStrings.importproject, + LanguageStrings.actionerror)); + //"Unable to show import project wizard, please contact Quoll Writer support for assistance."); + + } + + } + + public Action getAction (int name, + final NamedObject other) + { + + Action a = super.getAction (name, + other); + + if (a != null) + { + + return a; + + } + + final ProjectViewer pv = this; + + if (name == ProjectViewer.VIEW_CHAPTER_INFO_ACTION) + { + + return new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + try + { + + pv.viewChapterInformation ((Chapter) other); + + } catch (Exception e) { + + Environment.logError ("Unable to view chapter information for chapter: " + + other, + e); + + UIUtils.showErrorMessage (pv, + Environment.getUIString (LanguageStrings.project, + LanguageStrings.actions, + LanguageStrings.viewchapterinformation, + LanguageStrings.actionerror)); + //"Unable to view chapter information."); + + } + + } + + }; + + } + + if (name == ProjectViewer.NEW_NOTE_TYPE_ACTION) + { + + return new AddNewNoteTypeActionHandler (this); + + } + + if (name == ProjectViewer.MANAGE_NOTE_TYPES_ACTION) + { + + return new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + pv.showEditNoteTypes (); + + } + + }; + + } +/* + if (name == ProjectViewer.MANAGE_ITEM_TYPES_ACTION) + { + + return new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + pv.showEditItemTypes (); + + } + + }; + + } +*/ + if (name == ProjectViewer.NEW_CHAPTER_ACTION) + { + + if (other instanceof Chapter) + { + + Chapter c = (Chapter) other; + + return new AddChapterActionHandler (c.getBook (), + c, + pv); + + } + + if (other instanceof Book) + { + + return new AddChapterActionHandler ((Book) other, + null, + pv); + + } + + } + + if (name == ProjectViewer.EDIT_PLOT_OUTLINE_ITEM_ACTION) + { + + return new ActionAdapter () + { + + public void actionPerformed (final ActionEvent ev) + { + + final Chapter c = ((ChapterItem) other).getChapter (); + + pv.viewObject (c, + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + QuollEditorPanel qep = (QuollEditorPanel) pv.getEditorForChapter (c); + + qep.editOutlineItem ((OutlineItem) other); + + } + + }); + + } + + }; + + } + + if (name == ProjectViewer.EDIT_NOTE_ACTION) + { + + return new ActionAdapter () + { + + public void actionPerformed (final ActionEvent ev) + { + + final Chapter c = ((Note) other).getChapter (); + + pv.viewObject (c, + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + QuollEditorPanel qep = (QuollEditorPanel) pv.getEditorForChapter (c); + + qep.editNote ((Note) other); + + } + + }); + + } + + }; + + } + + if (name == ProjectViewer.EDIT_SCENE_ACTION) + { + + return new ActionAdapter () + { + + public void actionPerformed (final ActionEvent ev) + { + + final Chapter c = ((ChapterItem) other).getChapter (); + + pv.viewObject (c, + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + QuollEditorPanel qep = (QuollEditorPanel) pv.getEditorForChapter (c); + + qep.editScene ((Scene) other); + + } + + }); + + } + + }; + + } + + if (name == ProjectViewer.DELETE_PLOT_OUTLINE_ITEM_ACTION) + { + + return new DeleteChapterItemActionHandler ((OutlineItem) other, + this, + false); + + } + + if (name == ProjectViewer.DELETE_SCENE_ACTION) + { + + return new DeleteChapterItemActionHandler ((Scene) other, + this, + false); + + } + + if (name == ProjectViewer.DELETE_NOTE_ACTION) + { + + return new DeleteChapterItemActionHandler ((Note) other, + this, + false); + + } + + if (name == ProjectViewer.NEW_PLOT_OUTLINE_ITEM_ACTION) + { + + return new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + Chapter c = (Chapter) other; + + QuollEditorPanel qep = (QuollEditorPanel) pv.getEditorForChapter (c); + + String text = qep.getEditor ().getText (); + + int pos = 0; + + if (text != null) + { + + pos = text.length (); + + } + + pv.scrollTo (c, + pos); + + OutlineItem o = new OutlineItem (-1, + c); + + new ChapterItemActionHandler (o, + qep, + AbstractFormPopup.ADD, + pos).actionPerformed (ev); + + } + + }; + + } + + /* + if (name == ProjectViewer.NEW_SCENE_ACTION) + { + + return new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + Chapter c = (Chapter) other; + + QuollEditorPanel qep = (QuollEditorPanel) pv.getEditorForChapter (c); + + String text = qep.getEditor ().getText (); + + int pos = 0; + + if (text != null) + { + + pos = text.length (); + + } + + pv.scrollTo (c, + pos); + + Scene s = new Scene (-1, + c); + + new ChapterItemActionHandler (s, + qep, + AbstractFormPopup.ADD, + pos).actionPerformed (ev); + + } + + }; + + } +*/ + if (name == ProjectViewer.NEW_SCENE_BELOW_ACTION) + { + + return new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + Chapter c = (Chapter) other; + + QuollEditorPanel qep = (QuollEditorPanel) pv.getEditorForChapter (c); + + String text = qep.getEditor ().getText (); + + int pos = 0; + + if (text != null) + { + + pos = text.length (); + + } + + pv.scrollTo (c, + pos); + + Scene s = new Scene (-1, + c); + + new ChapterItemActionHandler (s, + qep, + AbstractFormPopup.ADD, + pos).actionPerformed (ev); + + } + + }; + + } + + if (name == ProjectViewer.NEW_NOTE_ACTION) + { + + return new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + Chapter c = (Chapter) other; + + QuollEditorPanel qep = pv.getEditorForChapter (c); + + String text = qep.getEditor ().getText (); + + int pos = 0; + + if (text != null) + { + + pos = text.length (); + + } + + pv.scrollTo (c, + pos); + + new NoteActionHandler (c, + qep, + pos).actionPerformed (ev); + + } + + }; + + } + + if (name == ProjectViewer.NEW_PLOT_OUTLINE_ITEM_BELOW_ACTION) + { + + Chapter c = (Chapter) other; + + OutlineItem o = new OutlineItem (-1, + c); + + return new ChapterItemActionHandler (o, + this.getEditorForChapter (c), + AbstractFormPopup.ADD, + 0); + + } + + if (name == ProjectViewer.NEW_BOOK_ACTION) + { + + //return UIUtils.getComingSoonAction (pv); + + /* + return new AddBookActionHandler ((Book) other, + pv); + */ + } + + throw new IllegalArgumentException ("Action: " + + name + + " not known."); + + } + + public void handleNewProject () + throws Exception + { + + Book b = this.proj.getBooks ().get (0); + + Chapter c = b.getFirstChapter (); + + // Create a new chapter for the book. + if (c == null) + { + + c = new Chapter (b, + Environment.getDefaultChapterName ()); + + b.addChapter (c); + + } + + this.saveObject (c, + true); + + // Refresh the chapter tree. + this.reloadTreeForObjectType (c.getObjectType ()); + + this.handleOpenProject (); + + this.editChapter (c); + + } + + @Override + public void saveObject (NamedObject o, + boolean doInTransaction) + throws GeneralException + { + + super.saveObject (o, + doInTransaction); + + this.scheduleUpdateAppearsInChaptersTree (); + + } + + public String getViewerIcon () + { + + return Project.OBJECT_TYPE; + + //return this.proj.getObjectType (); + + } + + public String getViewerTitle () + { + + return String.format (getUIString (project,viewertitle), + this.proj.getName ()); + + } + + public void handleHTMLPanelAction (String v) + { + + StringTokenizer t = new StringTokenizer (v, + ",;"); + + if (t.countTokens () > 1) + { + + while (t.hasMoreTokens ()) + { + + String tok = t.nextToken ().trim (); + + this.handleHTMLPanelAction (tok); + + } + + return; + + } + + if (v.equals ("import")) + { + + this.showImportProject (); + + return; + + } + + if (v.equals ("export")) + { + + this.showExportProject (); + + return; + + } + + if (v.equals ("problemfinder")) + { + + QuollPanel qp = this.getCurrentlyVisibleTab (); + + if (qp instanceof QuollEditorPanel) + { + + ((QuollEditorPanel) qp).showProblemFinder (); + + } + + return; + + } + + if (v.equals ("problemfinderconfig")) + { + + this.showProblemFinderRuleConfig (); + + return; + + } + + if (v.equals ("ideaboard")) + { + + this.viewIdeaBoard (); + + return; + + } + + super.handleHTMLPanelAction (v); + + } + + public void handleOpenProject () + { + + //this.initProjectItemBoxes (); + + final ProjectViewer _this = this; + + /** + *TODO: CHECK if needed still + this.objectTypePropChangedListener = new PropertyChangedListener () + { + + @Override + public void propertyChanged (PropertyChangedEvent ev) + { + + if (ev.getChangeType ().equals (UserPropertyHandler.VALUE_CHANGED)) + { + + java.util.List toSave = new ArrayList (); + + java.util.List objs = _this.getProject ().getQObjects (); + + for (QObject o : objs) + { + + if (o.getType ().equals ((String) ev.getOldValue ())) + { + + o.setType ((String) ev.getNewValue ()); + + toSave.add (o); + + } + + if (toSave.size () > 0) + { + + try + { + + _this.saveObjects (toSave, + true); + + } catch (Exception e) + { + + Environment.logError ("Unable to save qobjects: " + + toSave + + " with new type: " + + ev.getNewValue (), + e); + + UIUtils.showErrorMessage (_this, + "Unable to change type"); + + } + + } + + } + + } + + } + + }; + + Environment.getUserPropertyHandler (Constants.OBJECT_TYPES_PROPERTY_NAME).addPropertyChangedListener (this.objectTypePropChangedListener); + */ + + // Called whenever a note type is changed. + this.noteTypePropChangedListener = new PropertyChangedListener () + { + + @Override + public void propertyChanged (PropertyChangedEvent ev) + { + + if (ev.getChangeType ().equals (UserPropertyHandler.VALUE_CHANGED)) + { + + java.util.List toSave = new ArrayList (); + + Set objs = _this.getAllNotes (); + + for (Note o : objs) + { + + if (o.getType ().equals ((String) ev.getOldValue ())) + { + + o.setType ((String) ev.getNewValue ()); + + toSave.add (o); + + } + + if (toSave.size () > 0) + { + + try + { + + _this.saveObjects (toSave, + true); + + } catch (Exception e) + { + + Environment.logError ("Unable to save notes: " + + toSave + + " with new type: " + + ev.getNewValue (), + e); +// TODO: Language string + UIUtils.showErrorMessage (_this, + "Unable to change type"); + + } + + } + + } + + _this.reloadTreeForObjectType (Note.OBJECT_TYPE); + + } + + } + + }; + + Environment.getUserPropertyHandler (Constants.NOTE_TYPES_PROPERTY_NAME).addPropertyChangedListener (this.noteTypePropChangedListener); + + this.scheduleUpdateAppearsInChaptersTree (); + + } + + /* + private void initProjectItemBoxes () + { + + String openTypes = this.proj.getProperty (Constants.ASSETS_TREE_OPEN_TYPES_PROPERTY_NAME); + + Set open = new HashSet (); + + if (openTypes != null) + { + + // Split on : + StringTokenizer t = new StringTokenizer (openTypes, + "|"); + + while (t.hasMoreTokens ()) + { + + String tok = t.nextToken ().trim (); + + open.add (tok); + + } + + } + + this.sideBar.initOpenObjectTypes (open); + + } +*/ + public void handleItemChangedEvent (ItemChangedEvent ev) + { + + Object o = ev.getChangedObject (); + + if (o instanceof DataObject) + { + + if (ev.getChangedObject () instanceof Chapter) + { + + this.reloadTreeForObjectType (((DataObject) o).getObjectType ()); + + } + + } + /* + if (ev.getChangedObject () instanceof Chapter) + { + + this.reloadTreeForObjectType (Chapter.OBJECT_TYPE); + + } + + if (ev.getChangedObject () instanceof Note) + { + + this.reloadTreeForObjectType (Note.OBJECT_TYPE); + + } + */ + } + + public void showObjectInTree (String treeObjType, + NamedObject obj) + { + + this.sideBar.showObjectInTree (treeObjType, + obj); + + } + + public void reloadTreeForObjectType (String objType) + { + + this.sideBar.reloadTreeForObjectType (objType); + + } + + public void reloadTreeForObjectType (NamedObject obj) + { + + this.sideBar.reloadTreeForObjectType (obj.getObjectType ()); + + } + + public void reloadNoteTree () + { + + this.reloadTreeForObjectType (Note.OBJECT_TYPE); + + } + + public void reloadChapterTree () + { + + this.reloadTreeForObjectType (Chapter.OBJECT_TYPE); + + } + + @Override + public void doSaveState () + { + + } + + public QuollEditorPanel getEditorForChapter (Chapter c) + { + + for (QuollPanel qp : this.getAllQuollPanelsForObject (c)) + { + + if (qp instanceof FullScreenQuollPanel) + { + + qp = ((FullScreenQuollPanel) qp).getChild (); + + } + + if (qp instanceof QuollEditorPanel) + { + + return (QuollEditorPanel) qp; + + } + + } + + return null; + + } + + public boolean viewTimeline () + { + + final ProjectViewer _this = this; + + Timeline tp = null; + + try + { + + tp = new Timeline (this); + + tp.init (); + + } catch (Exception e) { + + Environment.logError ("Unable to init timeline", + e); + + UIUtils.showErrorMessage (_this, + "Unable to show timeline"); + + return false; + + } + + final TabHeader th = this.addPanel (tp); + + this.setPanelVisible (tp); + + return true; + + } + + public boolean editChapter (Chapter c) + { + + return this.editChapter (c, + null); + + } + + public boolean closePanel (QuollPanel qp) + { + + if (qp instanceof QuollEditorPanel) + { + + ((QuollEditorPanel) qp).getEditor ().getDocument ().removeDocumentListener (this); + + } + + return super.closePanel (qp); + + } + + @Override + public void insertUpdate (DocumentEvent ev) + { + + this.fireChaperDocumentChangedEvent (ev); + + } + + @Override + public void changedUpdate (DocumentEvent ev) + { + + this.fireChaperDocumentChangedEvent (ev); + + } + + @Override + public void removeUpdate (DocumentEvent ev) + { + + this.fireChaperDocumentChangedEvent (ev); + + } + + /** + * This is a top-level action so it can handle showing the user a message, it returns a boolean to indicate + * whether the chapter has been opened for editing. + */ + public boolean editChapter (final Chapter c, + final ActionListener doAfterView) + { + + // Check our tabs to see if we are already editing this chapter, if so then just switch to it instead. + QuollEditorPanel qep = (QuollEditorPanel) this.getQuollPanelForObject (c); + + if (qep != null) + { + + this.setPanelVisible (qep); + + this.getEditorForChapter (c).getEditor ().grabFocus (); + + this.getEditorForChapter (c).getEditor ().getDocument ().addDocumentListener (this); + + if (doAfterView != null) + { + + UIUtils.doActionWhenPanelIsReady (qep, + doAfterView, + c, + "afterview"); + + } + + return true; + + } + + final ProjectViewer _this = this; + + try + { + + qep = new QuollEditorPanel (this, + c); + + qep.init (); + + } catch (Exception e) + { + + Environment.logError ("Unable to edit chapter: " + + c, + e); + + UIUtils.showErrorMessage (_this, + String.format (Environment.getUIString (LanguageStrings.project, + LanguageStrings.actions, + LanguageStrings.editchapter, + LanguageStrings.actionerror), + c.getName ())); + //"Unable to edit {chapter}: " + + //c.getName ()); + + return false; + + } + + final TabHeader th = this.addPanel (qep); + + qep.addActionListener (new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + if (ev.getID () == QuollPanel.UNSAVED_CHANGES_ACTION_EVENT) + { + + th.setComponentChanged (true); + + } + + } + + }); + + this.addNameChangeListener (c, + qep); + + // Open the tab :) + return this.editChapter (c, + doAfterView); + + } + + public boolean viewObject (DataObject d) + { + + if (d == null) + { + + return false; + + } + + return this.viewObject (d, + null); + + } + + public boolean viewObject (final DataObject d, + final ActionListener doAfterView) + { + + final ProjectViewer _this = this; + + if (d instanceof ChapterItem) + { + + final ChapterItem ci = (ChapterItem) d; + + this.viewObject (ci.getChapter (), + new ActionListener () + { + + public void actionPerformed (ActionEvent ev) + { + + _this.getEditorForChapter (ci.getChapter ()).showItem (ci); + + } + + }); + + return true; + + } + + if (d.getObjectType ().equals (StatisticsPanel.OLD_WORD_COUNT_PANEL_ID)) + { + + return this.viewStatistics (); + + } + + if (d instanceof Chapter) + { + + Chapter c = (Chapter) d; + + if (d.getObjectType ().equals (Chapter.INFORMATION_OBJECT_TYPE)) + { + + try + { + + return this.viewChapterInformation (c); + + } catch (Exception e) { + + Environment.logError ("Unable to view chapter information for chapter: " + + c, + e); + + UIUtils.showErrorMessage (_this, + Environment.getUIString (LanguageStrings.project, + LanguageStrings.actions, + LanguageStrings.viewchapterinformation, + LanguageStrings.actionerror)); + //"Unable to show chapter information."); + + } + + } else + { + + return this.editChapter (c, + doAfterView); + + } + + } + + if (d instanceof Asset) + { + + return this.viewAsset ((Asset) d, + doAfterView); + + } +/* + if (d instanceof Note) + { + + this.viewNote ((Note) d); + + return true; + + } + */ +/* + if (d instanceof OutlineItem) + { + + this.viewOutlineItem ((OutlineItem) d); + + return true; + + } +*/ + // Record the error, then ignore. + Environment.logError ("Unable to open object: " + d); + + return false; + + } + /* + public void viewNote (Note n) + { + + try + { + + // Need to change this. + if (n.getObject () instanceof Chapter) + { + + Chapter c = (Chapter) n.getObject (); + + this.editChapter (c); + + QuollEditorPanel qep = this.getEditorForChapter (c); + + qep.showNote (n); + + return; + + } + + } catch (Exception e) + { + + Environment.logError ("Unable to show note: " + + n, + e); + + UIUtils.showErrorMessage (this, + "Unable to show " + Environment.getObjectTypeName (n).toLowerCase () + "."); + + } + + } + */ +/* + public void viewOutlineItem (OutlineItem n) + { + + try + { + + this.editChapter (n.getChapter ()); + + QuollEditorPanel qep = this.getEditorForChapter (n.getChapter ()); + + qep.showOutlineItem (n); + + } catch (Exception e) + { + + Environment.logError ("Unable to show outline item: " + + n, + e); + + UIUtils.showErrorMessage (this, + "Unable to show " + Environment.getObjectTypeName (n).toLowerCase ()); + + } + + } +*/ + public boolean openPanel (String id) + { + + if (id.equals (IdeaBoard.PANEL_ID)) + { + + return this.viewIdeaBoard (); + + } + + if (id.equals (Timeline.PANEL_ID)) + { + + return this.viewTimeline (); + + } + + return false; + + } + + public boolean showAdvertiseProjectPanel () + { + + AdvertiseProjectPanel ap = (AdvertiseProjectPanel) this.getQuollPanel (AdvertiseProjectPanel.PANEL_ID); + + if (ap == null) + { + + try + { + + ap = new AdvertiseProjectPanel (this); + + ap.init (); + + } catch (Exception e) + { + + Environment.logError ("Unable to view the advertise project panel", + e); + + UIUtils.showErrorMessage (this, + "Unable to open panel"); + + return false; + + } + + this.addPanel (ap); + + } + + this.setPanelVisible (ap); + + return true; + + + } +/* + public boolean showRegisterAsAnEditorPanel () + { + + RegisterAsAnEditorPanel ap = (RegisterAsAnEditorPanel) this.getQuollPanel (RegisterAsAnEditorPanel.PANEL_ID); + + if (ap == null) + { + + try + { + + ap = new RegisterAsAnEditorPanel (this); + + ap.init (); + + } catch (Exception e) + { + + Environment.logError ("Unable to view the register as an editor panel", + e); + + UIUtils.showErrorMessage (this, + "Unable to open panel"); + + return false; + + } + + this.addPanel (ap); + + } + + this.setPanelVisible (ap); + + return true; + + + } +*/ + public boolean viewIdeaBoard () + { + + IdeaBoard avp = (IdeaBoard) this.getQuollPanel (IdeaBoard.PANEL_ID); + + if (avp == null) + { + + try + { + + avp = new IdeaBoard (this); + + avp.init (); + + } catch (Exception e) + { + + Environment.logError ("Unable to view idea board", + e); + + UIUtils.showErrorMessage (this, + Environment.getUIString (LanguageStrings.ideaboard, + LanguageStrings.actionerror)); + //"Unable to view idea board"); + + return false; + + } + + this.addPanel (avp); + + } + + this.setPanelVisible (avp); + + return true; + + } + + public boolean viewAsset (Asset a) + { + + return this.viewAsset (a, + null); + + } + + /** + * Add an asset in a tab. + * + * @param a The asset to add, if it already has a key then an exception is thrown. + */ + public void showAddAsset (final Asset a, + final ActionListener doAfterAdd) + { + + if (a.getKey () != null) + { + + throw new IllegalStateException ("Asset already has a key."); + + } + + AddAssetPanel avp = null; + + try + { + + avp = new AddAssetPanel (this, + a); + + avp.init (); + + } catch (Exception e) + { + + Environment.logError ("Unable to add asset: " + + a, + e); + + UIUtils.showErrorMessage (this, + String.format (Environment.getUIString (LanguageStrings.project, + LanguageStrings.actions, + LanguageStrings.viewaddasset, + LanguageStrings.actionerror), + a.getObjectTypeName ())); + //"Unable to add " + + //a.getObjectTypeName ()); + + return; + + } + + this.addPanel (avp); + + this.setPanelVisible (avp); + + if (doAfterAdd != null) + { + + UIUtils.doActionWhenPanelIsReady (avp, + doAfterAdd, + a, + "afterview"); + + } + + } + + public void editAsset (final Asset a, + final ActionListener doAfterEdit) + { + + final ProjectViewer _this = this; + + // Display the object then edit it. + this.viewAsset (a, + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + AssetViewPanel p = (AssetViewPanel) _this.getQuollPanelForObject (a); + + if (p == null) + { + + Environment.logError ("Unable to edit asset: " + + a); + + UIUtils.showErrorMessage (_this, + String.format (Environment.getUIString (LanguageStrings.assets, + LanguageStrings.edit, + LanguageStrings.actionerror), + a.getObjectTypeName (), + a.getName ())); + //Environment.replaceObjectNames (String.format ("Unable to edit %s", + // a.getObjectTypeName ()))); + + return; + + } + + p.editObject (); + + if (doAfterEdit != null) + { + + UIUtils.doLater (doAfterEdit); + + } + + } + + }); + + } + + /** + * This is a top-level action so it can handle showing the user a message, it returns a boolean to indicate + * whether the asset is viewed. + */ + public boolean viewAsset (final Asset a, + final ActionListener doAfterView) + { + + ProjectObjectQuollPanel p = this.getQuollPanelForObject (a); + + if (p != null) + { + + this.setPanelVisible (p); + + if (doAfterView != null) + { + + UIUtils.doActionWhenPanelIsReady (p, + doAfterView, + a, + "afterview"); + + } + + return true; + + } + + final ProjectViewer _this = this; + + AssetViewPanel avp = null; + + try + { + + avp = new AssetViewPanel (this, + a); + + avp.init (); + + } catch (Exception e) + { + + Environment.logError ("Unable to view asset: " + + a, + e); + + UIUtils.showErrorMessage (_this, + String.format (Environment.getUIString (LanguageStrings.assets, + LanguageStrings.view, + LanguageStrings.actionerror), + a.getObjectTypeName (), + a.getName ())); + + return false; + + } + + this.addPanel (avp); + + this.addNameChangeListener (a, + avp); + + // Open the tab :) + return this.viewAsset (a, + doAfterView); + + } + + protected void addNameChangeListener (final NamedObject n, + final ProjectObjectQuollPanel qp) + { + + final ProjectViewer _this = this; + + qp.addObjectPropertyChangedListener (new PropertyChangedListener () + { + + @Override + public void propertyChanged (PropertyChangedEvent ev) + { + + if (ev.getChangeType ().equals (NamedObject.NAME)) + { + + _this.setTabHeaderTitle (qp, + qp.getTitle ()); + + _this.informTreeOfNodeChange (n, + _this.getTreeForObjectType (n.getObjectType ())); + + } + + } + + }); + + } + + public void viewWordCloud () + { + + WordCloudPanel wp = (WordCloudPanel) this.getQuollPanel (WordCloudPanel.PANEL_ID); + + if (wp != null) + { + + this.setPanelVisible (wp); + + return; + + } + + try + { + + wp = new WordCloudPanel (this); + + wp.init (); + + } catch (Exception e) + { + + Environment.logError ("Unable to show word cloud panel", + e); + + UIUtils.showErrorMessage (this, + "Unable to show word cloud panel"); + + return; + + } + + this.addPanel (wp); + + // Open the tab :) + this.viewWordCloud (); + + } + + /** + * This is a top-level action so it can handle showing the user a message, it returns a boolean to indicate + * whether the chapter information is viewed. + */ + public boolean viewChapterInformation (final Chapter c) + throws GeneralException + { + + ChapterInformationSideBar cb = new ChapterInformationSideBar (this, + c); + + this.addSideBar (cb); + + this.showSideBar (cb.getId ()); + + return true; + + } + + public JTree getTreeForObjectType (String objType) + { + + return this.sideBar.getTreeForObjectType (objType); + + } + + public void openObjectSection (Asset a) + { + + this.sideBar.setObjectsOpen (a.getUserConfigurableObjectType ().getObjectTypeId ()); + + } + + public void openObjectSection (String objType) + { + + this.sideBar.setObjectsOpen (objType); + + } + + public void addChapterToTreeAfter (Chapter newChapter, + Chapter addAfter) + { + + DefaultTreeModel model = (DefaultTreeModel) this.getChapterTree ().getModel (); + + DefaultMutableTreeNode cNode = new DefaultMutableTreeNode (newChapter); + + if (addAfter == null) + { + + // Get the book node. + TreePath tp = UIUtils.getTreePathForUserObject ((DefaultMutableTreeNode) model.getRoot (), + newChapter.getBook ()); + + if (tp != null) + { + + DefaultMutableTreeNode node = (DefaultMutableTreeNode) tp.getLastPathComponent (); + + model.insertNodeInto (cNode, + (MutableTreeNode) node, + 0); + + } else + { + + DefaultMutableTreeNode root = (DefaultMutableTreeNode) model.getRoot (); + + model.insertNodeInto (cNode, + root, + root.getChildCount ()); + + } + + } else + { + + // Get the "addAfter" node. + DefaultMutableTreeNode node = (DefaultMutableTreeNode) UIUtils.getTreePathForUserObject ((DefaultMutableTreeNode) model.getRoot (), + addAfter).getLastPathComponent (); + + model.insertNodeInto (cNode, + (MutableTreeNode) node.getParent (), + node.getParent ().getIndex (node) + 1); + + } + + this.getChapterTree ().setSelectionPath (new TreePath (cNode.getPath ())); + + } + + public JTree getNoteTree () + { + + return this.getTreeForObjectType (Note.OBJECT_TYPE); + + } + + public JTree getChapterTree () + { + + return this.getTreeForObjectType (Chapter.OBJECT_TYPE); + + } + + public boolean deleteIdeaType (IdeaType it) + { + + try + { + + this.dBMan.deleteObject (it, + false, + null); + + this.proj.removeObject (it); + + this.fireProjectEvent (it.getObjectType (), + ProjectEvent.DELETE, + it); + + return true; + + } catch (Exception e) + { + + Environment.logError ("Unable to delete idea type: " + it, + e); + + UIUtils.showErrorMessage (this, + Environment.getUIString (LanguageStrings.ideaboard, + LanguageStrings.ideatypes, + LanguageStrings.delete, + LanguageStrings.actionerror)); + //"Unable to delete Idea Type"); + + return false; + + } + + } + + public boolean deleteIdea (Idea i) + { + + try + { + + this.dBMan.deleteObject (i, + false, + null); + + this.fireProjectEvent (i.getObjectType (), + ProjectEvent.DELETE, + i); + + return true; + + } catch (Exception e) + { + + Environment.logError ("Unable to delete idea: " + i, + e); + + UIUtils.showErrorMessage (this, + Environment.getUIString (LanguageStrings.ideaboard, + LanguageStrings.ideas, + LanguageStrings.delete, + LanguageStrings.actionerror)); + //"Unable to delete Idea"); + + return false; + + } + + } + + public boolean updateIdeaType (IdeaType it) + { + + try + { + + this.dBMan.saveObject (it, + null); + + this.fireProjectEvent (it.getObjectType (), + ProjectEvent.EDIT, + it); + + return true; + + } catch (Exception e) + { + + Environment.logError ("Unable to save idea type: " + it, + e); + + UIUtils.showErrorMessage (this, + Environment.getUIString (LanguageStrings.ideaboard, + LanguageStrings.ideatypes, + LanguageStrings.edit, + LanguageStrings.actionerror)); + //"Unable to save Idea Type"); + + return false; + + } + + } + + public void deleteChapter (Chapter c) + { + + try + { + + // Remove the chapter from the book. + java.util.Set otherObjects = c.getOtherObjectsInLinks (); + + this.dBMan.deleteObject (c, + false, + null); + + Book b = c.getBook (); + + b.removeChapter (c); + + this.refreshObjectPanels (otherObjects); + + // See if there is a chapter information sidebar. + this.removeSideBar ("chapterinfo-" + c.getKey ()); + + this.fireProjectEvent (c.getObjectType (), + ProjectEvent.DELETE, + c); + + } catch (Exception e) + { + + Environment.logError ("Unable to delete chapter: " + c, + e); + + UIUtils.showErrorMessage (this, + String.format (Environment.getUIString (LanguageStrings.project, + LanguageStrings.actions, + LanguageStrings.deletechapter, + LanguageStrings.actionerror), + c.getName ())); + //"Unable to delete " + + //Environment.getObjectTypeName (c)); + + return; + + } + + // Inform the chapter tree about the change. + this.reloadTreeForObjectType (c.getObjectType ()); + + this.removeAllSideBarsForObject (c); + + // Remove the tab (if present). + this.removeAllPanelsForObject (c); + + // Notify the note tree about the change. + // We get a copy of the notes here to allow iteration. + Set _notes = new LinkedHashSet (c.getNotes ()); + for (Note n : _notes) + { + + try + { + + this.deleteNote (n, + false); + + } catch (Exception e) + { + + Environment.logError ("Unable to delete note: " + n, + e); + + } + + } + + } + + public void deleteAllAssetsOfType (UserConfigurableObjectType type) + { + + Set assets = this.proj.getAssets (type); + + if (assets == null) + { + + return; + + } + + Set nassets = new LinkedHashSet<> (assets); + + for (Asset a : nassets) + { + + this.deleteAsset (a); + + } + + } + + public void deleteAsset (Asset a) + { + + final ProjectViewer _this = this; + + // Remove the links. + try + { + + // Capture a list of all the object objects in the links, we then need to message + // the linked to panel of any of those. + java.util.Set otherObjects = a.getOtherObjectsInLinks (); + + this.dBMan.deleteObject (a, + false, + null); + + this.proj.removeObject (a); + + this.removeWordFromDictionary (a.getName ()); + //"project"); + //this.removeWordFromDictionary (a.getName () + "'s", + // "project"); + + this.refreshObjectPanels (otherObjects); + + this.fireProjectEvent (a.getObjectType (), + ProjectEvent.DELETE, + a); + + } catch (Exception e) + { + + Environment.logError ("Unable to remove links: " + + a, + e); + + UIUtils.showErrorMessage (this, + String.format (Environment.getUIString (LanguageStrings.assets, + LanguageStrings.delete, + LanguageStrings.actionerror), + a.getObjectTypeName (), + a.getName ())); + //"Unable to remove " + Environment.getObjectTypeName (a)); + + return; + + } + + this.reloadTreeForObjectType (a.getObjectType ()); + + this.removeAllSideBarsForObject (a); + + this.removePanel (a); + + } + + public void addNewIdeaType (IdeaType it) + throws GeneralException + { + + this.dBMan.saveObject (it, + null); + + this.fireProjectEvent (it.getObjectType (), + ProjectEvent.NEW, + it); + + } + + public void addNewIdea (Idea i) + throws GeneralException + { + + this.dBMan.saveObject (i, + null); + + i.getType ().addIdea (i); + + this.fireProjectEvent (i.getObjectType (), + ProjectEvent.NEW, + i); + + } + + public void deleteOutlineItem (OutlineItem it, + boolean doInTransaction) + throws GeneralException + { + + java.util.Set otherObjects = it.getOtherObjectsInLinks (); + + // Get the editor panel for the item. + Chapter c = it.getChapter (); + + this.dBMan.deleteObject (it, + false, + null); + + c.removeOutlineItem (it); + + this.fireProjectEvent (it.getObjectType (), + ProjectEvent.DELETE, + it); + + if (it.getScene () != null) + { + + it.getScene ().removeOutlineItem (it); + + } + + this.refreshObjectPanels (otherObjects); + + QuollEditorPanel qep = this.getEditorForChapter (c); + + if (qep != null) + { + + qep.removeItem (it); + + } + + this.reloadChapterTree (); + + } + + public void deleteObject (NamedObject o, + boolean deleteChildObjects) + throws GeneralException + { + + if (o instanceof ChapterItem) + { + + this.deleteChapterItem ((ChapterItem) o, + deleteChildObjects, + true); + + return; + + } + + this.deleteObject (o); + + } + + public void deleteObject (NamedObject o) + throws GeneralException + { + + if (o instanceof Asset) + { + + this.deleteAsset ((Asset) o); + + } + + if (o instanceof Chapter) + { + + this.deleteChapter ((Chapter) o); + + } + + if (o instanceof ChapterItem) + { + + this.deleteChapterItem ((ChapterItem) o, + true, + true); + + } + + } + + public void deleteChapterItem (ChapterItem ci, + boolean deleteChildObjects, + boolean doInTransaction) + throws GeneralException + { + + if (ci.getObjectType ().equals (Scene.OBJECT_TYPE)) + { + + this.deleteScene ((Scene) ci, + deleteChildObjects, + doInTransaction); + + } + + if (ci.getObjectType ().equals (OutlineItem.OBJECT_TYPE)) + { + + this.deleteOutlineItem ((OutlineItem) ci, + doInTransaction); + + } + + if (ci.getObjectType ().equals (Note.OBJECT_TYPE)) + { + + this.deleteNote ((Note) ci, + doInTransaction); + + } + + } + + public void deleteScene (Scene s, + boolean deleteOutlineItems, + boolean doInTransaction) + throws GeneralException + { + + java.util.Set otherObjects = s.getOtherObjectsInLinks (); + + java.util.List outlineItems = new ArrayList (s.getOutlineItems ()); + + // Get the editor panel for the item. + Chapter c = s.getChapter (); + + this.dBMan.deleteObject (s, + deleteOutlineItems, + null); + + c.removeScene (s); + + this.fireProjectEvent (s.getObjectType (), + ProjectEvent.DELETE, + s); + + this.refreshObjectPanels (otherObjects); + + QuollEditorPanel qep = this.getEditorForChapter (c); + + if (qep != null) + { + + for (OutlineItem oi : outlineItems) + { + + if (deleteOutlineItems) + { + + qep.removeItem (oi); + + } else { + + // Add the item back into the chapter. + c.addChapterItem (oi); + + } + + } + + qep.removeItem (s); + + } + + this.reloadChapterTree (); + + } + + public void reloadAssetTree (Asset a) + { + + this.reloadTreeForObjectType (a.getObjectType ()); + + } + + public void deleteNote (Note n, + boolean doInTransaction) + throws GeneralException + { + + java.util.Set otherObjects = n.getOtherObjectsInLinks (); + + NamedObject obj = n.getObject (); + + // Need to get the links, they may not be setup. + this.setLinks (n); + + this.dBMan.deleteObject (n, + false, + null); + + obj.removeNote (n); + + this.fireProjectEvent (n.getObjectType (), + ProjectEvent.DELETE, + n); + + this.refreshObjectPanels (otherObjects); + + if (obj instanceof Chapter) + { + + QuollEditorPanel qep = this.getEditorForChapter ((Chapter) obj); + + if (qep != null) + { + + qep.removeItem (n); + + } + + } + + this.reloadNoteTree (); + + this.reloadChapterTree (); + + } + + public JTree getAssetTree (Asset a) + { + + return this.getTreeForObjectType (a.getObjectType ()); + + } + /* + public void addToAssetTree (Asset a) + { + + DefaultTreeModel model = (DefaultTreeModel) this.getAssetTree (a).getModel (); + + DefaultMutableTreeNode node = (DefaultMutableTreeNode) model.getRoot (); + + int ind = 0; + + // Now work out where it should go. + en = node.children (); + + while (en.hasMoreElements ()) + { + + DefaultMutableTreeNode ccNode = en.nextElement (); + + Asset ast = (Asset) ccNode.getUserObject (); + + if (a.getName ().toLowerCase ().compareTo (ast.getName ().toLowerCase ()) < 0) + { + + break; + + } + + ind++; + + } + + this.sideBar.reloadTreeForObjectType (a.getObjectType ()); + + this.getAssetTree (a).setSelectionPath (new TreePath (cNode.getPath ())); + + } +*/ + public void chapterTreeChanged (DataObject d) + { + + DefaultTreeModel model = (DefaultTreeModel) this.getChapterTree ().getModel (); + + DefaultMutableTreeNode node = (DefaultMutableTreeNode) UIUtils.getTreePathForUserObject ((DefaultMutableTreeNode) model.getRoot (), + d).getLastPathComponent (); + + model.nodeStructureChanged (node); + + } + + public Set getNotesForType (String t) + { + + Set notes = this.getAllNotes (); + + Set ret = new TreeSet (new ChapterItemSorter ()); + + for (Note n : notes) + { + + if (n.getType ().equals (t)) + { + + ret.add (n); + + } + + } + + return ret; + + } + + public Set getAllNotes () + { + + Set notes = new HashSet (); + + Book b = this.proj.getBooks ().get (0); + + java.util.List chapters = b.getChapters (); + + for (Chapter c : chapters) + { + + notes.addAll (c.getNotes ()); + + } + + return notes; + + } + + @Override + public String getChapterObjectName () + { + + return getUIString (objectnames,plural, Chapter.OBJECT_TYPE); + + } + + public void updateChapterIndexes (Book b) + throws GeneralException + { + + this.dBMan.updateChapterIndexes (b); + + } + + public void saveProblemFinderIgnores (Chapter c) + throws GeneralException + { + + ChapterDataHandler dh = (ChapterDataHandler) this.getDataHandler (Chapter.class); + + dh.saveProblemFinderIgnores (c, + null); + + } + + public Set getProblemFinderIgnores (Rule r) + throws GeneralException + { + + Set ignores = new HashSet (); + + for (Chapter c : this.getProject ().getBook (0).getChapters ()) + { + + Set ignored = c.getProblemFinderIgnores (); + + for (Issue i : ignored) + { + + if (i.getRuleId ().equals (r.getId ())) + { + + ignores.add (i); + + } + + } + + } + + return ignores; + + } + + @Override + public Set findText (String t) + { + + Set res = new LinkedHashSet (); + + // Get the snippets. + Map> snippets = this.getTextSnippets (t); + + if (snippets.size () > 0) + { + + res.add (new ChapterFindResultsBox (getUIString (objectnames,plural, Chapter.OBJECT_TYPE), + Chapter.OBJECT_TYPE, + Chapter.OBJECT_TYPE, + this, + snippets)); + + } + + Set types = Environment.getAssetUserConfigurableObjectTypes (true); + + for (UserConfigurableObjectType type : types) + { + + Set objs = this.proj.getAssetsContaining (t, + type); + + if (objs.size () > 0) + { + + res.add (new AssetFindResultsBox (type, + this, + objs)); + + } + + } + + Set notes = this.proj.getNotesContaining (t); + + if (notes.size () > 0) + { + + res.add (new NamedObjectFindResultsBox (getUIString (objectnames,plural, Note.OBJECT_TYPE), + Note.OBJECT_TYPE, + Note.OBJECT_TYPE, + this, + notes)); + + } + + Set oitems = this.proj.getOutlineItemsContaining (t); + + if (oitems.size () > 0) + { + + res.add (new NamedObjectFindResultsBox (getUIString (objectnames,plural, OutlineItem.OBJECT_TYPE), + OutlineItem.OBJECT_TYPE, + OutlineItem.OBJECT_TYPE, + this, + oitems)); + + } + + Set scenes = this.proj.getScenesContaining (t); + + if (scenes.size () > 0) + { + + res.add (new NamedObjectFindResultsBox (getUIString (objectnames,plural, Scene.OBJECT_TYPE), + Scene.OBJECT_TYPE, + Scene.OBJECT_TYPE, + this, + scenes)); + + } + + return res; + + } + + @Override + public Set getTitleHeaderControlIds () + { + + Set ids = new LinkedHashSet (); + + //ids.add ("wordcloud"); + + ids.add (IDEA_BOARD_HEADER_CONTROL_ID); + + ids.addAll (super.getTitleHeaderControlIds ()); + + return ids; + + } + + @Override + public JComponent getTitleHeaderControl (String id) + { + + if (id == null) + { + + return null; + + } + + final ProjectViewer _this = this; + + JComponent c = null; +/* + if (id.equals ("wordcloud")) + { + + return UIUtils.createButton (Constants.IDEA_ICON_NAME, + Constants.ICON_TITLE_ACTION, + "Click to open the Idea Board", + new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + _this.viewWordCloud (); + + } + + }); + + } +*/ + if (id.equals (IDEA_BOARD_HEADER_CONTROL_ID)) + { + + return UIUtils.createButton (Constants.IDEA_ICON_NAME, + Constants.ICON_TITLE_ACTION, + Environment.getUIString (LanguageStrings.project, + LanguageStrings.title, + LanguageStrings.toolbar, + LanguageStrings.buttons, + LanguageStrings.ideaboard, + LanguageStrings.tooltip), + //"Click to open the Idea Board", + new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + _this.viewIdeaBoard (); + + } + + }); + + } + + return super.getTitleHeaderControl (id); + + } + + public Set getNoteTypes () + { + + Set notes = this.getAllNotes (); + + Set types = new TreeSet (); + + for (Note nn : notes) + { + + types.add (nn.getType ()); + + } + + return types; + + } + + public Map> getNotesAgainstTypes () + { + + // The implementation here is pretty inefficient but we can get away with it due to the generally + // low number of types and notes. + + // Might be worthwhile putting a josql wrapper around this for the grouping. + + Map> ret = new LinkedHashMap (); + + Set notes = this.getAllNotes (); + + Set types = this.getNoteTypes (); + + for (String type : types) + { + + for (Note n : notes) + { + + String t = n.getType (); + + if (t.equals (type)) + { + + Set retNotes = ret.get (t); + + if (retNotes == null) + { + + retNotes = new TreeSet (new ChapterItemSorter ()); + + ret.put (t, + retNotes); + + } + + retNotes.add (n); + + } + + } + + } + + return ret; + + } + + private void scheduleUpdateAppearsInChaptersTree () + { + + final ProjectViewer _this = this; + + this.schedule (new Runnable () + { + + @Override + public void run () + { + + try + { + + _this.doForSideBars (AppearsInChaptersSideBar.class, + new QuollSideBarAction () + { + + public void doAction (final AppearsInChaptersSideBar sb) + { + + final NamedObject n = sb.getForObject (); + + try + { + + final Map> snippets = UIUtils.getObjectSnippets (n, + _this); + + UIUtils.doLater (new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + try + { + + sb.updateSnippets (snippets); + + } catch (Exception e) { + + Environment.logError ("Unable to update appears in chapters sidebar for object: " + + n, + e); + + } + + } + + }); + + } catch (Exception e) { + + Environment.logError ("Unable to update appears in chapters sidebar for object: " + + n, + e); + + } + + } + + }); + + _this.doForPanels (AssetViewPanel.class, + new QuollPanelAction () + { + + public void doAction (final AssetViewPanel vp) + { + + final NamedObject n = vp.getForObject (); + + final AppearsInChaptersEditPanel p = vp.getAppearsInChaptersEditPanel (); + + try + { + + final Map> snippets = UIUtils.getObjectSnippets (n, + _this); + + UIUtils.doLater (new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + try + { + + p.updateChapterTree (snippets); + + } catch (Exception e) { + + Environment.logError ("Unable to update appears in chapters tree(2) for object: " + + n, + e); + + } + + } + + }); + + } catch (Exception e) { + + Environment.logError ("Unable to update appears in chapters tree for object: " + + n, + e); + + } + + } + + }, + false); + + } catch (Exception e) { + + Environment.logError ("Unable to update sidebars/panels", + e); + + } + + } + + }, + // Start in 5s. + 1000, //5 * 1000, + // Run every 30s. + -1); //30 * 1000); + + } + + private void fireChaperDocumentChangedEvent (final DocumentEvent dev) + { + + final ProjectViewer _this = this; + + UIUtils.doActionLater (new ActionListener () + { + + public void actionPerformed (ActionEvent aev) + { + + Set ls = null; + + // Get a copy of the current valid listeners. + synchronized (_this.chapterDocumentListeners) + { + + ls = new LinkedHashSet (_this.chapterDocumentListeners.keySet ()); + + } + + for (DocumentListener l : ls) + { + + // Is this the right way to do this? + // TODO: Find a better way + if (dev.getType () == DocumentEvent.EventType.INSERT) + { + + l.insertUpdate (dev); + + } + + if (dev.getType () == DocumentEvent.EventType.CHANGE) + { + + l.changedUpdate (dev); + + } + + if (dev.getType () == DocumentEvent.EventType.REMOVE) + { + + l.removeUpdate (dev); + + } + + } + + } + + }); + + } + + public void removeChapterDocumentListener (DocumentListener l) + { + + this.chapterDocumentListeners.remove (l); + + } + + /** + * This provides a mechanism for classes to listen to document events from the chapter editors + * without having to explicitly add/remove themselves from the document. This class listens + * for events and will fire to registered listeners. A weak map is used so that listeners + * can fall out of scope without having to worry about removing themselves as listeners (but they + * should if they can to prevent possible leaks). + * + * @param l The listener. + */ + public void addChapterDocumentListener (DocumentListener l) + { + + this.chapterDocumentListeners.put (l, + ProjectViewer.listenerFillObj); + + } + + public ProblemFinderSideBar getProblemFinderSideBar () + { + + return this.problemFinderSideBar; + + } + + public void showProblemFinderRuleSideBar (Rule rule) + { + + try + { + + if (this.problemFinderSideBar == null) + { + + this.problemFinderSideBar = new ProblemFinderSideBar (this, + rule); + + this.addSideBar (this.problemFinderSideBar); + + } else { + + this.problemFinderSideBar.setRule (rule); + + } + + this.showSideBar (ProblemFinderSideBar.ID); + + } catch (Exception e) { + + Environment.logError ("Unable to create/init problem finder sidebar for rule: " + + rule, + e); + + UIUtils.showErrorMessage (this, + Environment.getUIString (LanguageStrings.project, + LanguageStrings.actions, + LanguageStrings.viewproblemfindersidebar, + LanguageStrings.actionerror)); + //"Unable to show problem finder sidebar."); + + } + + } + + public ProblemFinderRuleConfig getProblemFinderRuleConfig () + { + + return this.problemFinderRuleConfig; + + } + + public void showProblemFinderRuleConfig () + { + + String popupName = "problemfinderruleconfig"; + QPopup popup = this.getNamedPopup (popupName); + + if (popup == null) + { + + popup = UIUtils.createClosablePopup (Environment.getUIString (LanguageStrings.problemfinder, + LanguageStrings.config, + LanguageStrings.popup, + LanguageStrings.title), + //"Configure the Problem Finder rules", + Environment.getIcon (Constants.CONFIG_ICON_NAME, + Constants.ICON_POPUP), + null); + + popup.setPopupName (popupName); + + this.addNamedPopup (popupName, + popup); + + this.problemFinderRuleConfig.init (); + + this.problemFinderRuleConfig.setSize (new Dimension (UIUtils.getPopupWidth () - 20, + this.problemFinderRuleConfig.getPreferredSize ().height)); + this.problemFinderRuleConfig.setBorder (UIUtils.createPadding (10, 10, 10, 10)); + + popup.setContent (this.problemFinderRuleConfig); + + popup.setDraggable (this); + + popup.resize (); + this.showPopupAt (popup, + UIUtils.getCenterShowPosition (this, + popup), + false); + + } else { + + popup.setVisible (true); + + } + + this.fireProjectEvent (ProjectEvent.PROBLEM_FINDER_RULE_CONFIG, + ProjectEvent.SHOW); + + } + + public void showUserConfigurableObjectType (UserConfigurableObjectType type) + { + + this.sideBar.addAccordionItem (this.sideBar.createAssetAccordionItem (type)); + + } + + @Override + public void eventOccurred (ProjectEvent ev) + { + + if (ev.getType ().equals (ProjectEvent.TAG)) + { + + if (ev.getAction ().equals (ProjectEvent.DELETE)) + { + + Tag tag = (Tag) ev.getSource (); + + this.removeTag (tag); + + } + + } + + if (ev.getType ().equals (ProjectEvent.USER_OBJECT_TYPE)) + { + + UserConfigurableObjectType type = (UserConfigurableObjectType) ev.getSource (); + + if (ev.getAction ().equals (ProjectEvent.NEW)) + { + + this.sideBar.addAccordionItem (this.sideBar.createAssetAccordionItem (type)); + + return; + + } + + if (ev.getAction ().equals (ProjectEvent.DELETE)) + { + + // Removing an object type. + // Remove it from the project sidebar. + // Remove any tabs for objects of that type. + this.sideBar.removeSection (type); + + if (type.isAssetObjectType ()) + { + + this.removeAssetsOfType (type); + + } + + } + + } + + } + + private void removeAssetsOfType (UserConfigurableObjectType type) + { + + Set assets = this.proj.getAssets (type); + + if (assets == null) + { + + return; + + } + + assets = new HashSet (assets); + + for (Asset a : assets) + { + + this.deleteAsset (a); + + } + + } + + /** + * Remove the specified tag from all objects in this project. + * + * @param tag The tag. + */ + public void removeTag (Tag tag) + { + + try + { + + // Get all objects with the tag, remove the tag. + Set objs = this.proj.getAllObjectsWithTag (tag); + + for (NamedObject o : objs) + { + + o.removeTag (tag); + + } + + this.saveObjects (new ArrayList (objs), + true); + + this.sideBar.removeTagSection (tag); + + } catch (Exception e) { + + Environment.logError ("Unable to remove tag: " + + tag, + e); + + UIUtils.showErrorMessage (this, + Environment.getUIString (LanguageStrings.project, + LanguageStrings.actions, + LanguageStrings.removetag, + LanguageStrings.actionerror)); + //"Unable to remove tag."); + + } + + } + +} diff --git a/src/com/quollwriter/ui/ProjectViewerAction.java b/src/main/java/com/quollwriter/ui/ProjectViewerAction.java similarity index 100% rename from src/com/quollwriter/ui/ProjectViewerAction.java rename to src/main/java/com/quollwriter/ui/ProjectViewerAction.java diff --git a/src/com/quollwriter/ui/ProjectViewerInitable.java b/src/main/java/com/quollwriter/ui/ProjectViewerInitable.java similarity index 100% rename from src/com/quollwriter/ui/ProjectViewerInitable.java rename to src/main/java/com/quollwriter/ui/ProjectViewerInitable.java diff --git a/src/com/quollwriter/ui/QColorChooser.java b/src/main/java/com/quollwriter/ui/QColorChooser.java similarity index 99% rename from src/com/quollwriter/ui/QColorChooser.java rename to src/main/java/com/quollwriter/ui/QColorChooser.java index 17a4eb06..3398faa0 100644 --- a/src/com/quollwriter/ui/QColorChooser.java +++ b/src/main/java/com/quollwriter/ui/QColorChooser.java @@ -25,8 +25,6 @@ import com.jgoodies.forms.factories.*; import com.jgoodies.forms.layout.*; -import com.gentlyweb.utils.*; - import com.quollwriter.*; import com.quollwriter.events.*; import com.quollwriter.ui.components.ChangeAdapter; @@ -449,7 +447,7 @@ public static JPanel getSwatch (Color col, 1, 1, 1, - Environment.getBorderColor ()); + UIUtils.getBorderColor ()); diff --git a/src/com/quollwriter/ui/QuestionWindow.java b/src/main/java/com/quollwriter/ui/QuestionWindow.java similarity index 82% rename from src/com/quollwriter/ui/QuestionWindow.java rename to src/main/java/com/quollwriter/ui/QuestionWindow.java index dca0a379..f7ffd766 100644 --- a/src/com/quollwriter/ui/QuestionWindow.java +++ b/src/main/java/com/quollwriter/ui/QuestionWindow.java @@ -7,16 +7,14 @@ import javax.swing.border.*; import javax.swing.event.*; -import com.gentlyweb.utils.*; - import com.jgoodies.forms.factories.*; import com.quollwriter.*; import com.quollwriter.ui.components.*; -public class QuestionWindow extends PopupWindow +public class QuestionWindow extends PopupWindow { - + private String iconType = null; private JButton[] buttons = null; private String headerTitle = null; @@ -24,10 +22,10 @@ public class QuestionWindow extends PopupWindow private String message = null; private JTextPane error = null; private JComponent content = null; - + public QuestionWindow() { - + this.error = UIUtils.createHelpTextPane ("

    ", null); this.error.setVisible (false); @@ -35,7 +33,7 @@ public QuestionWindow() 0, 5, 0)); - + } public QuestionWindow (AbstractProjectViewer pv) @@ -44,7 +42,7 @@ public QuestionWindow (AbstractProjectViewer pv) this (); } - + public static QuestionWindow create (AbstractProjectViewer viewer, String title, String icon, @@ -53,184 +51,184 @@ public static QuestionWindow create (AbstractProjectViewer viewer, final ActionListener onConfirm, final ActionListener onCancel) { - + final QuestionWindow ti = new QuestionWindow (viewer); - + ti.setHeaderTitle (title); ti.setMessage (message); - + ti.setHeaderIconType (icon); - + ti.setWindowTitle (title); - + JButton confirm = null; JButton cancel = UIUtils.createButton (Environment.getUIString (LanguageStrings.actions, LanguageStrings.cancel), //"Cancel", new ActionListener () { - + @Override public void actionPerformed (ActionEvent ev) { - + if (onCancel != null) { - + onCancel.actionPerformed (new ActionEvent (ti, 0, "cancel")); - + } - + ti.close (); - + } - + }); - + if (onConfirm != null) { - - ActionListener confirmAction = new ActionListener () + + ActionListener confirmAction = new ActionListener () { - + public void actionPerformed (ActionEvent ev) { - + onConfirm.actionPerformed (ev); - + ti.close (); - + } - + }; - + confirm = UIUtils.createButton (confirmButtonLabel, confirmAction); - + } - + JButton[] buts = null; - + if (confirm != null) { - + buts = new JButton[] { confirm, cancel }; - + } else { - + buts = new JButton[] { cancel }; - + } - + ti.setButtons (buts); - + ti.init (); - + return ti; - + } public void setVisible (boolean v) { - + super.setVisible (v); - + } - + public void setMessage (String m) { - + this.message = m; - + } - + public void setError (String mess) { - + this.error.setText ("

    " + mess + "

    "); - + this.error.setMaximumSize (this.error.getPreferredSize ()); - + } - + public void showError (boolean v) { - + this.error.setVisible (v); - + this.resize (); - + } - + public String getMessage () { - + return this.message; - + } - + public String getHelpText () { - + return this.getMessage (); - + } - + public JButton[] getButtons () { - + return this.buttons; - + } - + public void setButtons (JButton[] buts) { - + this.buttons = buts; - + } - + public JComponent getContentPanel () { - + this.content = new Box (BoxLayout.Y_AXIS); - - this.error.setAlignmentX (Component.LEFT_ALIGNMENT); + + this.error.setAlignmentX (Component.LEFT_ALIGNMENT); this.content.add (this.error); - + this.content.setBorder (new EmptyBorder (0, 5, 0, 0)); - + return this.content; - + } - + public String getWindowTitle () { return this.windowTitle; } - + public void setWindowTitle (String t) { - + this.windowTitle = t; - + } public void setHeaderTitle (String t) { - + this.headerTitle = t; - + } - + public String getHeaderTitle () { @@ -240,18 +238,18 @@ public String getHeaderTitle () public void setHeaderIconType (String t) { - + this.iconType = t; - + } - + public String getHeaderIconType () { return this.iconType; } - + public void init () { diff --git a/src/com/quollwriter/ui/QuollChart.java b/src/main/java/com/quollwriter/ui/QuollChart.java similarity index 100% rename from src/com/quollwriter/ui/QuollChart.java rename to src/main/java/com/quollwriter/ui/QuollChart.java diff --git a/src/com/quollwriter/ui/QuollEditorPanel.java.old b/src/main/java/com/quollwriter/ui/QuollEditorPanel.java.old similarity index 100% rename from src/com/quollwriter/ui/QuollEditorPanel.java.old rename to src/main/java/com/quollwriter/ui/QuollEditorPanel.java.old diff --git a/src/main/java/com/quollwriter/ui/QuollPanel.java b/src/main/java/com/quollwriter/ui/QuollPanel.java new file mode 100644 index 00000000..4b19a862 --- /dev/null +++ b/src/main/java/com/quollwriter/ui/QuollPanel.java @@ -0,0 +1,868 @@ +package com.quollwriter.ui; + +import java.awt.*; +import java.awt.event.*; + +import java.io.*; + +import java.text.*; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import javax.swing.plaf.LayerUI; +import javax.swing.*; +import javax.swing.border.*; +import javax.swing.event.*; + +import com.gentlyweb.properties.*; + +import com.jgoodies.forms.builder.*; +import com.jgoodies.forms.factories.*; +import com.jgoodies.forms.layout.*; + +import com.quollwriter.*; + +import com.quollwriter.data.*; + +import com.quollwriter.events.*; + +import com.quollwriter.ui.actionHandlers.*; + +import com.quollwriter.ui.components.ActionAdapter; + +public abstract class QuollPanel extends JRootPane implements Stateful, + PopupsSupported +{ + + public static final int UNSAVED_CHANGES_ACTION_EVENT = 0; + + //public static final int SAVED = 1; + + //public static final String HAS_CHANGES_COMMAND = "hasChanges"; + //public static final String NO_CHANGES_COMMAND = "noChanges"; + + protected E viewer = null; + + protected ActionMap actions = null; + private ActionListener performAction = null; + protected Box content = null; + private java.util.List actionListeners = new ArrayList (); + private JToolBar toolBar = null; + private boolean readyForUse = false; + private MouseEventHandler mouseEventHandler = null; + + public QuollPanel (E viewer) + { + + this.viewer = viewer; + + this.setOpaque (false); + this.setBackground (null); + + this.content = new Box (BoxLayout.Y_AXIS); + this.content.setBackground (UIUtils.getComponentColor ()); + + this.getContentPane ().setBackground (UIUtils.getComponentColor ()); + + this.getContentPane ().add (this.content); + + final QuollPanel _this = this; + + this.mouseEventHandler = this.getDefaultMouseEventHandler (); + + this.getContentPane ().add (new JLayer (this.content, new LayerUI () + { + + @Override + public void installUI(JComponent c) { + super.installUI(c); + // enable mouse motion events for the layer's subcomponents + ((JLayer) c).setLayerEventMask(AWTEvent.MOUSE_EVENT_MASK|AWTEvent.MOUSE_MOTION_EVENT_MASK); + } + + @Override + public void uninstallUI(JComponent c) { + super.uninstallUI(c); + // reset the layer event mask + ((JLayer) c).setLayerEventMask(0); + } + + @Override + public void processMouseEvent (MouseEvent ev, + JLayer l) + { + + if (_this.mouseEventHandler == null) + { + + return; + + } + + if (ev.getID () == MouseEvent.MOUSE_MOVED) + { + + _this.mouseEventHandler.mouseMoved (ev); + + return; + + } + + if (ev.getID () == MouseEvent.MOUSE_RELEASED) + { + + _this.mouseEventHandler.mouseReleased (ev); + + return; + + } + + if (ev.getID () == MouseEvent.MOUSE_PRESSED) + { + + _this.mouseEventHandler.mousePressed (ev); + + return; + + } + + if (ev.getID () == MouseEvent.MOUSE_DRAGGED) + { + + _this.mouseEventHandler.mousePressed (ev); + + return; + + } + + if (ev.getID () == MouseEvent.MOUSE_ENTERED) + { + + _this.mouseEventHandler.mouseEntered (ev); + + return; + + } + + if (ev.getID () == MouseEvent.MOUSE_EXITED) + { + + _this.mouseEventHandler.mouseExited (ev); + + return; + + } + + if (ev.getID () == MouseEvent.MOUSE_CLICKED) + { + + _this.mouseEventHandler.mouseClicked (ev); + + return; + + } + + } + + })); + + this.actions = this.getActionMap (); + + this.performAction = new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + _this.performAction (ev); + + } + + }; + + } + + /** + * Set a mouse event handler for the panel, mouse events are forwarded to the handler + * which should makes it's own checks to determine what event should be handled. + * + * Set to null to prevent the default behavior which is to fill the popup menu. + * + * @param m The mouse event handler. + */ + public void setMouseEventHandler (MouseEventHandler m) + { + + this.mouseEventHandler = m; + + } + + /** + * Get the current mouse event handler. + * + * @return The current mouse event handler. + */ + public MouseEventHandler getMouseEventHandler () + { + + return this.mouseEventHandler; + + } + + /** + * Creates a default mouse event handler that just fills the popup menu for the panel by calling + * this.fillPopupMenu. + * + * @return A default mouse event handler. + */ + public MouseEventHandler getDefaultMouseEventHandler () + { + + final QuollPanel _this = this; + + return new MouseEventHandler () + { + + @Override + public void fillPopup (JPopupMenu m, + MouseEvent ev) + { + + _this.fillPopupMenu (ev, + m); + + } + + }; + + } + + public E getViewer () + { + + return this.viewer; + + } + + public boolean isReadyForUse () + { + + return this.readyForUse; + + } + + public void setReadyForUse (boolean v) + { + + this.readyForUse = true; + + } + + public abstract String getPanelId (); + + public abstract void close (); + + public abstract void init () + throws GeneralException; + + public abstract void getState (Map s); + + public abstract void setState (Map s, + boolean hasFocus); + + public abstract ImageIcon getIcon (int type); + + //public abstract String getIconType (); + + public abstract String getTitle (); + + public abstract void fillToolBar (JToolBar toolBar, + boolean fullScreen); + + public abstract void fillPopupMenu (MouseEvent ev, + JPopupMenu popup); + + public abstract List getTopLevelComponents (); + + //public abstract void refresh (T n); + + @Override + public void remove (Component c) + { + + this.content.remove (c); + + } + + @Override + public Component add (Component c) + { + + if (this.content == null) + { + + super.add (c); + + return c; + + } + + if (c instanceof JComponent) + { + + ((JComponent) c).setAlignmentX (Component.LEFT_ALIGNMENT); + + } + + this.content.add (c); + + return c; + + } + + @Override + public Component add (Component c, + int index) + { + + if (this.content == null) + { + + super.add (c, + index); + + return c; + + } + + if (c instanceof JComponent) + { + + ((JComponent) c).setAlignmentX (Component.LEFT_ALIGNMENT); + + } + + // Add to the content box. + this.content.add (c, + index); + + return c; + + } + + public void performAction (ActionEvent ev) + { + + Action aa = this.actions.get (ev.getActionCommand ()); + + //Action aa = (Action) this.getActionMap ().get (ev.getActionCommand ()); + + if (aa != null) + { + + aa.actionPerformed (ev); + + } + + } + + public void removeActionListener (ActionListener a) + { + + this.actionListeners.remove (a); + + } + + public void addActionListener (ActionListener a) + { + + this.actionListeners.add (a); + + } + + protected void fireActionEvent (ActionEvent ev) + { + + for (int i = 0; i < this.actionListeners.size (); i++) + { + + ActionListener a = (ActionListener) this.actionListeners.get (i); + + a.actionPerformed (ev); + + } + + } + + private JToolBar createToolBar () + { + + JToolBar t = new JToolBar (); + t.setFloatable (false); + t.setOpaque (false); + t.setRollover (true); + t.setAlignmentX (Component.LEFT_ALIGNMENT); + + return t; + + } + + public JToolBar getToolBar (boolean fullScreen) + { + + JToolBar tb = this.createToolBar (); + + this.fillToolBar (tb, + fullScreen); + + this.toolBar = tb; + + return tb; + + } + + public void setToolBarButtonIcon (String actionCommand, + String toolTipText, + String icon) + { + + AbstractButton ab = this.getToolBarButton (actionCommand); + + if (ab == null) + { + + return; + + } + + ab.setToolTipText (toolTipText); + + ab.setIcon (Environment.getIcon (icon, + Constants.ICON_TOOLBAR)); /* was false */ + + this.toolBar.repaint (); + + } + + public AbstractButton getToolBarButton (String actionCommand) + { + + Component[] comps = this.toolBar.getComponents (); + + for (int i = 0; i < comps.length; i++) + { + + Component c = comps[i]; + + if (c instanceof AbstractButton) + { + + AbstractButton ab = (AbstractButton) c; + + if ((ab.getActionCommand () != null) && + (ab.getActionCommand ().equals (actionCommand))) + { + + return ab; + + } + + } + + } + + return null; + + } + + @Override + public void removePopup (Component c) + { + + c.setVisible (false); + + this.getLayeredPane ().remove (c); + + this.getLayeredPane ().validate (); + + this.getLayeredPane ().repaint (); + + // this.content.remove (c); + + // this.content.repaint (); + + } + + public void addPopup (Component c, + boolean hideOnParentClick) + { + + this.addPopup (c, + hideOnParentClick, + false); + + } + + @Override + public void showPopupAt (Component popup, + Component showAt, + boolean hideOnParentClick) + { + + Point po = SwingUtilities.convertPoint (showAt, + 0, + 0, + this.getContentPane ()); + + this.showPopupAt (popup, + po, + hideOnParentClick); + + + } + + @Override + public void showPopupAt (Component c, + Point p, + boolean hideOnParentClick) + { + + Insets ins = this.getInsets (); + + if ((c.getParent () == null) + && + (c.getParent () != this.getLayeredPane ()) + ) + { + + this.addPopup (c, + hideOnParentClick, + false); + + } + + Dimension cp = c.getPreferredSize (); + + if ((p.y + cp.height) > (this.getBounds ().height - ins.top - ins.bottom)) + { + + p = new Point (p.x, + p.y); + + p.y = p.y - (cp.height - c.getBounds ().height); + + } + + if (p.y < 0) + { + + p = new Point (p.x, + p.y); + + p.y = 10; + + } + + if ((p.x + cp.width) > (this.getBounds ().width - ins.left - ins.right)) + { + + p = new Point (p.x, + p.y); + + p.x = p.x - cp.width; + + } + + if (p.x < 0) + { + + p = new Point (p.x, + p.y); + + p.x = 10; + + } + + c.setBounds (p.x, + p.y, + c.getPreferredSize ().width, + c.getPreferredSize ().height); + + c.setVisible (true); + this.validate (); + this.repaint (); + + } + + public void showPopupAt (Component c, + Point p, + String where, + boolean hideOnParentClick) + { + + this.showPopupAt (c, + new Rectangle (p, + c.getPreferredSize ()), + where, + hideOnParentClick); + + } + + public void showPopupAt (Component c, + Rectangle r, + String where, + boolean hideOnParentClick) + { + + Dimension s = c.getPreferredSize (); + + int x = r.x; + int y = r.y; + + if (where == null) + { + + where = "below"; + + } + + if (where.equals ("below")) + { + + y = y + r.height; + + } + + if (where.equals ("above")) + { + + y = y - s.height; + + } + + if (y < 0) + { + + y = r.y + r.height; + + } + + if ((x + s.width) > (this.getWidth ())) + { + + x = this.getWidth () - 20 - s.width; + + } + + if (x < 0) + { + + x = 5; + + } + + this.showPopupAt (c, + new Point (x, + y), + hideOnParentClick); + + } + + @Override + public void addPopup (final Component c, + boolean hideOnClick, + boolean hideViaVisibility) + { + + if (c.getParent () != null) + { + + c.getParent ().remove (c); + + } + + this.getLayeredPane ().add (c, + JLayeredPane.POPUP_LAYER); + + this.getLayeredPane ().moveToFront (c); + + if (hideOnClick) + { + + final QuollPanel _this = this; + final boolean hideVia = hideViaVisibility; + + // Need to do it this way because mouse events aren't being forwarded/delivered. + MouseEventHandler m = new MouseEventHandler () + { + + @Override + public void mouseReleased (MouseEvent ev) + { + + c.setVisible (false); + + if (hideVia) + { + + c.setVisible (false); + + } else + { + + _this.removePopup (c); + + List comps = _this.getTopLevelComponents (); + + if (comps != null) + { + + for (int i = 0; i < comps.size (); i++) + { + + comps.get (i).removeMouseListener (this); + + } + + } + + } + + } + + }; + + List comps = this.getTopLevelComponents (); + + if (comps != null) + { + + for (int i = 0; i < comps.size (); i++) + { + + comps.get (i).addMouseListener (m); + + } + + } + + } + + } + + public void addPerformActionListener (AbstractButton b) + { + + b.addActionListener (this.performAction); + + } + + public ActionListener getPerformActionListener () + { + + return this.performAction; + + } + + public JButton createToolbarButton (String icon, + String toolTipText, + String actionCommand) + { + + return this.createButton (icon, + Constants.ICON_TOOLBAR, + toolTipText, + actionCommand); + + } + + public JButton createButton (String icon, + int iconType, + String toolTipText, + String actionCommand) + { + + JButton but = UIUtils.createButton (icon, + iconType, + toolTipText, + this.performAction); + + but.setActionCommand (actionCommand); + + return but; + + } + + public JButton createButton (String icon, + int iconType, + String toolTipText, + String actionCommand, + ActionListener list) + { + + JButton but = UIUtils.createButton (icon, + iconType, + toolTipText, + list); + + but.setActionCommand (actionCommand); + + return but; + + } + + public JMenuItem createMenuItem (String label, + String icon, + String actionCommand, + KeyStroke accel, + ActionListener list) + { + + JMenuItem mi = UIUtils.createMenuItem (label, + icon, + list); + + mi.setActionCommand (actionCommand); + + mi.setAccelerator (accel); + + return mi; + + + } + + public JMenuItem createMenuItem (String label, + String icon, + String actionCommand, + KeyStroke accel) + { + + JMenuItem mi = this.createMenuItem (label, + icon, + actionCommand); + + mi.setAccelerator (accel); + + return mi; + + + } + + public JMenuItem createMenuItem (String label, + String icon, + String actionCommand) + { + + JMenuItem mi = UIUtils.createMenuItem (label, + icon, + this.performAction); + + mi.setActionCommand (actionCommand); + + return mi; + + } + +} diff --git a/src/com/quollwriter/ui/QuollPanelAction.java b/src/main/java/com/quollwriter/ui/QuollPanelAction.java similarity index 100% rename from src/com/quollwriter/ui/QuollPanelAction.java rename to src/main/java/com/quollwriter/ui/QuollPanelAction.java diff --git a/src/com/quollwriter/ui/RefreshablePanel.java b/src/main/java/com/quollwriter/ui/RefreshablePanel.java similarity index 100% rename from src/com/quollwriter/ui/RefreshablePanel.java rename to src/main/java/com/quollwriter/ui/RefreshablePanel.java diff --git a/src/com/quollwriter/ui/ShareWritingPrompt.java b/src/main/java/com/quollwriter/ui/ShareWritingPrompt.java similarity index 100% rename from src/com/quollwriter/ui/ShareWritingPrompt.java rename to src/main/java/com/quollwriter/ui/ShareWritingPrompt.java diff --git a/src/com/quollwriter/ui/SideBarsSupported.java b/src/main/java/com/quollwriter/ui/SideBarsSupported.java similarity index 100% rename from src/com/quollwriter/ui/SideBarsSupported.java rename to src/main/java/com/quollwriter/ui/SideBarsSupported.java diff --git a/src/com/quollwriter/ui/SpellCheckSupported.java b/src/main/java/com/quollwriter/ui/SpellCheckSupported.java similarity index 100% rename from src/com/quollwriter/ui/SpellCheckSupported.java rename to src/main/java/com/quollwriter/ui/SpellCheckSupported.java diff --git a/src/com/quollwriter/ui/SplashScreen.java b/src/main/java/com/quollwriter/ui/SplashScreen.java similarity index 83% rename from src/com/quollwriter/ui/SplashScreen.java rename to src/main/java/com/quollwriter/ui/SplashScreen.java index 3ee10fcf..52bf017c 100644 --- a/src/com/quollwriter/ui/SplashScreen.java +++ b/src/main/java/com/quollwriter/ui/SplashScreen.java @@ -6,11 +6,9 @@ import javax.swing.border.*; import com.quollwriter.*; -import com.quollwriter.events.*; import com.quollwriter.ui.components.*; - -public class SplashScreen extends JWindow implements PropertyChangedListener +public class SplashScreen extends JWindow { private JProgressBar progressBar = null; @@ -28,7 +26,7 @@ public SplashScreen(Image image, JLabel l = new JLabel (new ImageIcon (image)); l.setAlignmentX (Component.LEFT_ALIGNMENT); box.add (l); - + this.progressBar = new JProgressBar (); this.progressBar.setAlignmentX (Component.LEFT_ALIGNMENT); this.progressBar.setForeground (UIUtils.getColor ("#4d4d4f")); @@ -41,7 +39,7 @@ public SplashScreen(Image image, box.setOpaque (false); box.setBorder (UIUtils.createLineBorder ()); box.setBorder (new MatteBorder (1, 1, 1, 1, UIUtils.getColor ("#4d4d4f"))); - + JComponent cp = (JComponent) this.getContentPane (); cp.add (box);//ip); @@ -56,22 +54,20 @@ public SplashScreen(Image image, this.setVisible (true); this.toFront (); +/* + Environment.startupProgressProperty ().addListener ((p, oldv, newv) -> + { - Environment.addStartupProgressListener (this); - - } + this.setProgress (newv.intValue ()); - public void propertyChanged (PropertyChangedEvent ev) - { - - this.setProgress (((Number) ev.getNewValue ()).intValue ()); - + }); +*/ } - + public void finish () { - this.progressBar.setValue (100); + this.progressBar.setValue (100); try { @@ -113,14 +109,14 @@ public void setProgress (int v) { this.progressBar.setValue (v); - + if (v >= 100) { - + this.finish (); - + } - + } } diff --git a/src/com/quollwriter/ui/StarBar.java b/src/main/java/com/quollwriter/ui/StarBar.java similarity index 100% rename from src/com/quollwriter/ui/StarBar.java rename to src/main/java/com/quollwriter/ui/StarBar.java diff --git a/src/com/quollwriter/ui/Stateful.java b/src/main/java/com/quollwriter/ui/Stateful.java similarity index 100% rename from src/com/quollwriter/ui/Stateful.java rename to src/main/java/com/quollwriter/ui/Stateful.java diff --git a/src/com/quollwriter/ui/TaggedObjectAccordionItem.java b/src/main/java/com/quollwriter/ui/TaggedObjectAccordionItem.java similarity index 99% rename from src/com/quollwriter/ui/TaggedObjectAccordionItem.java rename to src/main/java/com/quollwriter/ui/TaggedObjectAccordionItem.java index 7fa792ba..2f4786fc 100644 --- a/src/com/quollwriter/ui/TaggedObjectAccordionItem.java +++ b/src/main/java/com/quollwriter/ui/TaggedObjectAccordionItem.java @@ -40,7 +40,7 @@ public TaggedObjectAccordionItem (Tag tag, this.tag = tag; - Environment.addUserProjectEventListener (this); + // TODO Environment.addUserProjectEventListener (this); this.sorter = NamedObjectSorter.getInstance (); diff --git a/src/com/quollwriter/ui/TagsEditor.java b/src/main/java/com/quollwriter/ui/TagsEditor.java similarity index 87% rename from src/com/quollwriter/ui/TagsEditor.java rename to src/main/java/com/quollwriter/ui/TagsEditor.java index 39f96528..33cb3581 100644 --- a/src/com/quollwriter/ui/TagsEditor.java +++ b/src/main/java/com/quollwriter/ui/TagsEditor.java @@ -22,10 +22,6 @@ import javax.swing.table.*; import javax.swing.tree.*; -import com.gentlyweb.utils.*; - -import com.gentlyweb.xml.*; - import com.quollwriter.*; import com.quollwriter.data.*; @@ -35,7 +31,9 @@ import com.quollwriter.ui.components.*; import com.quollwriter.ui.renderers.*; -import com.quollwriter.events.*; +import com.quollwriter.ui.fx.ProjectEvent; +import com.quollwriter.ui.fx.ProjectEventListener; +import com.quollwriter.events.MouseEventHandler; public class TagsEditor extends Box implements ProjectEventListener { @@ -43,31 +41,31 @@ public class TagsEditor extends Box implements ProjectEventListener private DefaultTableModel typeModel = null; private AbstractViewer viewer = null; private JLabel error = null; - + public TagsEditor (AbstractViewer pv) { super (BoxLayout.Y_AXIS); - + this.viewer = pv; Environment.addUserProjectEventListener (this); - + } @Override public void eventOccurred (ProjectEvent ev) { - - if (ev.getType ().equals (ProjectEvent.TAG)) + + if (ev.getType ().equals (ProjectEvent.Type.tag)) { this.reloadTypes (); - - } - + + } + } - + public void init () { @@ -105,7 +103,7 @@ public void init () 5)); this.add (tp); - + final JTextField newTypes = UIUtils.createTextField (); newTypes.setAlignmentX (Component.LEFT_ALIGNMENT); @@ -120,7 +118,7 @@ public void init () typeTable.setDefaultRenderer (Object.class, new DefaultTableCellRenderer () { - + @Override public Component getTableCellRendererComponent (JTable table, Object value, @@ -129,182 +127,182 @@ public Component getTableCellRendererComponent (JTable table, int row, int column) { - + super.getTableCellRendererComponent (table, value, isSelected, hasFocus, row, column); - + this.setText (((Tag) value).getName ()); - + this.setBorder (UIUtils.createPadding (0, 3, 0, 3)); - + return this; - + } - + }); - + typeTable.setDefaultEditor (Object.class, new DefaultCellEditor (new JTextField ()) { - + private Tag tag = null; - + @Override public int getClickCountToStart () { - + return 2; - + } - + @Override public Component getTableCellEditorComponent (JTable table, Object value, boolean isSelected, int row, - int column) + int column) { - + this.tag = (Tag) value; - + JTextField t = (JTextField) this.getComponent (); - + t.setText (this.tag.getName ().trim ()); - + t.setBorder (UIUtils.createPadding (0, 3, 0, 3)); - + return t; - + } - + @Override public boolean stopCellEditing () { - + java.util.List prefix = new ArrayList (); prefix.add (LanguageStrings.tags); prefix.add (LanguageStrings.actions); prefix.add (LanguageStrings.manage); prefix.add (LanguageStrings.table); prefix.add (LanguageStrings.edit); - + _this.error.setVisible (false); - + UIUtils.resizeParent (_this); - + String newName = ((JTextField) this.getComponent ()).getText ().trim (); - + if (newName.length () == 0) { - + return _this.showError (Environment.getUIString (prefix, LanguageStrings.errors, LanguageStrings.novalue)); //"Tag must have a value!"); - + } - + try { - + Tag ot = Environment.getTagByName (newName); - + // See if we have another tag with that name. if ((ot != null) && (ot != this.tag) ) { - + return _this.showError (Environment.getUIString (prefix, LanguageStrings.errors, LanguageStrings.novalue)); //String.format ("Already have a tag called %s.", // ot.getName ())); - + } - + } catch (Exception e) { - + Environment.logError ("Unable to get tag for name: " + newName, e); - + return _this.showError (Environment.getUIString (prefix, LanguageStrings.actionerror)); //"Unable to check tag."); - + } - this.tag.setName (newName); - + this.tag.setName (newName); + try { - + Environment.saveTag (this.tag); - + } catch (Exception e) { - + Environment.logError ("Unable to update tag: " + this.tag, e); - + return _this.showError (Environment.getUIString (prefix, LanguageStrings.actionerror)); //"Unable to update tag."); - + } - + _this.error.setVisible (false); - + UIUtils.resizeParent (_this.error); return super.stopCellEditing (); - + } - + @Override public void cancelCellEditing () { - + _this.error.setVisible (false); - + UIUtils.resizeParent (_this.error); - + super.cancelCellEditing (); - + } - + @Override public Object getCellEditorValue () { - + return this.tag; - + } - + }); typeTable.addMouseListener (new MouseEventHandler () { - + @Override public void fillPopup (final JPopupMenu m, final MouseEvent ev) { - + final int rowInd = typeTable.rowAtPoint (ev.getPoint ()); - + if (rowInd < 0) { - + return; - + } - + typeTable.setRowSelectionInterval (rowInd, rowInd); @@ -319,22 +317,22 @@ public void fillPopup (final JPopupMenu m, Constants.EDIT_ICON_NAME, new ActionListener () { - + @Override public void actionPerformed (ActionEvent ev) { - + typeTable.editCellAt (rowInd, 0); - + } - + })); - + } - + }); - + this.typeModel = (DefaultTableModel) typeTable.getModel (); this.reloadTypes (); @@ -342,7 +340,7 @@ public void actionPerformed (ActionEvent ev) Box fb = new Box (BoxLayout.Y_AXIS); fb.setAlignmentX (Component.LEFT_ALIGNMENT); fb.add (newTypes); - + fb.add (Box.createVerticalStrut (5)); fb.setBorder (UIUtils.createPadding (5, 5, @@ -357,7 +355,7 @@ public void actionPerformed (ActionEvent ev) //"Add"); JButton[] buts = new JButton[] { add }; - + final ActionAdapter aa = new ActionAdapter () { @@ -376,46 +374,46 @@ public void actionPerformed (ActionEvent ev) if (w.length () == 0) { - + continue; - + } - + try { - + if (Environment.getTagByName (w) != null) { - + continue; - + } } catch (Exception e) { - + Environment.logError ("Unable to get tag for name: " + w, e); - + continue; - + } - + DefaultTableModel m = (DefaultTableModel) typeTable.getModel (); Tag tag = new Tag (); tag.setName (w); - + try { - + Environment.saveTag (tag); - + } catch (Exception e) { Environment.logError ("Unable to add tag: " + tag, e); - + UIUtils.showErrorMessage (_this.viewer, Environment.getUIString (LanguageStrings.tags, LanguageStrings.actions, @@ -423,16 +421,16 @@ public void actionPerformed (ActionEvent ev) LanguageStrings.newtag, LanguageStrings.actionerror)); //"Unable to add tag."); - + return; - + } - + Vector r = new Vector (); r.add (tag); m.insertRow (0, r); - + } newTypes.setText (""); @@ -447,15 +445,15 @@ public void actionPerformed (ActionEvent ev) aa); fb.add (UIUtils.createButtonBar2 (buts, Component.LEFT_ALIGNMENT)); - + this.add (fb); - + java.util.List prefix = new ArrayList (); prefix.add (LanguageStrings.tags); prefix.add (LanguageStrings.actions); prefix.add (LanguageStrings.manage); prefix.add (LanguageStrings.table); - + this.add (UIUtils.createBoldSubHeader (Environment.getUIString (prefix, LanguageStrings.title), null)); @@ -465,15 +463,15 @@ public void actionPerformed (ActionEvent ev) fb.setBorder (UIUtils.createPadding (5, 5, 0, - 5)); - + 5)); + tp = UIUtils.createHelpTextPane (Environment.getUIString (prefix, LanguageStrings.text), this.viewer); tp.setBorder (null); fb.add (tp); fb.add (Box.createVerticalStrut (10)); - + final JScrollPane ppsp = UIUtils.createScrollPane (typeTable); typeTable.setPreferredScrollableViewportSize (new Dimension (-1, @@ -481,11 +479,11 @@ public void actionPerformed (ActionEvent ev) this.error = UIUtils.createErrorLabel ("");//Please enter a value."); this.error.setVisible (false); - + this.error.setBorder (UIUtils.createPadding (5, 0, 5, 5)); - + fb.add (this.error); - + fb.add (ppsp); final JButton remove = new JButton (Environment.getUIString (LanguageStrings.tags, @@ -496,7 +494,7 @@ public void actionPerformed (ActionEvent ev) //"Remove Selected"); buts = new JButton[] { remove }; - + remove.addActionListener (new ActionAdapter () { @@ -515,18 +513,18 @@ public void actionPerformed (ActionEvent ev) // Remove the row. m.removeRow (selection[i]); - + try { - + Environment.deleteTag (tag); - + } catch (Exception e) { Environment.logError ("Unable to delete tag: " + tag, e); - + UIUtils.showErrorMessage (_this.viewer, Environment.getUIString (LanguageStrings.tags, LanguageStrings.actions, @@ -535,11 +533,11 @@ public void actionPerformed (ActionEvent ev) LanguageStrings.delete, LanguageStrings.actionerror)); //"Unable to delete tag."); - + return; - + } - + } ((DefaultListSelectionModel) typeTable.getSelectionModel ()).clearSelection (); @@ -549,11 +547,11 @@ public void actionPerformed (ActionEvent ev) }); fb.add (Box.createVerticalStrut (5)); - + fb.add (UIUtils.createButtonBar2 (buts, Component.LEFT_ALIGNMENT)); this.add (fb); - + JButton finish = new JButton (Environment.getUIString (LanguageStrings.tags, LanguageStrings.actions, LanguageStrings.manage, @@ -567,7 +565,7 @@ public void actionPerformed (ActionEvent ev) { _this.error.setVisible (false); - + UIUtils.closePopupParent (_this.getParent ()); } @@ -577,45 +575,45 @@ public void actionPerformed (ActionEvent ev) buts = new JButton[] { finish }; JPanel bp = UIUtils.createButtonBar2 (buts, - Component.CENTER_ALIGNMENT); + Component.CENTER_ALIGNMENT); bp.setOpaque (false); this.add (Box.createVerticalStrut (10)); - - this.add (bp); - + + this.add (bp); + //return b; } - + private boolean showError (String m) { - + this.error.setText (m); - + this.error.setVisible (true); - + UIUtils.resizeParent (this.error); return false; - + } - + public void reloadTypes () { Set tags = null; - + try { - + tags = Environment.getAllTags (); - + } catch (Exception e) { - + Environment.logError ("Unable to get all tags", e); - + UIUtils.showErrorMessage (this.viewer, Environment.getUIString (LanguageStrings.tags, LanguageStrings.actions, @@ -623,25 +621,25 @@ public void reloadTypes () LanguageStrings.table, LanguageStrings.loadallerror)); // "Unable to get the tags."); - + return; - + } Vector tagsData = new Vector (); TreeSet nt = new TreeSet (NamedObjectSorter.getInstance ()); - + nt.addAll (tags); - + for (Tag t : nt) { - + Vector d = new Vector (); d.add (t); - + tagsData.add (d); - + } Vector cols = new Vector (); @@ -649,7 +647,7 @@ public void reloadTypes () this.typeModel.setDataVector (tagsData, cols); - + } public String getHeaderIconType () @@ -658,5 +656,5 @@ public String getHeaderIconType () return Constants.TAG_ICON_NAME; } - + } diff --git a/src/com/quollwriter/ui/Targets.java b/src/main/java/com/quollwriter/ui/Targets.java similarity index 99% rename from src/com/quollwriter/ui/Targets.java rename to src/main/java/com/quollwriter/ui/Targets.java index aaa97251..91eff0f4 100644 --- a/src/com/quollwriter/ui/Targets.java +++ b/src/main/java/com/quollwriter/ui/Targets.java @@ -699,9 +699,9 @@ public void actionPerformed (ActionEvent ev) ChapterCounts count = viewer.getChapterCounts (c); - int diff = count.wordCount - tcc; + int diff = count.getWordCount () - tcc; - int perc = Environment.getPercent (diff, tcc); + int perc = Utils.getPercent (diff, tcc); JLabel diffl = null; @@ -709,7 +709,7 @@ public void actionPerformed (ActionEvent ev) { diffl = UIUtils.createErrorLabel (String.format ("+%s", - Environment.formatNumber (count.wordCount - tcc))); + Environment.formatNumber (count.getWordCount () - tcc))); diffl.setIcon (null); @@ -718,7 +718,7 @@ public void actionPerformed (ActionEvent ev) } else { diffl = UIUtils.createLabel (String.format ("+%s", - Environment.formatNumber (count.wordCount - tcc))); + Environment.formatNumber (count.getWordCount () - tcc))); } @@ -726,7 +726,7 @@ public void actionPerformed (ActionEvent ev) cc.xy (5, r)); b.addLabel (String.format ("%s", - Environment.formatNumber (count.wordCount)), + Environment.formatNumber (count.getWordCount ())), cc.xy (3, r)); b.add (l, diff --git a/src/com/quollwriter/ui/TextArea.java b/src/main/java/com/quollwriter/ui/TextArea.java similarity index 96% rename from src/com/quollwriter/ui/TextArea.java rename to src/main/java/com/quollwriter/ui/TextArea.java index 8eb02f1e..437deda3 100644 --- a/src/com/quollwriter/ui/TextArea.java +++ b/src/main/java/com/quollwriter/ui/TextArea.java @@ -11,16 +11,16 @@ import javax.swing.event.*; import com.quollwriter.*; -import com.quollwriter.events.*; import com.quollwriter.ui.actionHandlers.*; import com.quollwriter.ui.components.QTextEditor; -import com.quollwriter.ui.components.Markup; import com.quollwriter.ui.components.ActionAdapter; import com.quollwriter.DictionaryProvider; import com.quollwriter.synonyms.*; import com.quollwriter.text.*; +import com.quollwriter.events.MouseEventHandler; +import com.quollwriter.ui.fx.ProjectEvent; import com.quollwriter.ui.components.ScrollableBox; public class TextArea extends ScrollableBox @@ -64,8 +64,43 @@ public TextArea (String placeholder, super (BoxLayout.Y_AXIS); + final TextArea _this = this; + this.text = new QTextEditor (null, - false); + false) + { + + @Override + public void cut () + { + + super.cut (); + + _this.onCut (); + + } + + @Override + public void paste () + { + + super.paste (); + + _this.onPaste (); + + } + + @Override + public void copy () + { + + super.copy (); + + _this.onCopy (); + + } + + }; this.text.setCanFormat (false); @@ -107,8 +142,6 @@ public TextArea (String placeholder, this.text.setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, null); this.text.setFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, null); - final TextArea _this = this; - this.addCaretListener (new CaretListener () { @@ -405,8 +438,9 @@ public void actionPerformed (ActionEvent ev) _this.text.addWordToDictionary (ev.getActionCommand ()); - Environment.fireUserProjectEvent (ProjectEvent.PERSONAL_DICTIONARY, - ProjectEvent.ADD_WORD, + Environment.fireUserProjectEvent (_this, + ProjectEvent.Type.personaldictionary, + ProjectEvent.Action.addword, ev.getActionCommand ()); } @@ -495,8 +529,9 @@ public void actionPerformed (ActionEvent ev) loc + word.length (), repWord); - Environment.fireUserProjectEvent (ProjectEvent.SPELL_CHECK, - ProjectEvent.REPLACE, + Environment.fireUserProjectEvent (_this, + ProjectEvent.Type.spellcheck, + ProjectEvent.Action.replace, ev.getActionCommand ()); } @@ -1291,6 +1326,32 @@ public void removeMouseListener (MouseListener l) } + /** + * Pass through to the underlying QTextEditor. + * + * @param l The listener. + */ + @Override + public void addMouseMotionListener (MouseMotionListener l) + { + + this.text.addMouseMotionListener (l); + + } + + /** + * Pass through to the underlying QTextEditor. + * + * @param l The listener. + */ + @Override + public void removeMouseMotionListener (MouseMotionListener l) + { + + this.text.removeMouseMotionListener (l); + + } + public void removeCaretListener (CaretListener l) { @@ -1340,4 +1401,19 @@ public void setBorder (Border b) } + public void onCut () + { + + } + + public void onCopy () + { + + } + + public void onPaste () + { + + } + } diff --git a/src/com/quollwriter/ui/TextInputWindow.java b/src/main/java/com/quollwriter/ui/TextInputWindow.java similarity index 99% rename from src/com/quollwriter/ui/TextInputWindow.java rename to src/main/java/com/quollwriter/ui/TextInputWindow.java index 53b4350d..9df6c0db 100644 --- a/src/com/quollwriter/ui/TextInputWindow.java +++ b/src/main/java/com/quollwriter/ui/TextInputWindow.java @@ -7,8 +7,6 @@ import javax.swing.border.*; import javax.swing.event.*; -import com.gentlyweb.utils.*; - import com.jgoodies.forms.factories.*; import com.quollwriter.*; diff --git a/src/com/quollwriter/ui/TextPropertiesEditPanel.java b/src/main/java/com/quollwriter/ui/TextPropertiesEditPanel.java similarity index 99% rename from src/com/quollwriter/ui/TextPropertiesEditPanel.java rename to src/main/java/com/quollwriter/ui/TextPropertiesEditPanel.java index 25bb0524..061217e6 100644 --- a/src/com/quollwriter/ui/TextPropertiesEditPanel.java +++ b/src/main/java/com/quollwriter/ui/TextPropertiesEditPanel.java @@ -120,7 +120,7 @@ public void propertyChanged (UserPropertyEvent ev) } - if (ev.getName ().equals (Constants.FULL_SCREEN_EDITOR_FONT_BGCOLOR_PROPERTY_NAME)) + if (ev.getName ().equals (Constants.FULL_SCREEN_EDITOR_BGCOLOR_PROPERTY_NAME)) { this.bgcolorSwatch.setBackground (this.textProps.getBackgroundColor ()); diff --git a/src/main/java/com/quollwriter/ui/Tips.java b/src/main/java/com/quollwriter/ui/Tips.java new file mode 100644 index 00000000..37f9f42f --- /dev/null +++ b/src/main/java/com/quollwriter/ui/Tips.java @@ -0,0 +1,329 @@ +package com.quollwriter.ui; + +import java.util.*; + +import org.dom4j.*; + +import com.quollwriter.*; +import com.quollwriter.ui.panels.*; +import com.quollwriter.data.*; + +public class Tips +{ + + public class XMLConstants + { + + public static final String tip = "tip"; + public static final String id = "id"; + + } + + private List baseTips = new ArrayList (); + private List tips = new ArrayList (); + private Random ind = new Random (); + private int lastInd = 0; + private AbstractViewer viewer = null; + + public Tips (AbstractViewer viewer) + throws Exception + { + + this.viewer = viewer; + + String tipsXML = Utils.getResourceFileAsString (Constants.TIPS_FILE); + + Element root = DOM4JUtils.stringAsElement (tipsXML); + + List tipEls = root.elements (XMLConstants.tip); + + for (int i = 0; i < tipEls.size (); i++) + { + + Element el = (Element) tipEls.get (i); + + this.baseTips.add (new Tip (el)); + + } + + this.tips = new ArrayList (this.baseTips); + + } + + public String getNextTip () + { + + if (this.tips.size () == 0) + { + + this.tips = new ArrayList (this.baseTips); + + } + + int n = this.ind.nextInt (this.tips.size ()); + + if ((n == this.lastInd) + && + (this.tips.size () > 1) + ) + { + + return this.getNextTip (); + + } + + this.lastInd = n; + + Tip t = this.tips.remove (n); + + // See if there is a condition. + String text = t.getText (this.viewer); + + if (text == null) + { + + return this.getNextTip (); + + } + + return text; + + } + + private class Tip + { + + public class XMLConstants + { + + public static final String id = "id"; + public static final String item = "item"; + + } + + private List items = new ArrayList (); + + public Tip (Element root) + throws GeneralException + { + + String id = DOM4JUtils.attributeValue (root, + XMLConstants.id); + + for (Element el : root.elements (XMLConstants.item)) + { + + this.items.add (new Item (id, + el)); + + } + + } + + public String getText (AbstractViewer viewer) + { + + for (Item it : this.items) + { + + if (it.shouldShow (viewer)) + { + + return it.getText (); + + } + + } + + return null; + + } + + private class Item + { + + public class XMLConstants + { + + public static final String id = "id"; + public static final String condition = "condition"; + + } + + private List conds = new ArrayList (); + private String text = null; + + public Item (String tipId, + Element root) + throws GeneralException + { + + String id = tipId; + + String iid = DOM4JUtils.attributeValue (root, + XMLConstants.id, + false); + + if (!iid.equals ("")) + { + + id = tipId + "_" + iid; + + } + + String cs = DOM4JUtils.attributeValue (root, + XMLConstants.condition, + false); + + if (!cs.equals ("")) + { + + StringTokenizer t = new StringTokenizer (cs, + ",;"); + + while (t.hasMoreTokens ()) + { + + this.conds.add (t.nextToken ().trim ().toLowerCase ()); + + } + + } + + this.text = Environment.getUIString (LanguageStrings.tips, + id); + + if (this.text == null) + { + + throw new GeneralException ("Unable to find language string for tip/item: " + + id); + + } + //JDOMUtils.getChildContent (root); + + } + + public String getText () + { + + return this.text; + + } + + public boolean shouldShow (AbstractViewer viewer) + { + + for (String c : this.conds) + { + + boolean not = c.startsWith ("!"); + + if (not) + { + + c = c.substring (1); + + } + + boolean v = false; + + if (c.equals ("landingviewer")) + { + + v = (viewer instanceof Landing); + + } + + if (c.equals ("projectviewer")) + { + + v = (viewer instanceof ProjectViewer); + + } + + if (c.equals ("warmupsviewer")) + { + + v = (viewer instanceof WarmupsViewer); + + } + + if (viewer instanceof AbstractProjectViewer) + { + + AbstractProjectViewer pv = (AbstractProjectViewer) viewer; + + QuollPanel qp = pv.getCurrentlyVisibleTab (); + + if (qp != null) + { + + if ((c.equals ("chaptertab")) + && + (qp instanceof ProjectObjectQuollPanel) + ) + { + + v = (((ProjectObjectQuollPanel) qp).getForObject () instanceof Chapter); + + } + + if (c.equals ("ideaboard")) + { + + v = qp.getPanelId ().equals (IdeaBoard.PANEL_ID); + + } + + } + + if (c.equals ("spellcheckon")) + { + + v = pv.isSpellCheckingEnabled (); + + } + + if (c.equals ("spellcheckoff")) + { + + v = !pv.isSpellCheckingEnabled (); + + } + + } + + if (v) + { + + if (not) + { + + return false; + + } + + } else { + + if (!not) + { + + return false; + + } + + + } + + } + + return true; + + } + + } + + } + +} diff --git a/src/main/java/com/quollwriter/ui/TreeParentNode.java b/src/main/java/com/quollwriter/ui/TreeParentNode.java new file mode 100644 index 00000000..af7e9d4e --- /dev/null +++ b/src/main/java/com/quollwriter/ui/TreeParentNode.java @@ -0,0 +1,125 @@ +package com.quollwriter.ui; + +import java.util.*; + +import org.dom4j.*; +import com.quollwriter.data.*; + +public class TreeParentNode extends NamedObject +{ + + public static final String OBJECT_TYPE = "treeparentnode"; + + private String forObjectType = null; + private int count = -1; + + public TreeParentNode (String objType, + String name) + { + + this (objType, + name, + -1); + + } + + public TreeParentNode(String objType, + String name, + int count) + { + + super (TreeParentNode.OBJECT_TYPE + "_" + objType); + + this.forObjectType = objType; + + this.setKey ((long) name.toLowerCase ().hashCode ()); + + this.setName (name); + + this.count = count; + + } + + public void setCount (int c) + { + + this.count = c; + + } + + public int getCount () + { + + return this.count; + + } + + @Override + public void getChanges (NamedObject old, + Element root) + { + + } + + @Override + public int hashCode () + { + + int hash = 7; + hash = (31 * hash) + this.forObjectType.hashCode (); + hash = (31 * hash) + this.getName ().toLowerCase ().hashCode (); + + return hash; + + } + + public String getForObjectType () + { + + return this.forObjectType; + + } + + @Override + public boolean equals (Object o) + { + + if ((o == null) || (!(o instanceof TreeParentNode))) + { + + + return false; + + } + + TreeParentNode n = (TreeParentNode) o; + + if ((n.getName ().equalsIgnoreCase (this.getName ())) && + (n.forObjectType.equals (this.forObjectType))) + { + + return true; + + } + + return false; + + } + + @Override + public String toString () + { + + return TreeParentNode.OBJECT_TYPE + "(for: " + this.forObjectType + ", type: " + this.getName () + ")"; + + } + + @Override + public Set getAllNamedChildObjects () + { + + return new HashSet (); + + } + +} diff --git a/src/com/quollwriter/ui/TypesEditor.java b/src/main/java/com/quollwriter/ui/TypesEditor.java similarity index 99% rename from src/com/quollwriter/ui/TypesEditor.java rename to src/main/java/com/quollwriter/ui/TypesEditor.java index c3e11cc8..816673e0 100644 --- a/src/com/quollwriter/ui/TypesEditor.java +++ b/src/main/java/com/quollwriter/ui/TypesEditor.java @@ -23,10 +23,6 @@ import javax.swing.table.*; import javax.swing.tree.*; -import com.gentlyweb.utils.*; - -import com.gentlyweb.xml.*; - import com.jgoodies.forms.builder.*; import com.jgoodies.forms.factories.*; import com.jgoodies.forms.layout.*; diff --git a/src/com/quollwriter/ui/TypesHandler.java b/src/main/java/com/quollwriter/ui/TypesHandler.java similarity index 100% rename from src/com/quollwriter/ui/TypesHandler.java rename to src/main/java/com/quollwriter/ui/TypesHandler.java diff --git a/src/main/java/com/quollwriter/ui/UIUtils.java b/src/main/java/com/quollwriter/ui/UIUtils.java new file mode 100644 index 00000000..601d992d --- /dev/null +++ b/src/main/java/com/quollwriter/ui/UIUtils.java @@ -0,0 +1,11598 @@ +package com.quollwriter.ui; + +import java.awt.Color; +import java.awt.Component; +import java.awt.Container; +import java.awt.Cursor; +import java.awt.Desktop; +import java.awt.Dialog; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.Frame; +import java.awt.GraphicsEnvironment; +import java.awt.Insets; +import java.awt.KeyboardFocusManager; +import java.awt.Toolkit; +import java.awt.Window; +import java.awt.Graphics2D; +import java.awt.RenderingHints; +import java.awt.Graphics; +import java.awt.Point; +import java.awt.Image; +import java.awt.image.BufferedImage; +import java.awt.Rectangle; +import java.awt.GraphicsDevice; +import java.awt.GraphicsConfiguration; +import java.awt.FontMetrics; +import java.awt.datatransfer.*; +import java.awt.event.*; +import java.awt.font.*; +import java.awt.image.*; +import java.beans.*; +import javax.swing.plaf.basic.*; + +import java.util.concurrent.atomic.*; + +import java.net.*; + +import java.io.*; +import java.nio.file.*; + +import java.text.*; + +import java.util.*; +import java.util.regex.*; + +import javax.swing.*; +import javax.swing.border.*; +import javax.swing.event.*; +import javax.swing.text.*; +import javax.swing.text.html.*; +import javax.swing.tree.*; +import javax.swing.table.*; +import javax.swing.filechooser.*; + +import javax.imageio.*; + +//import javafx.scene.*; +import javafx.scene.web.*; +import javafx.scene.layout.BorderPane; +import javafx.application.*; +import javafx.embed.swing.*; + +import org.imgscalr.Scalr; + +import com.jgoodies.forms.builder.*; +import com.jgoodies.forms.factories.*; +import com.jgoodies.forms.layout.*; + +import org.josql.*; + +import com.quollwriter.*; + +import com.quollwriter.data.*; +import com.quollwriter.data.comparators.*; + +import com.quollwriter.events.*; + +import com.quollwriter.ui.actionHandlers.*; +import com.quollwriter.ui.components.*; +import com.quollwriter.ui.renderers.*; +import com.quollwriter.ui.fx.ProjectEvent; +import com.quollwriter.ui.fx.ProjectEventListener; +import com.quollwriter.ui.panels.*; +import com.quollwriter.ui.sidebars.*; +import com.quollwriter.ui.userobjects.*; +import com.quollwriter.editors.messages.*; +import com.quollwriter.editors.*; +import com.quollwriter.synonyms.*; +import com.quollwriter.db.*; +import com.quollwriter.ui.forms.Form; +import com.quollwriter.ui.forms.FormItem; +import com.quollwriter.uistrings.*; + +import com.quollwriter.text.*; + +import org.jfree.chart.*; +import org.jfree.chart.axis.*; +import org.jfree.chart.labels.*; +import org.jfree.chart.plot.*; +import org.jfree.chart.renderer.xy.*; + +import org.jfree.data.time.*; + +import org.jfree.chart.ui.*; + +import org.josql.utils.*; + +import static com.quollwriter.LanguageStrings.*; +import static com.quollwriter.uistrings.UILanguageStringsManager.getUIString; + +public class UIUtils +{ + + private static int DEFAULT_ASSUMED_SCREEN_RESOLUTION = 96; + private static int DEFAULT_POPUP_WIDTH = 450; + public static int DEFAULT_SCROLL_BY_AMOUNT = 20; + + public static final Point defaultLeftCornerShowPopupAt = new Point (10, 10); + + private static final QTextEditor wordCountPerPageEditor = new QTextEditor (null, + false); + + // Deliberately null so that the center of the window is found when the popup is shown. + public static final Point defaultCenterShowPopupAt = null; + + public static Font headerFont = null; + + public static final Border textFieldSpacing = new EmptyBorder (3, + 3, + 3, + 3); + + public static final FileNameExtensionFilter imageFileFilter = new FileNameExtensionFilter ("Image files: jpg, png, gif", + "jpg", + "jpeg", + "gif", + "png"); + + public static Color getIconColumnColor () + { + + return getColor ("#f0f0f0");//"f5fcfe"); + + } + + public static int getScrollByAmount () + { + + return DEFAULT_SCROLL_BY_AMOUNT; + + } + + public static int getScreenScaledWidth (int w) + { + + return Math.round ((float) w * ((float) java.awt.Toolkit.getDefaultToolkit ().getScreenResolution () / (float) DEFAULT_ASSUMED_SCREEN_RESOLUTION)); + + } + + public static int getPopupWidth () + { + + return UIUtils.getScreenScaledWidth (DEFAULT_POPUP_WIDTH); + + } + + public static Object getUserObjectForTreePath (TreePath p) + { + + if (p == null) + { + + return null; + + } + + Object[] objs = p.getPath (); + + DefaultMutableTreeNode n = (DefaultMutableTreeNode) objs[objs.length -1]; + + return n.getUserObject (); + + } + + public static TreePath getTreePathForUserObjects (DefaultMutableTreeNode node, + TreePath p) + { + + Object[] objs = p.getPath (); + + for (int i = 0; i < objs.length; i++) + { + + DefaultMutableTreeNode n = (DefaultMutableTreeNode) objs[i]; + + Object nObj = n.getUserObject (); + + TreePath tp = UIUtils.getTreePathForUserObject (node, + nObj); + + if (tp == null) + { + + continue; + + } else { + + if (i == objs.length - 1) + { + + return tp; + + } + + } + + node = (DefaultMutableTreeNode) tp.getPath ()[tp.getPath ().length - 1]; + + } + + return null; + + } + + public static TreePath getTreePathForUserObject (DefaultMutableTreeNode node, + Object o) + { + + Object nObj = node.getUserObject (); + + if (nObj instanceof SelectableDataObject) + { + + nObj = ((SelectableDataObject) nObj).obj; + + } + + if (nObj instanceof DataObject) + { + + if (nObj.equals (o)) + { + + return new TreePath (node.getPath ()); + + } + + } + + if ((nObj instanceof Segment) + && + (o instanceof Segment) + ) + { + + if (nObj.toString ().equals (o.toString ())) + { + + return new TreePath (node.getPath ()); + + } + + } + + if (nObj.equals (o)) + { + + return new TreePath (node.getPath ()); + + } + + if (nObj == o) + { + + return new TreePath (node.getPath ()); + + } + + Enumeration en = node.children (); + + while (en.hasMoreElements ()) + { + + node = (DefaultMutableTreeNode) en.nextElement (); + + TreePath tp = UIUtils.getTreePathForUserObject (node, + o); + + if (tp != null) + { + + return tp; + + } + + } + + return null; + + } + + public static void createTree (Collection items, + DefaultMutableTreeNode parent) + { + + Iterator iter = items.iterator (); + + while (iter.hasNext ()) + { + + Object v = iter.next (); + + if (v instanceof Map) + { + + UIUtils.createTree ((Map) v, + parent); + + continue; + + } + + if (v instanceof Collection) + { + + UIUtils.createTree ((Collection) v, + parent); + + continue; + + } + + DefaultMutableTreeNode n = new DefaultMutableTreeNode (v); + + parent.add (n); + + } + + } + + public static void createTree (Map items, + DefaultMutableTreeNode parent) + { + + Iterator iter = items.entrySet ().iterator (); + + while (iter.hasNext ()) + { + + Map.Entry item = (Map.Entry) iter.next (); + + Object k = item.getKey (); + + Object v = item.getValue (); + + // Add a node for the key. + DefaultMutableTreeNode key = new DefaultMutableTreeNode (k); + + parent.add (key); + + if (v instanceof Map) + { + + UIUtils.createTree ((Map) v, + key); + + } + + if (v instanceof Collection) + { + + UIUtils.createTree ((Collection) v, + key); + + } + + } + + } + + public static DefaultMutableTreeNode createAssetTree (UserConfigurableObjectType objType, + Project p) + { + + return UIUtils.createAssetTree (objType, + p, + new Comparator () + { + + @Override + public boolean equals (Object o) + { + + return this == o; + + } + + @Override + public int compare (Asset o1, + Asset o2) + { + + return NamedObjectSorter.getInstance ().compare (o1, o2); + + } + + }); + + } + + public static DefaultMutableTreeNode createAssetTree (UserConfigurableObjectType objType, + Project p, + Comparator sorter) + { + + List objs = new ArrayList (); + + Set assets = p.getAssets (objType); + + if (assets != null) + { + + objs.addAll (assets); + + } + + DefaultMutableTreeNode root = new DefaultMutableTreeNode (p); + + Collections.sort (objs, + sorter); + + for (NamedObject obj : objs) + { + + root.add (new DefaultMutableTreeNode (obj)); + + } + + return root; + + } +/* + public static DefaultMutableTreeNode createLocationsTree (Project p) + { + + DefaultMutableTreeNode root = new DefaultMutableTreeNode (p); + + Collections.sort (p.getLocations (), + new NamedObjectSorter ()); + + for (Location ll : p.getLocations ()) + { + + root.add (new DefaultMutableTreeNode (ll)); + + } + + return root; + + } + */ +/* + public static DefaultMutableTreeNode createAssetsTree (Project p) + { + + DefaultMutableTreeNode root = new DefaultMutableTreeNode (p); + + TreeParentNode c = new TreeParentNode (QCharacter.OBJECT_TYPE, + Environment.getObjectTypeNamePlural (QCharacter.OBJECT_TYPE)); + + DefaultMutableTreeNode tn = new DefaultMutableTreeNode (c); + + root.add (tn); + + Collections.sort (p.getCharacters (), + new NamedObjectSorter ()); + + for (int i = 0; i < p.getCharacters ().size (); i++) + { + + tn.add (new DefaultMutableTreeNode (p.getCharacters ().get (i))); + + } + + TreeParentNode l = new TreeParentNode (Location.OBJECT_TYPE, + Environment.getObjectTypeNamePlural (Location.OBJECT_TYPE)); + + tn = new DefaultMutableTreeNode (l); + + Collections.sort (p.getLocations (), + new NamedObjectSorter ()); + + for (Location ll : p.getLocations ()) + { + + tn.add (new DefaultMutableTreeNode (ll)); + + } + + root.add (tn); + + TreeParentNode o = new TreeParentNode (QObject.OBJECT_TYPE, + Environment.getObjectTypeNamePlural (QObject.OBJECT_TYPE)); + + tn = new DefaultMutableTreeNode (o); + + Collections.sort (p.getQObjects (), + new NamedObjectSorter ()); + + for (QObject oo : p.getQObjects ()) + { + + tn.add (new DefaultMutableTreeNode (oo)); + + } + + root.add (tn); + + TreeParentNode r = new TreeParentNode (ResearchItem.OBJECT_TYPE, + Environment.getObjectTypeNamePlural (ResearchItem.OBJECT_TYPE)); + + tn = new DefaultMutableTreeNode (r); + + Collections.sort (p.getResearchItems (), + NamedObjectSorter.getInstance ()); + + for (ResearchItem rr : p.getResearchItems ()) + { + + tn.add (new DefaultMutableTreeNode (rr)); + + } + + root.add (tn); + + return root; + + } +*/ + public static void getSelectedObjects (DefaultMutableTreeNode n, + NamedObject addTo, + Set s) + throws GeneralException + { + + Enumeration en = n.children (); + + while (en.hasMoreElements ()) + { + + DefaultMutableTreeNode nn = (DefaultMutableTreeNode) en.nextElement (); + + SelectableDataObject sd = (SelectableDataObject) nn.getUserObject (); + + if (sd.selected) + { + + s.add (new Link (addTo, + sd.obj)); + + } + + UIUtils.getSelectedObjects (nn, + addTo, + s); + + } + + } + + public static void initTable (JTable t) + { + + t.setAlignmentX (Component.LEFT_ALIGNMENT); + t.setOpaque (false); + t.setFillsViewportHeight (true); + t.setShowVerticalLines (false); + t.setRowHeight (24); + t.setBorder (null); + + t.setDefaultRenderer (Object.class, + new DefaultTableCellRenderer () + { + + @Override + public Component getTableCellRendererComponent (JTable t, + Object value, + boolean isSelected, + boolean hasFocus, + int row, + int column) + { + + super.getTableCellRendererComponent (t, + value, + isSelected, + hasFocus, + row, + column); + + this.setBorder (UIUtils.createPadding (0, 3, 0, 3)); + + return this; + + } + + }); + + } + + public static JTable createTable () + { + + JTable t = new JTable (); + + UIUtils.initTable (t); + + return t; + + } + + public static JTree createSelectableTree () + { + + final JTree tree = UIUtils.createTree (); + + tree.setCellRenderer (new SelectableProjectTreeCellRenderer ()); + + tree.setOpaque (false); + tree.setBorder (null); + tree.setBorder (UIUtils.createPadding (5, 5, 5, 5)); + + tree.setRootVisible (false); + tree.setShowsRootHandles (true); + tree.setScrollsOnExpand (true); + + tree.addMouseListener (new MouseEventHandler () + { + + private void selectAllChildren (DefaultTreeModel model, + DefaultMutableTreeNode n, + boolean v) + { + + Enumeration en = n.children (); + + while (en.hasMoreElements ()) + { + + DefaultMutableTreeNode c = (DefaultMutableTreeNode) en.nextElement (); + + SelectableDataObject s = (SelectableDataObject) c.getUserObject (); + + s.selected = v; + + // Tell the model that something has changed. + model.nodeChanged (c); + + // Iterate. + this.selectAllChildren (model, + c, + v); + + } + + } + + @Override + public void handlePress (MouseEvent ev) + { + + TreePath tp = tree.getPathForLocation (ev.getX (), + ev.getY ()); + + if (tp != null) + { + + DefaultMutableTreeNode n = (DefaultMutableTreeNode) tp.getLastPathComponent (); + + // Tell the model that something has changed. + DefaultTreeModel model = (DefaultTreeModel) tree.getModel (); + + SelectableDataObject s = (SelectableDataObject) n.getUserObject (); + + s.selected = !s.selected; + + model.nodeChanged (n); + + this.selectAllChildren (model, + n, + s.selected); + + } + + } + + }); + + tree.putClientProperty (com.jgoodies.looks.Options.TREE_LINE_STYLE_KEY, + com.jgoodies.looks.Options.TREE_LINE_STYLE_NONE_VALUE); + + tree.putClientProperty ("Tree.paintLines", + Boolean.FALSE); + + return tree; + + } + + public static JTree createLinkedToTree (final AbstractProjectViewer projectViewer, + final NamedObject dataObject, + boolean editMode) + { + + final JTree tree = UIUtils.createTree (); + + if (editMode) + { + + tree.setCellRenderer (new SelectableProjectTreeCellRenderer ()); + + } else + { + + tree.setCellRenderer (new ProjectTreeCellRenderer (true)); + + } + + tree.setOpaque (true); + tree.setBorder (null); + + tree.setRootVisible (false); + tree.setShowsRootHandles (true); + tree.setScrollsOnExpand (true); + + if (editMode) + { + + // Never toggle. + // tree.setToggleClickCount (-1); + + tree.addMouseListener (new MouseEventHandler () + { + + private void selectAllChildren (DefaultTreeModel model, + DefaultMutableTreeNode n, + boolean v) + { + + Enumeration en = n.children (); + + while (en.hasMoreElements ()) + { + + DefaultMutableTreeNode c = (DefaultMutableTreeNode) en.nextElement (); + + SelectableDataObject s = (SelectableDataObject) c.getUserObject (); + + s.selected = v; + + // Tell the model that something has changed. + model.nodeChanged (c); + + // Iterate. + this.selectAllChildren (model, + c, + v); + + } + + } + + @Override + public void handlePress (MouseEvent ev) + { + + TreePath tp = tree.getPathForLocation (ev.getX (), + ev.getY ()); + + if (tp != null) + { + + DefaultMutableTreeNode n = (DefaultMutableTreeNode) tp.getLastPathComponent (); + + // Tell the model that something has changed. + DefaultTreeModel model = (DefaultTreeModel) tree.getModel (); + + SelectableDataObject s = (SelectableDataObject) n.getUserObject (); + + /* + if ((ev.getClickCount () == 2) + && + (n.getChildCount () > 0) + ) + { + + this.selectAllChildren (model, + n, + s.selected); + + } else { + + s.selected = !s.selected; + + } + */ + s.selected = !s.selected; + + model.nodeChanged (n); + + } + + } + + }); + + } else + { + + tree.addMouseListener (new MouseEventHandler () + { + + @Override + public void handleDoublePress (MouseEvent ev) + { + + TreePath tp = tree.getPathForLocation (ev.getX (), + ev.getY ()); + + if (tp != null) + { + + DefaultMutableTreeNode n = (DefaultMutableTreeNode) tp.getLastPathComponent (); + + if ((n.getChildCount () == 0) && + (ev.getClickCount () == 2)) + { + + projectViewer.viewObject ((DataObject) n.getUserObject ()); + + } + + } + + } + + }); + + } + + tree.putClientProperty (com.jgoodies.looks.Options.TREE_LINE_STYLE_KEY, + com.jgoodies.looks.Options.TREE_LINE_STYLE_NONE_VALUE); + + tree.putClientProperty ("Tree.paintLines", + Boolean.FALSE); + + tree.setModel (UIUtils.getLinkedToTreeModel (projectViewer, + dataObject, + editMode)); + + UIUtils.expandPathsForLinkedOtherObjects (tree, + dataObject); + + return tree; + + } + + public static void expandPathsForLinkedOtherObjects (JTree tree, + NamedObject d) + { + + DefaultMutableTreeNode root = (DefaultMutableTreeNode) ((DefaultTreeModel) tree.getModel ()).getRoot (); + + for (Link l : d.getLinks ()) + { + + // Get the path for the object. + TreePath tp = UIUtils.getTreePathForUserObject (root, + l.getOtherObject (d)); + + if (tp != null) + { + + tree.expandPath (tp.getParentPath ()); + + } + + } + + } + + public static DefaultTreeModel getLinkedToTreeModel (AbstractProjectViewer projectViewer, + NamedObject dataObject, + boolean editMode) + { + + List exclude = new ArrayList (); + exclude.add (dataObject); + + // Painful but just about the only way. + projectViewer.setLinks (dataObject); + + // Get all the "other objects" for the links the note has. + Iterator it = dataObject.getLinks ().iterator (); + + Set links = new HashSet (); + + while (it.hasNext ()) + { + + links.add (it.next ().getOtherObject (dataObject)); + + } + + return new DefaultTreeModel (UIUtils.createLinkToTree (projectViewer.getProject (), + exclude, + links, + editMode)); + + } + + public static Box createLinkedToItemsBox (final NamedObject obj, + final AbstractProjectViewer pv, + final QPopup p, + boolean addTitle) + { + + Box pa = new Box (BoxLayout.Y_AXIS); + pa.setOpaque (false); + + if (addTitle) + { + + JLabel h = UIUtils.createLabel (getUIString (linkedto,view,title)); + //"Linked to"); + pa.add (h); + pa.add (Box.createVerticalStrut (3)); + + } + + Set sl = obj.getOtherObjectsInLinks (); + + Iterator liter = sl.iterator (); + + while (liter.hasNext ()) + { + + final NamedObject other = liter.next (); + + JLabel l = new JLabel (other.getName ()); + l.setOpaque (false); + l.setIcon (Environment.getIcon (other.getObjectType (), + Constants.ICON_MENU)); + l.setToolTipText (getUIString (viewitem,tooltip)); + //"Click to view the item"); + l.setCursor (Cursor.getPredefinedCursor (Cursor.HAND_CURSOR)); + l.setForeground (Color.BLUE); + l.setBorder (new EmptyBorder (0, + 5, + 0, + 0)); + + l.setAlignmentX (Component.LEFT_ALIGNMENT); + + pa.add (l); + pa.add (Box.createVerticalStrut (3)); + + l.addMouseListener (new MouseEventHandler () + { + + @Override + public void handlePress (MouseEvent ev) + { + + // Prevents the popup from disappearing. + pv.viewObject (other); + + if (p != null) + { + + // Close the popup. + p.setVisible (false); + + } + + } + + }); + + } + + pa.setPreferredSize (new Dimension (380, + pa.getPreferredSize ().height)); + + return pa; + + } + + public static QPopup createClosablePopup (final String title, + final Icon icon, + final ActionListener onClose, + final Component content, + final AbstractViewer viewer, + Point showAt) + { + + final QPopup ep = UIUtils.createClosablePopup (title, + icon, + onClose); + + Box b = new Box (BoxLayout.Y_AXIS); + + b.setBorder (UIUtils.createPadding (10, 10, 10, 10)); + + b.add (content); + + ep.setContent (b); + + b.setPreferredSize (new Dimension (UIUtils.getPopupWidth (), + b.getPreferredSize ().height)); + + if (showAt == null) + { + + showAt = UIUtils.getCenterShowPosition (viewer, + ep); + + } + + viewer.showPopupAt (ep, + showAt, + false); + ep.setDraggable (viewer); + + return ep; + + } + + public static QPopup createClosablePopup (final String title, + final Icon icon, + final ActionListener onClose) + { + + final QPopup qp = new QPopup (Environment.replaceObjectNames (title), + icon, + null) + { + + public void setVisible (boolean v) + { + + if ((!v) + && + (onClose != null) + ) + { + + onClose.actionPerformed (new ActionEvent (this, + 0, + "closing")); + + } + + super.setVisible (v); + + } + + }; + + JButton close = UIUtils.createButton (Constants.CLOSE_ICON_NAME, + Constants.ICON_MENU, + getUIString (actions,clicktoclose), + //"Click to close", + new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + qp.removeFromParent (); + + } + + }); + + List buts = new ArrayList (); + buts.add (close); + + qp.getHeader ().setControls (UIUtils.createButtonBar (buts)); + + return qp; + + } + + public static DefaultMutableTreeNode createChapterNotesNode (Chapter c) + { + + if (!UserProperties.getAsBoolean (Constants.SHOW_NOTES_IN_CHAPTER_LIST_PROPERTY_NAME)) + { + + return null; + + } + + Set notes = c.getNotes (); + + if ((notes == null) + || + (notes.size () == 0) + ) + { + + return null; + + } + + TreeParentNode nullN = new TreeParentNode (Note.OBJECT_TYPE, + getUIString (objectnames,plural, Note.OBJECT_TYPE), + //Environment.replaceObjectNames ("{Notes}"), + notes.size ()); + + DefaultMutableTreeNode root = new DefaultMutableTreeNode (nullN); + + for (Note n : c.getNotes ()) + { + + DefaultMutableTreeNode node = UIUtils.createTreeNode (n, + null, + null, + false); + + if (node == null) + { + + continue; + + } + + root.add (node); + + } + + if ((c.getNotes () == null) + || + (c.getNotes ().size () == 0) + ) + { + + return null; + + } + + return root; + + } + + public static DefaultMutableTreeNode createNoteTree (ProjectViewer pv) + { + + DefaultMutableTreeNode root = new DefaultMutableTreeNode (pv.getProject ()); + + Map> typeNotes = pv.getNotesAgainstTypes (); + + Map noteNodes = new HashMap (); + + TreeParentNode nullN = new TreeParentNode (Note.OBJECT_TYPE, + "No Type"); + + DefaultMutableTreeNode nullNode = new DefaultMutableTreeNode (nullN); + + noteNodes.put (null, + nullNode); + + Set types = typeNotes.keySet (); + + for (String type : types) + { + + boolean added = false; + + Set notes = typeNotes.get (type); + + for (Note n : notes) + { + + String t = n.getType (); + + DefaultMutableTreeNode noteNode = null; + + if ((t == null) || + (t.equals (""))) + { + + noteNode = noteNodes.get (null); + + } else + { + + if (t.equals (type)) + { + + if (!added) + { + + added = true; + + TreeParentNode b = new TreeParentNode (Note.OBJECT_TYPE, + type, + notes.size ()); + //noteTypeHandler.getObjectsForType (t).size ()); + + DefaultMutableTreeNode tn = new DefaultMutableTreeNode (b); + + root.add (tn); + + noteNodes.put (type, + tn); + + } + + noteNode = noteNodes.get (t); + + } + + } + + if (noteNode != null) + { + + DefaultMutableTreeNode nn = new DefaultMutableTreeNode (n); + + noteNode.add (nn); + + } + + } + + } + + if (nullNode.getChildCount () > 0) + { + + // Insert at the top. + root.insert (nullNode, + 0); + + } + + return root; + + } + + public static JRadioButton createRadioButton (String text) + { + + return UIUtils.createRadioButton (text, + null); + + } + + public static JRadioButton createRadioButton (String text, + ActionListener onClick) + { + + JRadioButton b = new JRadioButton () + { + + @Override + public void setText (String t) + { + + super.setText (String.format ("%s", + Environment.replaceObjectNames (t))); + + } + + }; + + b.setText (text); + b.setBackground (null); + b.setOpaque (false); + + if (onClick != null) + { + + b.addActionListener (onClick); + + } + + b.setVerticalTextPosition (SwingConstants.TOP); + b.setVerticalAlignment (SwingConstants.TOP); + + return b; + + } + + public static JCheckBox createCheckBox (String text) + { + + return UIUtils.createCheckBox (text, + null); + + } + + public static JCheckBox createCheckBox (String text, + ActionListener onClick) + { + + JCheckBox b = new JCheckBox () + { + + @Override + public void setText (String t) + { + + super.setText (String.format ("%s", + t)); + + } + + }; + + b.setText (text); + b.setBackground (null); + b.setOpaque (false); + + if (onClick != null) + { + + b.addActionListener (onClick); + + } + + b.setVerticalTextPosition (SwingConstants.TOP); + b.setVerticalAlignment (SwingConstants.TOP); + + return b; + + } + + public static DefaultMutableTreeNode createChaptersTree (Project p, + Collection exclude, + Collection init, + boolean selectable) + { + + DefaultMutableTreeNode root = UIUtils.createTreeNode (p, + exclude, + init, + selectable); + + if (p.getBooks ().size () == 1) + { + + Book b = (Book) p.getBooks ().get (0); + + // Get the chapters. + List chaps = b.getChapters (); + + for (Chapter c : chaps) + { + + DefaultMutableTreeNode node = UIUtils.createTree (c, + exclude, + init, + selectable); + + if (node == null) + { + + continue; + + } + + root.add (node); + + } + + } else + { + + List books = p.getBooks (); + + for (int i = 0; i < books.size (); i++) + { + + Book b = books.get (i); + + DefaultMutableTreeNode node = UIUtils.createTree (b, + exclude, + init, + selectable); + + if (node == null) + { + + continue; + + } + + root.add (node); + + } + + } + + return root; + + } + + public static void addAssetsToLinkToTree (DefaultMutableTreeNode root, + UserConfigurableObjectType forType, + Set assets, + Collection exclude, + Collection init, + boolean selectable) + { + + if ((assets == null) + || + (assets.size () == 0) + ) + { + + return; + + } + + DefaultMutableTreeNode charn = null; + + if (selectable) + { + + SelectableDataObject s = new SelectableDataObject (forType); + s.parentNode = true; + + charn = new DefaultMutableTreeNode (s); + + root.add (charn); + + root = charn; + + } + + for (Asset a : assets) + { + + if (!selectable) + { + + if (!init.contains (a)) + { + + continue; + + } + + } + + DefaultMutableTreeNode node = UIUtils.createTreeNode (a, + exclude, + init, + selectable); + + if (node == null) + { + + continue; + + } + + root.add (node); + + } + + } + + public static DefaultMutableTreeNode createLinkToTree (Project p, + Collection exclude, + Collection init, + boolean selectable) + { + + DefaultMutableTreeNode root = UIUtils.createTreeNode (p, + exclude, + init, + selectable); + + if (p.getBooks ().size () == 1) + { + + Book b = (Book) p.getBooks ().get (0); + + // Get the chapters. + List chaps = b.getChapters (); + + for (Chapter c : chaps) + { + + if (!selectable) + { + + if (!init.contains (c)) + { + + continue; + + } + + } + + DefaultMutableTreeNode node = UIUtils.createTree (c, + exclude, + init, + selectable); + + if (node == null) + { + + continue; + + } + + root.add (node); + + } + + } else + { + + List books = p.getBooks (); + + for (int i = 0; i < books.size (); i++) + { + + Book b = books.get (i); + + if (!selectable) + { + + if (!init.contains (b)) + { + + continue; + + } + + } + + DefaultMutableTreeNode node = UIUtils.createTree (b, + exclude, + init, + selectable); + + if (node == null) + { + + continue; + + } + + root.add (node); + + } + + } + + Set assetTypes = Environment.getAssetUserConfigurableObjectTypes (true); + + for (UserConfigurableObjectType t : assetTypes) + { + + Set as = p.getAssets (t); + + UIUtils.addAssetsToLinkToTree (root, + t, + as, + exclude, + init, + selectable); + + } + + Map> allNotes = new TreeMap (); + + List books = p.getBooks (); + + // Collect all the notes. + for (int i = 0; i < books.size (); i++) + { + + List chapters = books.get (i).getChapters (); + + for (int j = 0; j < chapters.size (); j++) + { + + Set notes = chapters.get (j).getNotes (); + + for (Note n : notes) + { + + String t = n.getType (); + + Set l = allNotes.get (t); + + if (l == null) + { + + l = new TreeSet (new ChapterItemSorter ()); + + allNotes.put (t, + l); + + } + + l.add (n); + + } + + } + + } + + Iterator>> iter = allNotes.entrySet ().iterator (); + + while (iter.hasNext ()) + { + + Map.Entry> item = iter.next (); + + String t = item.getKey (); + + Set l = item.getValue (); + + // Peek at the top of the list to see the actual type. + t = l.iterator ().next ().getType (); + //t = l.get (0).getType (); + + BlankNamedObject bdo = new BlankNamedObject (Note.OBJECT_TYPE, + t); + + Object o = bdo; + + if (selectable) + { + + SelectableDataObject s = new SelectableDataObject (bdo); + s.parentNode = true; + o = s; + + } + + DefaultMutableTreeNode tn = new DefaultMutableTreeNode (o); + + for (Note n : l) + { + + if (!selectable) + { + + if (!init.contains (n)) + { + + continue; + + } + + } + + DefaultMutableTreeNode node = UIUtils.createTreeNode (n, + exclude, + init, + selectable); + + if (node != null) + { + + tn.add (node); + + } + + } + + if (tn.getChildCount () > 0) + { + + root.add (tn); + + } + + } + + return root; + + } + + public static void expandAllNodesWithChildren (JTree t) + { + + DefaultTreeModel dtm = (DefaultTreeModel) t.getModel (); + + DefaultMutableTreeNode root = (DefaultMutableTreeNode) dtm.getRoot (); + + Enumeration en = root.depthFirstEnumeration (); + + while (en.hasMoreElements ()) + { + + DefaultMutableTreeNode node = (DefaultMutableTreeNode) en.nextElement (); + + if (node.getChildCount () > 0) + { + + t.expandPath (new TreePath (node.getPath ())); + + } + + } + + } + + public static void getSelectedObjects (DefaultMutableTreeNode n, + Set s) + { + + Enumeration en = n.children (); + + while (en.hasMoreElements ()) + { + + DefaultMutableTreeNode nn = (DefaultMutableTreeNode) en.nextElement (); + + SelectableDataObject sd = (SelectableDataObject) nn.getUserObject (); + + if (sd.selected) + { + + s.add (sd.obj); + + } + + UIUtils.getSelectedObjects (nn, + s); + + } + + } + + public static void addSelectableListener (final JTree tree) + { + + tree.addMouseListener (new MouseEventHandler () + { + + private void selectAllChildren (DefaultTreeModel model, + DefaultMutableTreeNode n, + boolean v) + { + + Enumeration en = n.children (); + + while (en.hasMoreElements ()) + { + + DefaultMutableTreeNode c = (DefaultMutableTreeNode) en.nextElement (); + + SelectableDataObject s = (SelectableDataObject) c.getUserObject (); + + s.selected = v; + + // Tell the model that something has changed. + model.nodeChanged (c); + + // Iterate. + this.selectAllChildren (model, + c, + v); + + } + + } + + @Override + public void handlePress (MouseEvent ev) + { + + TreePath tp = tree.getPathForLocation (ev.getX (), + ev.getY ()); + + if (tp != null) + { + + DefaultMutableTreeNode n = (DefaultMutableTreeNode) tp.getLastPathComponent (); + + // Tell the model that something has changed. + DefaultTreeModel model = (DefaultTreeModel) tree.getModel (); + + SelectableDataObject s = (SelectableDataObject) n.getUserObject (); +/* + if ((ev.getClickCount () == 2) + && + (n.getChildCount () > 0) + ) + { + + this.selectAllChildren (model, + n, + s.selected); + + } else { + + s.selected = !s.selected; + + } +*/ + s.selected = !s.selected; + + model.nodeChanged (n); + + } + + } + + }); + + } + + public static DefaultMutableTreeNode createTree (Book b, + Collection exclude, + Collection init, + boolean selectable) + { + + DefaultMutableTreeNode root = UIUtils.createTreeNode (b, + exclude, + init, + selectable); + + if (root == null) + { + + return null; + + } + + // Get the chapters. + List chs = b.getChapters (); + + for (int i = 0; i < chs.size (); i++) + { + + Chapter c = chs.get (i); + + if (!selectable) + { + + if ((init != null) + && + (!init.contains (c)) + ) + { + + continue; + + } + + } + + DefaultMutableTreeNode node = UIUtils.createTree (c, + exclude, + init, + selectable); + + if (node == null) + { + + continue; + + } + + root.add (node); + + } + + return root; + + } + + public static DefaultMutableTreeNode createTreeNode (Object o, + Collection exclude, + Collection init, + boolean selectable) + { + + if ((exclude != null) && + (exclude.contains (o))) + { + + return null; + + } + + if (selectable) + { + + SelectableDataObject so = new SelectableDataObject ((NamedObject) o); + + if ((init != null) + && + (init.contains (o)) + ) + { + + so.selected = true; + + } + + o = so; + + } + + return new DefaultMutableTreeNode (o); + + } + + public static DefaultMutableTreeNode createTree (Scene s, + Collection exclude, + Collection init, + boolean selectable) + { + + DefaultMutableTreeNode root = UIUtils.createTreeNode (s, + exclude, + init, + selectable); + + if (root == null) + { + + return null; + + } + + // Get the outline items. + Iterator iter = s.getOutlineItems ().iterator (); + + while (iter.hasNext ()) + { + + Object o = iter.next (); + + if (!selectable) + { + + if ((init != null) && + (!init.contains (o))) + { + + continue; + + } + + } + + DefaultMutableTreeNode node = UIUtils.createTreeNode (o, + exclude, + init, + selectable); + + if (node == null) + { + + continue; + + } + + root.add (node); + + } + + return root; + + } + + public static DefaultMutableTreeNode createTree (Chapter c, + Collection exclude, + Collection init, + boolean selectable) + { + + DefaultMutableTreeNode root = UIUtils.createTreeNode (c, + exclude, + init, + selectable); + + if (root == null) + { + + return null; + + } + + List items = new ArrayList (c.getScenes ()); + + items.addAll (c.getOutlineItems ()); + + Collections.sort (items, + new ChapterItemSorter ()); + + for (int j = 0; j < items.size (); j++) + { + + ChapterItem i = (ChapterItem) items.get (j); +/* + if (i instanceof Note) + { + + Note n = (Note) i; + + DefaultMutableTreeNode node = UIUtils.createTreeNode ((Note) n, + exclude, + init, + false); + + if (node == null) + { + + continue; + + } + + root.add (node); + + } +*/ + if (i instanceof Scene) + { + + Scene s = (Scene) i; + + if (!selectable) + { + + if ((init != null) && + (!init.contains (s))) + { + + continue; + + } + + } + + DefaultMutableTreeNode node = UIUtils.createTree ((Scene) s, + exclude, + init, + selectable); + + if (node == null) + { + + continue; + + } + + root.add (node); + + } + + if (i instanceof OutlineItem) + { + + OutlineItem oi = (OutlineItem) i; + + if (!selectable) + { + + if ((init != null) && + (!init.contains (oi))) + { + + continue; + + } + + } + + DefaultMutableTreeNode node = UIUtils.createTreeNode (oi, + exclude, + init, + selectable); + + if (node == null) + { + + continue; + + } + + root.add (node); + + } + + } + + if (!selectable) + { + + DefaultMutableTreeNode notesNode = UIUtils.createChapterNotesNode (c); + + if (notesNode != null) + { + + root.add (notesNode); + + } + + } + + return root; + + } + + private static void showErrorMessage (final PopupsSupported parent, + final String message) + { + + if (parent == null) + { + + return; + + } + + // Force back onto event thread. + UIUtils.doActionLater (new ActionListener () + { + + public void actionPerformed (ActionEvent ev) + { + + final Box content = new Box (BoxLayout.Y_AXIS); + + AbstractProjectViewer pv = null; + + if (parent instanceof AbstractProjectViewer) + { + + pv = (AbstractProjectViewer) parent; + + } + + JTextPane m = UIUtils.createHelpTextPane (String.format (Environment.getUIString (LanguageStrings.errormessage, + LanguageStrings.text), + //"%s

    Click here to contact Quoll Writer support about this problem.", + message, + Constants.ACTION_PROTOCOL, + "reportbug"), + pv); + m.setSize (new Dimension (UIUtils.getPopupWidth () - 20, + m.getPreferredSize ().height)); + m.setBorder (null); + content.add (m); + + content.add (Box.createVerticalStrut (10)); + + JButton close = UIUtils.createButton (getUIString (buttons, LanguageStrings.close)); + + JButton[] buts = new JButton[] { close }; + + JComponent buttons = UIUtils.createButtonBar2 (buts, + Component.LEFT_ALIGNMENT); + buttons.setAlignmentX (Component.LEFT_ALIGNMENT); + content.add (buttons); + content.setBorder (new EmptyBorder (10, 10, 10, 10)); + + final QPopup ep = UIUtils.createPopup (Environment.getUIString (LanguageStrings.errormessage, + LanguageStrings.title), + //"Oops, an error has occurred...", + Constants.ERROR_ICON_NAME, + content, + true, + null); + + close.addActionListener (new ActionListener () + { + + public void actionPerformed (ActionEvent ev) + { + + ep.removeFromParent (); + + } + }); + + content.setPreferredSize (new Dimension (UIUtils.getPopupWidth (), + content.getPreferredSize ().height)); + + parent.showPopupAt (ep, + UIUtils.getCenterShowPosition ((Component) parent, + ep), + false); + ep.setDraggable ((Component) parent); + + } + + }); + + } + + /** + * And this convoluted mess is what happens when you change something fundemantal half way + * through! This needs to be cleaned up in a future release. + * + * @param parent The parent to show the error against. + * @param message The message to show. + */ + public static void showErrorMessage (Object parent, + String message) + { + + if (parent == null) + { + + UIUtils.showErrorMessage (message); + + return; + + } + + if (parent instanceof PopupsSupported) + { + + UIUtils.showErrorMessage ((PopupsSupported) parent, + message); + + return; + + } + + if (parent instanceof PopupWindow) + { + + UIUtils.showErrorMessage ((PopupWindow) parent, + message); + + return; + + } + + if (parent instanceof PopupWindow) + { + + UIUtils.showErrorMessage (((PopupWindow) parent).getViewer (), + message); + + return; + + } + + if (parent instanceof QuollPanel) + { + + UIUtils.showErrorMessage ((PopupsSupported) ((QuollPanel) parent).getViewer (), + message); + + return; + + } + + UIUtils.showErrorMessage (message); + + } +/* + private static void showErrorMessage (final AbstractProjectViewer pv, + final String message) + { + + if (pv == null) + { + + return; + + } + + UIUtils.doActionLater (new ActionListener () + { + + public void actionPerformed (ActionEvent ev) + { + + ErrorWindow ew = new ErrorWindow (pv, + message); + + ew.init (); + + } + + }); + + } + */ + private static void showErrorMessage (final PopupWindow p, + final String message) + { + + if (p == null) + { + + return; + + } + + UIUtils.doActionLater (new ActionListener () + { + + public void actionPerformed (ActionEvent ev) + { + + ErrorWindow ew = new ErrorWindow (p.getViewer (), + message); + + ew.init (); + + Rectangle pbounds = p.getBounds (); + + Dimension size = ew.getPreferredSize (); + + int x = ((pbounds.width - size.width) / 2) + pbounds.x; + int y = ((pbounds.height - size.height) / 2) + pbounds.y; + + // Move the window + Point showAt = new Point (x, + y); + + ew.setShowAt (showAt); + + } + + }); + + } + + private static void showErrorMessage (final String message) + { + + UIUtils.doActionLater (new ActionListener () + { + + public void actionPerformed (ActionEvent ev) + { + + ErrorWindow ew = new ErrorWindow (null, + message); + + ew.init (); + + } + + }); + + } + + public static void showObjectSelectPopup (final Set objs, + final AbstractViewer parent, + final String popupTitle, + final ActionListener onSelect, + final boolean closeOnSelect, + final Point showAt) + { + + UIUtils.showObjectSelectPopup (objs, + parent, + popupTitle, + new DefaultListCellRenderer () + { + + @Override + public Component getListCellRendererComponent (JList list, + Object value, + int index, + boolean isSelected, + boolean cellHasFocus) + { + + NamedObject obj = (NamedObject) value; + + JLabel l = (JLabel) super.getListCellRendererComponent (list, + value, + index, + isSelected, + cellHasFocus); + + l.setText (obj.getName ()); + + l.setFont (l.getFont ().deriveFont (UIUtils.getScaledFontSize (14)).deriveFont (Font.PLAIN)); + l.setIcon (Environment.getObjectIcon (obj, + Constants.ICON_NOTIFICATION)); + l.setBorder (UIUtils.createBottomLineWithPadding (5, 5, 5, 5)); + + if (cellHasFocus) + { + + l.setBackground (UIUtils.getHighlightColor ()); + + } + + return l; + + } + + }, + onSelect, + closeOnSelect, + showAt); + + } + + public static void showObjectSelectPopup (final Set objs, + final AbstractViewer parent, + final String popupTitle, + final ListCellRenderer renderer, + final ActionListener onSelect, + final boolean closeOnSelect, + final Point showAt) + { + + UIUtils.showObjectSelectPopup (objs, + parent, + popupTitle, + renderer, + onSelect, + closeOnSelect, + null, + showAt); + + } + + public static void showObjectSelectPopup (final Set objs, + final AbstractViewer parent, + final String popupTitle, + final ListCellRenderer renderer, + final ActionListener onSelect, + final boolean closeOnSelect, + final JComponent extra, + final Point showAt) + { + + if (popupTitle == null) + { + + throw new IllegalArgumentException ("Expected a popup title."); + + } + + UIUtils.doActionLater (new ActionListener () + { + + public void actionPerformed (ActionEvent ev) + { + + final Box content = new Box (BoxLayout.Y_AXIS); + + content.setOpaque (true); + content.setBackground (UIUtils.getComponentColor ()); + + DefaultListModel m = new DefaultListModel (); + + for (NamedObject o : objs) + { + + m.addElement (o); + + } + + final JList l = new JList (); + l.setModel (m); + l.setLayoutOrientation (JList.VERTICAL); + l.setVisibleRowCount (0); + l.setOpaque (true); + l.setBackground (UIUtils.getComponentColor ()); + l.setMaximumSize (new Dimension (Short.MAX_VALUE, + Short.MAX_VALUE)); + UIUtils.setAsButton (l); + + l.setCellRenderer (renderer); +/* + new DefaultListCellRenderer () + { + + public Component getListCellRendererComponent (JList list, + Object value, + int index, + boolean isSelected, + boolean cellHasFocus) + { + + NamedObject obj = (NamedObject) value; + + JLabel l = (JLabel) super.getListCellRendererComponent (list, + value, + index, + isSelected, + cellHasFocus); + + l.setText (obj.getName ()); + + l.setFont (l.getFont ().deriveFont (UIUtils.getScaledFontSize (14)).deriveFont (Font.PLAIN)); + l.setIcon (Environment.getObjectIcon (obj, + Constants.ICON_NOTIFICATION)); + l.setBorder (UIUtils.createBottomLineWithPadding (5, 5, 5, 5)); + + if (cellHasFocus) + { + + l.setBackground (Environment.getHighlightColor ()); + + } + + return l; + + } + + }); +*/ +/* + int rowHeight = 37; + + Component t = renderer.getListCellRendererComponent (l, + objs.iterator ().next (), + 0, + false, + false); + + rowHeight = t.getPreferredSize ().height; +*/ + l.setAlignmentX (JComponent.LEFT_ALIGNMENT); + /* + final Dimension sSize = new Dimension (this.swatchSize.width + (2 * this.borderWidth) + (2 * this.horizGap), + this.swatchSize.height + (2 * this.borderWidth) + (2 * this.vertGap)); + */ + JScrollPane sp = new JScrollPane (l); + + sp.setHorizontalScrollBarPolicy (ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); + sp.getVerticalScrollBar ().setUnitIncrement (20);//rowHeight); + sp.setAlignmentX (JComponent.LEFT_ALIGNMENT); + sp.setOpaque (false); +/* + sp.getViewport ().setPreferredSize (new Dimension (400, + rowHeight * (objs.size () > 3 ? 3 : objs.size ()))); +*/ + + l.setVisibleRowCount (Math.min (3, objs.size ())); + + sp.setBorder (null); + + content.add (sp); + + if (extra != null) + { + + extra.setBorder (UIUtils.createPadding (10, 5, 10, 5)); + + content.add (extra); + + } + + final QPopup ep = UIUtils.createClosablePopup (popupTitle, + Environment.getIcon (Constants.VIEW_ICON_NAME, + Constants.ICON_POPUP), + null); + + ep.setContent (content); + + l.addListSelectionListener (new ListSelectionListener () + { + + @Override + public void valueChanged (ListSelectionEvent ev) + { + + if (onSelect != null) + { + + NamedObject obj = (NamedObject) l.getSelectedValue (); + + onSelect.actionPerformed (new ActionEvent (obj, + 0, + obj.getObjectReference ().asString ())); + + if (closeOnSelect) + { + + ep.removeFromParent (); + + } + + } + } + + }); + + content.setPreferredSize (new Dimension (UIUtils.getPopupWidth (), + content.getPreferredSize ().height)); + + parent.showPopupAt (ep, + (showAt != null ? showAt : UIUtils.getCenterShowPosition (parent, + ep)), + false); + ep.setDraggable (parent); + + } + + }); + + } + + public static void showMessage (final PopupsSupported parent, + final String title, + final Component message) + { + + UIUtils.showMessage (parent, + title, + message, + null, + null); + + } + + public static void showMessage (final PopupsSupported parent, + final String title, + final Component message, + final String confirmButtonLabel, + final ActionListener onConfirm) + { + + UIUtils.showMessage (parent, + title, + message, + confirmButtonLabel, + onConfirm, + null); + + } + + public static void showMessage (final PopupsSupported parent, + final String title, + final Component message, + final String confirmButtonLabel, + final ActionListener onConfirm, + final Point showAt) + { + + if (parent == null) + { + + return; + + } + + UIUtils.doActionLater (new ActionListener () + { + + public void actionPerformed (ActionEvent ev) + { + + final Box content = new Box (BoxLayout.Y_AXIS); + + content.setOpaque (true); + content.setBackground (UIUtils.getComponentColor ()); + content.add (message); + + content.add (Box.createVerticalStrut (10)); + + JButton close = UIUtils.createButton ((confirmButtonLabel != null ? confirmButtonLabel : getUIString (buttons, LanguageStrings.close)), + onConfirm); + + JButton[] buts = new JButton[] { close }; + + JComponent buttons = UIUtils.createButtonBar2 (buts, + Component.CENTER_ALIGNMENT); + buttons.setAlignmentX (Component.LEFT_ALIGNMENT); + content.add (buttons); + content.setBorder (new EmptyBorder (10, 10, 10, 10)); + + final QPopup ep = UIUtils.createClosablePopup ((title != null ? title : getUIString (generalmessage,LanguageStrings.title)), + //"Just so you know..."), + Environment.getIcon (Constants.INFO_ICON_NAME, + Constants.ICON_POPUP), + onConfirm); + + ep.setContent (content); + + close.addActionListener (ep.getCloseAction ()); + + content.setPreferredSize (new Dimension (UIUtils.getPopupWidth (), + content.getPreferredSize ().height)); + + parent.showPopupAt (ep, + (showAt != null ? showAt : UIUtils.getCenterShowPosition ((Component) parent, + ep)), + false); + ep.setDraggable ((Component) parent); + + } + + }); + + } + + public static void showMessage (final PopupsSupported parent, + final String title, + final String message, + final String confirmButtonLabel, + final ActionListener onConfirm) + { + + UIUtils.showMessage (parent, + title, + message, + confirmButtonLabel, + onConfirm, + null); + + } + + public static void showMessage (final PopupsSupported parent, + final String title, + final String message, + final String confirmButtonLabel, + final ActionListener onConfirm, + final Point showAt) + { + + AbstractViewer pv = null; + + if (parent instanceof AbstractViewer) + { + + pv = (AbstractViewer) parent; + + } + + JTextPane m = UIUtils.createHelpTextPane (message, + pv); + + m.setSize (new Dimension (UIUtils.getPopupWidth () - 20, + m.getPreferredSize ().height)); + m.setBorder (null); + + UIUtils.showMessage (parent, + title, + m, + confirmButtonLabel, + onConfirm, + showAt); + + } + + public static void showMessage (PopupsSupported parent, + String title, + String message) + { + + UIUtils.showMessage (parent, + title, + message, + null); + + } + + public static void showMessage (PopupsSupported parent, + String title, + String message, + Point showAt) + { + + UIUtils.showMessage (parent, + title, + message, + null, + null, + showAt); + + } + + public static void showMessage (AbstractViewer parent, + String title, + String message, + String confirmButtonLabel, + ActionListener onConfirm) + { + + if (parent == null) + { + + UIUtils.showMessage (title, + message, + confirmButtonLabel, + onConfirm); + + return; + + } + + UIUtils.showMessage ((PopupsSupported) parent, + title, + message, + confirmButtonLabel, + onConfirm); + + } + + public static void showMessage (Component parent, + String title, + String message, + String confirmButtonLabel, + ActionListener onConfirm) + { + + if (parent == null) + { + + UIUtils.showMessage (title, + message, + confirmButtonLabel, + onConfirm); + + return; + + } + + if (parent instanceof QuollPanel) + { + + UIUtils.showMessage ((PopupsSupported) ((QuollPanel) parent).getViewer (), + title, + message, + confirmButtonLabel, + onConfirm); + + return; + + } + + if (parent instanceof PopupsSupported) + { + + UIUtils.showMessage ((PopupsSupported) parent, + title, + message, + confirmButtonLabel, + onConfirm); + + return; + + } + + if (parent instanceof PopupWindow) + { + + UIUtils.showMessage (((PopupWindow) parent).getViewer (), + title, + message, + confirmButtonLabel, + onConfirm); + + return; + + } + + UIUtils.showMessage (title, + message, + confirmButtonLabel, + onConfirm); + + } + + public static void showMessage (Component parent, + String title, + String message) + { + + UIUtils.showMessage (parent, + title, + message, + null, + null); + + } + + public static void showMessage (Component parent, + String message) + { + + UIUtils.showMessage (parent, + null, + message, + null, + null); + + } + + private static void showMessage (String title, + String message, + String confirmButtonLabel, + ActionListener onConfirm) + { + + MessageWindow ew = new MessageWindow (null, + title, + message, + confirmButtonLabel, + onConfirm); + + ew.init (); + + } + + public static QPopup createPopup (String title, + String icon, + JComponent content, + boolean includeCancel, + final ActionListener cancelListener) + { + + final QPopup p = new QPopup (title, + (icon != null ? Environment.getIcon (icon, + Constants.ICON_POPUP) : null), + null); + + if (content != null) + { + + p.setContent (content); + + } + + if (includeCancel) + { + + final JButton cancel = UIUtils.createButton ("cancel", + Constants.ICON_MENU, + getUIString (actions,clicktoclose), + //"Click to close.", + null); + + cancel.addActionListener (new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + p.setVisible (false); + + if (cancelListener != null) + { + + cancelListener.actionPerformed (ev); + + } + + } + + }); + + List buts = new ArrayList (); + buts.add (cancel); + + p.getHeader ().setControls (UIUtils.createButtonBar (buts)); + + } + + return p; + + } + + public static JLabel createInformationLabel (String message) + { + + JLabel l = new JLabel () + { + + public void setText (String t) + { + + if (t == null) + { + + super.setText (""); + + return; + + } + + super.setText (String.format ("%s", + t)); + + } + + }; + + l.setText (message); + l.setAlignmentX (Component.LEFT_ALIGNMENT); + + return l; + + } + + public static JLabel createLoadingLabel (String message) + { + + JLabel l = new JLabel (Environment.getLoadingIcon (), + SwingConstants.LEFT) + { + + @Override + public void setText (String t) + { + + super.setText (String.format ("%s", + (t != null ? t : getUIString (general,loading)))); + //"Loading..."))); + + } + + }; + + l.setText (message); + l.setVisible (false); + l.setAlignmentX (Component.LEFT_ALIGNMENT); + + return l; + + } + + public static JLabel createErrorLabel (String message) + { + + JLabel err = new JLabel () + { + + @Override + public void setText (String t) + { + + super.setText (String.format ("%s", + t)); + + } + + @Override + public void setToolTipText (String t) + { + + super.setText (String.format ("%s", + Environment.replaceObjectNames (t))); + + } + + }; + + err.setText (message); + err.setForeground (UIUtils.getColor (Constants.ERROR_TEXT_COLOR)); + err.setIcon (Environment.getIcon (Constants.ERROR_RED_ICON_NAME, + Constants.ICON_MENU)); + err.setAlignmentX (Component.LEFT_ALIGNMENT); + err.setVerticalTextPosition (SwingConstants.TOP); + err.setVerticalAlignment (SwingConstants.TOP); + + return err; + + } + + public static JLabel createLabel (String message) + { + + JLabel err = new JLabel () + { + + @Override + public void setText (String t) + { + + super.setText (String.format ("%s", + t)); + + } + + }; + + err.setText (message); + err.setAlignmentX (Component.LEFT_ALIGNMENT); + + return err; + + } + + public static void createPopupMenuLabels (Map labels) + { + + int maxWidth = 0; + int maxHeight = 0; + + Iterator iter = labels.keySet ().iterator (); + + while (iter.hasNext ()) + { + + String l = (String) iter.next (); + + JLabel lab = new JLabel (l + " "); + lab.setOpaque (false); + lab.setBorder (null); + + labels.put (l, + lab); + + Dimension dim = lab.getPreferredSize (); + + int w = dim.width; + int h = dim.height; + + if (w > maxWidth) + { + + maxWidth = w; + + } + + if (h > maxHeight) + { + + maxHeight = h; + + } + + } + + FormLayout fl = new FormLayout ("right:" + maxWidth + "px", + "center:" + 20 + "px"); + + iter = labels.entrySet ().iterator (); + + while (iter.hasNext ()) + { + + PanelBuilder b = new PanelBuilder (fl); + CellConstraints cc = new CellConstraints (); + + Map.Entry item = (Map.Entry) iter.next (); + + String l = (String) item.getKey (); + + JLabel ll = (JLabel) item.getValue (); + + b.add (ll, + cc.xy (1, + 1)); + + JPanel p = b.getPanel (); + p.setOpaque (false); + + labels.put (l, + p); + + } + + } + + public static void setAsButton (Component c) + { + + c.setCursor (Cursor.getPredefinedCursor (Cursor.HAND_CURSOR)); + + } + + public static void setDefaultCursor (Component c) + { + + c.setCursor (Cursor.getPredefinedCursor (Cursor.DEFAULT_CURSOR)); + + } + + public static void setAsButton2 (Component c) + { + + c.setCursor (Cursor.getPredefinedCursor (Cursor.HAND_CURSOR)); + + if (c instanceof AbstractButton) + { + + final AbstractButton b = (AbstractButton) c; + + b.setContentAreaFilled (false); + + // b.setMargin (new Insets (2, 2, 2, 2)); + b.addMouseListener (new MouseEventHandler () + { + + @Override + public void mouseEntered (MouseEvent ev) + { + + b.setContentAreaFilled (true); + + } + + @Override + public void mouseExited (MouseEvent ev) + { + + b.setContentAreaFilled (false); + + } + + }); + + } + + } + + public static Border createLineBorder () + { + + return new LineBorder (UIUtils.getBorderColor (), + 1); + + } + + public static JComboBox createNumberComboBox (Vector vals, + int def) + { + + final JComboBox cb = new JComboBox (vals); + + cb.setEditor (new javax.swing.plaf.basic.BasicComboBoxEditor () + { + + protected JTextField createEditorComponent () + { + + return new FormattedTextField ("[0-9]"); + + } + + }); + + cb.setEditable (true); + + cb.setMaximumSize (cb.getPreferredSize ()); + + if (def > 0) + { + + cb.setSelectedItem (def); + + } + + return cb; + + } + + public static JComboBox getFontSizesComboBox (final int sizeDef) + { + + Vector sizeV = new Vector (); + + boolean defAdded = false; + + for (int i = 8; i < 19; i += 2) + { + + if ((sizeDef < i) && + (!defAdded)) + { + + sizeV.addElement (sizeDef); + defAdded = true; + + } + + if (i != sizeDef) + { + + sizeV.addElement (i); + + } + + } + + if (sizeDef > 18) + { + + sizeV.addElement (sizeDef); + + } + + final JComboBox sizes = UIUtils.createNumberComboBox (sizeV, + sizeDef); + + return sizes; + + } + + public static JComboBox getLineSpacingComboBox (final float lsDef) + { + + Vector lineS = new Vector (); + + boolean defAdded = false; + + for (float i = 0.5f; i < 2.5f; i += 0.5f) + { + + if ((lsDef < i) && + (!defAdded)) + { + + lineS.addElement (lsDef); + defAdded = true; + + } + + if (lsDef != i) + { + + lineS.addElement (i); + + } + + } + + if (lsDef > 2.0f) + { + + lineS.addElement (lsDef); + + } + + final JComboBox line = new JComboBox (lineS); + + line.setEditable (true); + + line.setEditor (new javax.swing.plaf.basic.BasicComboBoxEditor () + { + + protected JTextField createEditorComponent () + { + + return new FormattedTextField ("[0-9\\.]"); + + } + + }); + + line.setMaximumSize (line.getPreferredSize ()); + + if (lsDef > 0) + { + + line.setSelectedItem (lsDef); + + } + + return line; + + } + + public static JComboBox getFontsComboBox (final String selected) + { + + GraphicsEnvironment gEnv = GraphicsEnvironment.getLocalGraphicsEnvironment (); + + String[] envfonts = gEnv.getAvailableFontFamilyNames (); + + Vector vector = new Vector (); + + for (int i = 1; i < envfonts.length; i++) + { + + if (new Font (envfonts[i], + Font.PLAIN, + 12).canDisplayUpTo ("ABCDEFabcdef") == -1) + { + + vector.addElement (envfonts[i]); + + } + + } + + final JComboBox fonts = new JComboBox (vector); + + fonts.setRenderer (new DefaultListCellRenderer () + { + + public Component getListCellRendererComponent (JList list, + Object value, + int index, + boolean isSelected, + boolean cellHasFocus) + { + + super.getListCellRendererComponent (list, + value, + index, + isSelected, + cellHasFocus); + + this.setFont (new Font ((String) value, + Font.PLAIN, + 12)); + + return this; + + } + + }); + + fonts.setMaximumSize (new Dimension (Short.MAX_VALUE, + fonts.getPreferredSize ().height)); + + if (selected != null) + { + + fonts.setSelectedItem (selected); + + } + + return fonts; + + } + + /** + * Get a combobox for the user to select the text alignment. + * The order is always, Left, Justified, Right. + * + * LanguageStrings - "textalignments". + * + * @param alignDef The default alignment, should be one of the ALIGN_* constants from QTextEditor, can be null. + * @returns The combobox. + */ + public static JComboBox getAlignmentComboBox (final String alignDef) + { + + Vector alignS = new Vector (); + alignS.add (getUIString (textalignments,left)); + //QTextEditor.ALIGN_LEFT); + alignS.add (getUIString (textalignments,justified)); + //QTextEditor.ALIGN_JUSTIFIED); + alignS.add (getUIString (textalignments,right)); + //QTextEditor.ALIGN_RIGHT); + + final JComboBox align = new JComboBox (alignS); + + align.setMaximumSize (align.getPreferredSize ()); + + if (alignDef != null) + { + + if (alignDef.equals (QTextEditor.ALIGN_LEFT)) + { + + align.setSelectedIndex (0); + + } + + if (alignDef.equals (QTextEditor.ALIGN_JUSTIFIED)) + { + + align.setSelectedIndex (1); + + } + + if (alignDef.equals (QTextEditor.ALIGN_RIGHT)) + { + + align.setSelectedIndex (2); + + } + + //align.setSelectedItem (alignDef); + + } + + return align; + + } + + public static Component getLimitWrapper (Component c) + { + + Box sw = new Box (BoxLayout.X_AXIS); + sw.add (c); + sw.add (Box.createHorizontalGlue ()); + + return sw; + + } + + public static Border createTestLineBorder () + { + + return new LineBorder (Color.GREEN, + 1); + + } + + public static Border createTestLineBorder2 () + { + + return new LineBorder (Color.RED, + 1); + + } + + public static Header createBoldSubHeader (String title, + String iconType) + { + + Header h = new Header (Environment.replaceObjectNames (title), + ((iconType == null) ? null : Environment.getIcon (iconType, + Constants.ICON_MENU)), + null); + + h.setFont (h.getFont ().deriveFont (UIUtils.getScaledFontSize (14)).deriveFont (Font.PLAIN)); + + h.setTitleColor (UIUtils.getTitleColor ()); + h.setOpaque (false); + + h.setPaintProvider (null); + + h.setAlignmentX (Component.LEFT_ALIGNMENT); + + h.setBorder (UIUtils.createPadding (0, 0, 2, 0)); + + return h; + + } + + public static JLabel createSubHeader (String title, + String iconType) + { + + JLabel l = new JLabel (title); + l.setIcon (Environment.getIcon (iconType, + Constants.ICON_MENU)); + l.setMaximumSize (new Dimension (Short.MAX_VALUE, + l.getPreferredSize ().height)); + l.setBorder (new CompoundBorder (new MatteBorder (0, + 0, + 1, + 0, + UIUtils.getBorderColor ()), + new EmptyBorder (0, + 0, + 2, + 0))); + l.setAlignmentX (Component.LEFT_ALIGNMENT); + + return l; + + } + +/* + + public static List getChapterSnippetsForNames (Collection names, + Chapter c) + { + + return UIUtils.getTextSnippetsForNames (names, + c.getText ()); + + } +*/ +/* + public static List getTextSnippetsForNames (Collection names, + String text) + { + + List snippets = new ArrayList (); + + if (text != null) + { + + text = (text, + String.valueOf ('\r'), + ""); + + } + + TextIterator ti = new TextIterator (text); + + for (String n : names) + { + + Map> matches = ti.findInSentences (n, + null); + + if (matches != null) + { + + Iterator iter = matches.keySet ().iterator (); + + char[] tchar = text.toCharArray (); + + while (iter.hasNext ()) + { + + Sentence sen = iter.next (); + + Set inds = matches.get (sen); + + if ((inds != null) + && + (inds.size () > 0) + ) + { + + Segment s = new Segment (tchar, + sen.getAllTextStartOffset (), + sen.getText ().length ()); + + snippets.add (s); + + } + + } + + } + + } + + // Order the segments by the start offset. + try + { + + Query q = new Query (); + q.parse ("SELECT * FROM javax.swing.text.Segment ORDER BY beginIndex"); + QueryResults qr = q.execute (snippets); + + snippets = new ArrayList (qr.getResults ()); + + } catch (Exception e) { + + Environment.logError ("Unable to sort segments", + e); + + } + + return snippets; + + } +*/ +/* + public static Set getObjectsContaining (String s, + Project p) + { + + Set ret = new TreeSet (NamedObjectSorter.getInstance ()); + + for (NamedObject n : p.getAllNamedChildObjects ()) + { + + if (n.contains (s)) + { + + ret.add (n); + + } + + } + + return ret; + + } + + public static Set getAssetsContaining (String s, + Project p) + { + + Set ret = new TreeSet (NamedObjectSorter.getInstance ()); + + for (NamedObject n : p.getAllNamedChildObjects (Asset.class)) + { + + if (n.contains (s)) + { + + ret.add ((Asset) n); + + } + + } + + return ret; + + } + + public static Set getAssetsContaining (String s, + UserConfigurableObjectType limitTo, + Project p) + { + + Set ret = new TreeSet (NamedObjectSorter.getInstance ()); + + if (limitTo != null) + { + + if (!limitTo.isAssetObjectType ()) + { + + return ret; + + } + + } + + for (NamedObject n : p.getAllNamedChildObjects (limitTo)) + { + + if (n.contains (s)) + { + + ret.add ((Asset) n); + + } + + } + + return ret; + + } + + public static Set getNotesContaining (String s, + Project p) + { + + Set ret = new TreeSet (NamedObjectSorter.getInstance ()); + + for (NamedObject n : p.getAllNamedChildObjects (Note.class)) + { + + if (n.contains (s)) + { + + ret.add ((Note) n); + + } + + } + + return ret; + + } + + public static Set getOutlineItemsContaining (String s, + Project p) + { + + Set ret = new TreeSet (NamedObjectSorter.getInstance ()); + + for (NamedObject n : p.getAllNamedChildObjects (OutlineItem.class)) + { + + if (n.contains (s)) + { + + ret.add ((OutlineItem) n); + + } + + } + + return ret; + + } + + public static Set getScenesContaining (String s, + Project p) + { + + Set ret = new TreeSet (NamedObjectSorter.getInstance ()); + + for (NamedObject n : p.getAllNamedChildObjects (Scene.class)) + { + + if (n.contains (s)) + { + + ret.add ((Scene) n); + + } + + } + + return ret; + + } +*/ + public static Map> getObjectSnippets (NamedObject n, + AbstractProjectViewer pv) + { + + Project p = pv.getProject (); + + Map> data = new LinkedHashMap (); + + Set names = n.getAllNames (); + + // String name = n.getName ().toLowerCase (); + + // Get all the books and chapters. + List books = p.getBooks (); + + for (int i = 0; i < books.size (); i++) + { + + Book b = books.get (i); + + List chapters = b.getChapters (); + + for (int j = 0; j < chapters.size (); j++) + { + + Chapter c = chapters.get (j); + + String t = (c.getText () != null ? c.getText ().getText () : null); + + // See if there is an editor for it. + AbstractEditorPanel aep = (AbstractEditorPanel) pv.getEditorForChapter (c); + + if (aep != null) + { + + t = aep.getEditor ().getText (); + + } + + if ((t == null) + || + (t.trim ().equals ("")) + ) + { + + continue; + + } + + List snippets = TextUtilities.getTextSnippetsForNames (names, + t); + + if ((snippets != null) && + (snippets.size () > 0)) + { + + data.put (c, + snippets); + + } + + } + + } + + return data; + + } + +/* + public static Map> getTextSnippets (String s, + AbstractProjectViewer pv) + { + + Map> data = new LinkedHashMap (); + + // String name = n.getName ().toLowerCase (); + + List names = new ArrayList (); + names.add (s); + + // Get all the books and chapters. + List books = pv.getProject ().getBooks (); + + for (int i = 0; i < books.size (); i++) + { + + Book b = books.get (i); + + List chapters = b.getChapters (); + + for (int j = 0; j < chapters.size (); j++) + { + + Chapter c = chapters.get (j); + + AbstractEditorPanel qep = pv.getEditorForChapter (c); + + String t = null; + + if (qep != null) + { + + t = qep.getEditor ().getText (); + + } else { + + if (c.getText () != null) + { + + // Get the text. + t = c.getText ().getText (); + + } + + } + + if (t == null) + { + + continue; + + } + + List snippets = TextUtilities.getTextSnippetsForNames (names, + t); + + if ((snippets != null) && + (snippets.size () > 0)) + { + + data.put (c, + snippets); + + } + + } + + } + + return data; + + } +*/ + public static String markupLinks (String s) + { + + if (s == null) + { + + return s; + + } + + //s = Environment.replaceObjectNames (s); + + s = UIUtils.markupLinks ("http://", + s); + + s = UIUtils.markupLinks ("https://", + s); + + // Replace 0) + { + + char c = s.charAt (ind - 1); + + if ((c == '"') || + (c == '\'')) + { + + ind += 1; + + continue; + + } + + } + + // Find the first whitespace char after... + char[] chars = s.toCharArray (); + + StringBuilder b = new StringBuilder (); + + for (int i = ind + urlPrefix.length (); i < chars.length; i++) + { + + if ((!Character.isWhitespace (chars[i])) + && + (chars[i] != '<') + ) + { + + b.append (chars[i]); + + } else { + + break; + + } + + } + + // Now replace whatever we got... + String st = b.toString ().trim (); + + if ((st.length () == 0) + || + (st.equals (urlPrefix)) + ) + { + + ind = ind + urlPrefix.length (); + + continue; + + } + + // Not sure about this but "may" be ok. + if ((st.endsWith (";")) || + (st.endsWith (",")) || + (st.endsWith ("."))) + { + + st = st.substring (0, + st.length () - 1); + + } + + String w = null; + + try + { + + w = "" + urlPrefix + st + ""; + + } catch (Exception e) { + + // Won't happen. + + } + + StringBuilder ss = new StringBuilder (s); + + s = ss.replace (ind, + ind + st.length () + urlPrefix.length (), + w).toString (); + + ind = ind + w.length (); + + } else + { + + // No more... + break; + + } + + } + + return s; + + } + + public static void removeNodeFromTreeIfNoChildren (JTree tree, + Object n) + { + + DefaultTreeModel model = (DefaultTreeModel) tree.getModel (); + + DefaultMutableTreeNode root = (DefaultMutableTreeNode) model.getRoot (); + + // See how many children there are. + TreePath tp = UIUtils.getTreePathForUserObject (root, + n); + + if (tp != null) + { + + DefaultMutableTreeNode nNode = (DefaultMutableTreeNode) tp.getLastPathComponent (); + + if (nNode.getChildCount () == 0) + { + + // Remove it. + model.removeNodeFromParent (nNode); + + } + + } + + } + + public static void removeNodeFromTree (JTree tree, + Object n) + { + + DefaultTreeModel model = (DefaultTreeModel) tree.getModel (); + + DefaultMutableTreeNode root = (DefaultMutableTreeNode) model.getRoot (); + + TreePath tp = UIUtils.getTreePathForUserObject (root, + n); + + // It can happen but shouldn't. + if (tp == null) + { + + return; + + } + + DefaultMutableTreeNode nNode = (DefaultMutableTreeNode) tp.getLastPathComponent (); + + if (nNode != null) + { + + model.removeNodeFromParent (nNode); + + } + + } +/* + public static Set getReferencedObjects (String t, + Project p, + NamedObject ignore) + { + + if (t == null) + { + + return t; + + } + + Set ret = new HashSet (); + + Set objs = p.getAllNamedChildObjects (Asset.class); + + Set chaps = p.getAllNamedChildObjects (Chapter.class); + + if (chaps.size () > 0) + { + + objs.addAll (chaps); + + } + + if (objs.size () == 0) + { + + return ret; + + } + + if (ignore != null) + { + + objs.remove (ignore); + + } + + Map> items = new HashMap (); + + for (NamedObject o : objs) + { + + NamedObjectNameWrapper.addTo (o, + items); + + } + + // Get all the names. + Set names = items.keySet (); + + List namesL = new ArrayList (names); + + try + { + + JoSQLComparator jc = new JoSQLComparator ("SELECT * FROM java.lang.String ORDER BY toString.length DESC"); + + Collections.sort (namesL, + jc); + + } catch (Exception e) + { + + Environment.logError ("Unable to construct josql comparator", + e); + + } + + for (String name : namesL) + { + + int ind = 0; + int start = 0; + StringBuilder b = new StringBuilder (); + String tl = t.toLowerCase (); + + while (ind != -1) + { + + ind = tl.indexOf (name, + start); + + if (ind != -1) + { + + String tag = "[[_$@" + name.hashCode () + "@$_]]"; + + b.append (t.substring (start, + ind)); + b.append (tag); + + start = ind + name.length (); + + } else + { + + b.append (t.substring (start)); + + } + + } + + t = b.toString (); + + } + + for (String name : namesL) + { + + List nitems = items.get (name); + + NamedObjectNameWrapper nw = nitems.get (0); + + t = Utilities.replaceString (t, + "[[_$@" + name.hashCode () + "@$_]]", + "" + nw.name + ""); + + } + + + } + */ + public static String markupStringForAssets (String t, + Project p, + NamedObject ignore) + { + + if (t == null) + { + + return t; + + } + + Set objs = p.getAllNamedChildObjects (Asset.class); + + Set chaps = p.getAllNamedChildObjects (Chapter.class); + + if (chaps.size () > 0) + { + + objs.addAll (chaps); + + } + + if (objs.size () == 0) + { + + return t; + + } + + if (ignore != null) + { + + objs.remove (ignore); + + } + + Map> items = new HashMap (); + + for (NamedObject o : objs) + { + + NamedObjectNameWrapper.addTo (o, + items); + + } + + NavigableMap reps = new TreeMap (); + + TextIterator ti = new TextIterator (t); + + for (NamedObject n : objs) + { + + Set matches = null; + + for (String name : n.getAllNames ()) + { + + matches = ti.findAllTextIndexes (name, + null); + + // TODO: This needs to be on a language basis. + Set matches2 = ti.findAllTextIndexes (name + "'s", + null); + + matches.addAll (matches2); + + Iterator iter = matches.iterator (); + + while (iter.hasNext ()) + { + + Integer ind = iter.next (); + + // Now search back through the string to make sure + // we aren't actually part of a http or https string. + int httpInd = t.lastIndexOf ("http://", + ind); + int httpsInd = t.lastIndexOf ("https://", + ind); + + if ((httpInd > -1) + || + (httpsInd > -1) + ) + { + + // Check forward to ensure there is no white space. + String ss = t.substring (Math.max (httpInd, httpsInd), + ind); + + boolean hasWhitespace = false; + + char[] chars = ss.toCharArray (); + + for (int i = 0; i < chars.length; i++) + { + + if (Character.isWhitespace (chars[i])) + { + + hasWhitespace = true; + + break; + + } + + } + + if (!hasWhitespace) + { + + // This name is part of a http/https link so ignore. + continue; + + } + + } + + // Check the char at the index, if it's uppercase then we upper the word otherwise lower. + if (Character.isLowerCase (t.charAt (ind))) + { + + reps.put (ind, + new NamedObjectNameWrapper (name.toLowerCase (), + n)); + + } else { + + // Uppercase each of the words in the name. + reps.put (ind, + new NamedObjectNameWrapper (TextUtilities.capitalize (name), + n)); + + } + + } + + } + + } + + NavigableMap nreps = new TreeMap (); + + List mis = new ArrayList (reps.keySet ()); + + // Sort by location. + Collections.sort (mis); + + // Prune out the overlaps. + for (int i = 0; i < mis.size (); i++) + { + + Integer curr = mis.get (i); + + NamedObjectNameWrapper wrap = reps.get (curr); + + nreps.put (curr, + wrap); + + int ni = i + 1; + + if (ni < mis.size ()) + { + + Integer next = mis.get (ni); + + // Does the next match start before the end of the current match? + if (next.intValue () <= curr.intValue () + wrap.name.length ()) + { + + // Move to the next, when the loop goes to the next it will + // increment again moving past it. + i = ni; + + } + + } + + } + + reps = nreps; + + StringBuilder b = new StringBuilder (t); + + // We iterate backwards over the indexes so we don't have to choppy-choppy the string. + Iterator iter = reps.descendingKeySet ().iterator (); + + while (iter.hasNext ()) + { + + Integer ind = iter.next (); + + NamedObjectNameWrapper obj = reps.get (ind); +/* + b = b.replace (ind, + ind + obj.name.length (), + "" + obj.name + ""); + */ + + String w = obj.name; + + try + { + + w = URLEncoder.encode (obj.name, "utf-8"); + + } catch (Exception e) { + + // Ignore. + + } + + b = b.replace (ind, + ind + obj.name.length (), + String.format ("%s", + Constants.OBJECTNAME_PROTOCOL, + w, + obj.name)); + + } + + t = b.toString (); + + t = Utils.replaceString (t, + String.valueOf ('\n'), + "
    "); + + return t; + + } + + public static String getObjectALink (NamedObject d) + { + + return "" + d.getName () + ""; + + } + + public static Map parseState (String s) + { + + // Preserve the order, it "may" be important. + Map ret = new LinkedHashMap (); + + StringTokenizer t = new StringTokenizer (s, + String.valueOf ('\n')); + + while (t.hasMoreTokens ()) + { + + String tok = t.nextToken ().trim (); + + StringTokenizer tt = new StringTokenizer (tok, + "="); + + while (tt.hasMoreTokens ()) + { + + if (tt.countTokens () == 2) + { + + String name = tt.nextToken ().trim (); + String value = tt.nextToken ().trim (); + + ret.put (name, + value); + + } + + } + + } + + return ret; + + } + + public static String createState (Map values) + { + + StringBuilder b = new StringBuilder (); + + Iterator iter = values.keySet ().iterator (); + + while (iter.hasNext ()) + { + + String k = iter.next ().toString (); + String v = values.get (k).toString (); + + b.append (k); + b.append ("="); + b.append (v); + b.append ('\n'); + + } + + return b.toString (); + + } + + public static JButton createToolBarButton (String icon, + String tooltip, + String actionCommand, + ActionListener action) + { + + JButton bt = new JButton (Environment.getIcon (icon, + Constants.ICON_TOOLBAR)) + { + + @Override + public void setText (String t) + { + + super.setText (Environment.replaceObjectNames (t)); + + } + + }; + + UIUtils.setAsButton (bt); + bt.setToolTipText (Environment.replaceObjectNames (tooltip)); + bt.setActionCommand (actionCommand); + bt.setOpaque (false); + + if (action != null) + { + + bt.addActionListener (action); + + } + + return bt; + + } + + public static JScrollPane createTreeScroll (JTree tree) + { + + JScrollPane scroll = new JScrollPane (tree); + scroll.setBorder (new MatteBorder (3, + 3, + 3, + 3, + tree.getBackground ())); + scroll.setOpaque (false); + scroll.setOpaque (true); + + return scroll; + + } + + public static JTree createTree () + { + + JTree tree = new JTree (); + tree.setCellRenderer (new ProjectTreeCellRenderer (false)); + tree.setOpaque (true); + tree.setBorder (null); + tree.setRootVisible (false); + tree.setShowsRootHandles (true); + tree.setScrollsOnExpand (true); + tree.setRowHeight (0); + + tree.putClientProperty (com.jgoodies.looks.Options.TREE_LINE_STYLE_KEY, + com.jgoodies.looks.Options.TREE_LINE_STYLE_NONE_VALUE); + + tree.putClientProperty ("Tree.paintLines", + Boolean.FALSE); + + return tree; + + } + + public static void setTreeRootNode (JTree tree, + DefaultMutableTreeNode tn) + { + + java.util.List openPaths = new ArrayList (); + + Enumeration paths = tree.getExpandedDescendants (new TreePath (tree.getModel ().getRoot ())); + + if (paths != null) + { + + while (paths.hasMoreElements ()) + { + + openPaths.add (paths.nextElement ()); + + } + + } + + DefaultTreeModel dtm = (DefaultTreeModel) tree.getModel (); + + dtm.setRoot (tn); + + for (TreePath p : openPaths) + { + + tree.expandPath (UIUtils.getTreePathForUserObject (tn, + ((DefaultMutableTreeNode) p.getLastPathComponent ()).getUserObject ())); + + } + + } + + public static void setCenterOfScreenLocation (Window f) + { + + f.pack (); + + Dimension dim = Toolkit.getDefaultToolkit ().getScreenSize (); + + int w = f.getSize ().width; + int h = f.getSize ().height; + int x = (dim.width - w) / 2; + int y = (dim.height - h) / 2; + + // Move the window + f.setLocation (x, + y); + + } + + public static void addHyperLinkListener (final JEditorPane p, + final AbstractViewer viewer) + { + + p.addHyperlinkListener (new HyperlinkListener () + { + + @Override + public void hyperlinkUpdate (HyperlinkEvent ev) + { + + if (ev.getEventType () == HyperlinkEvent.EventType.ACTIVATED) + { + + URL url = ev.getURL (); + + UIUtils.openURL (viewer, + url); + + } + + } + + }); + + } + + public static Header createHeader (String title, + int titleType) + { + + return UIUtils.createHeader (title, + titleType, + (String) null, + null); + + } + + public static Header createHeader (String title, + int titleType, + String icon, + JComponent controls) + { + + int iconType = Constants.ICON_MENU; + + if (titleType == Constants.POPUP_WINDOW_TITLE) + { + + iconType = Constants.ICON_POPUP; + + } + + if (titleType == Constants.SUB_PANEL_TITLE) + { + + iconType = Constants.ICON_SUB_PANEL_MAIN; + + } + + if (titleType == Constants.PANEL_TITLE) + { + + iconType = Constants.ICON_PANEL_MAIN; + + + } + + if (titleType == Constants.FULL_SCREEN_TITLE) + { + + iconType = Constants.ICON_PANEL_MAIN; + + } + + ImageIcon ii = null; + + if (icon != null) + { + + ii = Environment.getIcon (icon, + iconType); + + } + + return UIUtils.createHeader (title, + titleType, + ii, + controls); + + } + + public static Header createHeader (String title, + int titleType, + Icon icon, + JComponent controls) + { + + int fontSize = 10; + Insets ins = null; + + if (titleType == Constants.POPUP_WINDOW_TITLE) + { + + fontSize = 16; + ins = null; //new Insets (3, 3, 3, 3); + + } + + if (titleType == Constants.SUB_PANEL_TITLE) + { + + fontSize = 14; + ins = new Insets (5, 5, 0, 0); + + } + + if (titleType == Constants.PANEL_TITLE) + { + + fontSize = 16; + ins = new Insets (5, 7, 5, 7); + + + } + + if (titleType == Constants.FULL_SCREEN_TITLE) + { + + fontSize = 18; + ins = new Insets (5, 10, 8, 5); + + + } + + Header h = new Header (Environment.replaceObjectNames (title), + icon, + controls); + + h.setAlignmentX (Component.LEFT_ALIGNMENT); + + h.setFont (h.getFont ().deriveFont ((float) UIUtils.scaleToScreenSize (fontSize)).deriveFont (Font.PLAIN)); + h.setTitleColor (UIUtils.getTitleColor ()); + h.setPadding (ins); + + return h; + + } + + public static JPanel createHelpBox (String helpText, + int iconType, + AbstractViewer pv) + { + + FormLayout fl = new FormLayout ("p, 3px, fill:90px:grow", + "top:p"); + + PanelBuilder pb = new PanelBuilder (fl); + + CellConstraints cc = new CellConstraints (); + + ImagePanel helpII = new ImagePanel (Environment.getIcon ("help", + iconType), + null); + helpII.setAlignmentX (Component.LEFT_ALIGNMENT); + + pb.add (helpII, + cc.xy (1, + 1)); + + JTextPane helpT = UIUtils.createHelpTextPane (helpText, + pv); + + JScrollPane hsp = new JScrollPane (helpT); + hsp.setOpaque (false); + hsp.setBorder (null); + hsp.getViewport ().setOpaque (false); + hsp.setAlignmentX (Component.LEFT_ALIGNMENT); + + pb.add (hsp, + cc.xy (3, + 1)); + + JPanel helpBox = pb.getPanel (); + helpBox.setOpaque (false); + helpBox.setVisible (false); + helpBox.setBorder (new EmptyBorder (0, + 0, + 5, + 0)); + helpBox.setAlignmentX (Component.LEFT_ALIGNMENT); + + return helpBox; + + } + + public static String formatTextForHelpPane (String text) + { + + if (text != null) + { + + StringBuilder buf = new StringBuilder (); + + //text = Environment.replaceObjectNames (text); + + text = Utils.replaceString (text, + "{QW}", + Constants.QUOLL_WRITER_NAME); + + text = Utils.replaceString (text, + String.valueOf ('\n'), + "
    "); + + text = UIUtils.markupLinks (text); + + int ind = text.indexOf ("["); + + while (ind > -1) + { + + int end = text.indexOf ("]", + ind + 1); + + if (end < 0) + { + + ind = text.indexOf ("[", + ind + 1); + + continue; + + } + + if (end > ind + 1) + { + + String v = text.substring (ind + 1, + end); + + StringTokenizer st = new StringTokenizer (v, + ",;"); + + String icon = st.nextToken ().trim ().toLowerCase (); + String action = null; + + if (st.hasMoreTokens ()) + { + + action = st.nextToken ().trim ().toLowerCase (); + + } + + v = ""; + + if (action != null) + { + + v = "" + v + ""; + + } + + // Split up the value. + text = text.substring (0, + ind) + v + text.substring (end + 1); + + ind = text.indexOf ("[", + ind + v.length ()); + + + } + + } + + text = UIUtils.getWithHTMLStyleSheet (new JTextField ("abcdABCD"), + text); + + } + + return text; + + } + + // TODO: Make this work. + public static JTextPane createHelpTextPane (StringWithMarkup text, + AbstractViewer viewer) + { + + return UIUtils.createHelpTextPane ((text != null ? text.getMarkedUpText () : null), + viewer); + + } + + public static JTextPane createHelpTextPane (AbstractViewer viewer) + { + + return UIUtils.createHelpTextPane ((String) null, + viewer); + + } + + public static JTextPane createHelpTextPane (String text, + AbstractViewer viewer) + { + + HTMLEditorKit kit = new HTMLEditorKit (); + HTMLDocument doc = (HTMLDocument) kit.createDefaultDocument (); + + final JTextPane desc = new JTextPane (doc) + { + + @Override + public void setText (String t) + { + + super.setText (UIUtils.formatTextForHelpPane (t)); + + } + + }; + + desc.setEditorKit (kit); + desc.setEditable (false); + desc.setOpaque (false); + desc.setAlignmentX (JComponent.LEFT_ALIGNMENT); + + desc.setSize (new Dimension (500, + Short.MAX_VALUE)); + + desc.setText (text); + + UIUtils.addHyperLinkListener (desc, + viewer); + + return desc; + + } + + public static String getWithHTMLStyleSheet (JTextComponent desc, + String text) + { + + return UIUtils.getWithHTMLStyleSheet (desc, + text, + null, + null); + + } + + public static String getWithHTMLStyleSheet (JTextComponent desc, + String text, + String linkColor, + String textColor) + { + + if (text == null) + { + + text = ""; + + } + + text = Utils.replaceString (text, + String.valueOf ('\n'), + "
    "); + + StringBuilder t = new StringBuilder (); + t.append (""); + t.append (UIUtils.getHTMLStyleSheet (desc, + linkColor, + textColor)); + t.append (""); + t.append (UIUtils.markupLinks (text)); + t.append (""); + + return t.toString (); + + } + + public static void openURL (Component parent, + String url) + { + + URL u = null; + + try + { + + u = new URL (url); + + } catch (Exception e) + { + + Environment.logError ("Unable to browse to: " + + url, + e); + + UIUtils.showErrorMessage (parent, + String.format (getUIString (general,unabletoopenwebpage), + url)); + //"Unable to open web page: " + url); + + return; + + } + + UIUtils.openURL (parent, + u); + + } + + public static AbstractViewer getViewer (Component parent) + { + + if (parent == null) + { + + return null; + + } + + if (parent instanceof AbstractViewer) + { + + return (AbstractViewer) parent; + + } + + if (parent instanceof PopupWindow) + { + + return ((PopupWindow) parent).getViewer (); + + } + + if (parent instanceof QuollPanel) + { + + return ((QuollPanel) parent).getViewer (); + + } + + return UIUtils.getViewer (parent.getParent ()); + + } + + public static AbstractProjectViewer getProjectViewer (Component parent) + { + + AbstractViewer v = UIUtils.getViewer (parent); + + if ((v != null) + && + (v instanceof AbstractProjectViewer) + ) + { + + return (AbstractProjectViewer) v; + + } + + return null; + + } + +/* + public static AbstractViewer getViewer (Component parent) + { + + if (parent == null) + { + + return null; + + } + + if (parent instanceof AbstractViewer) + { + + return (AbstractViewer) parent; + + } + + return UIUtils.getViewer (parent.getParent ()); + + } +*/ + public static void showFile (Component parent, + File f) + { + + try + { + + Desktop.getDesktop ().open (f); + + } catch (Exception e) + { + + Environment.logError ("Unable to open: " + + f, + e); + + UIUtils.showErrorMessage (parent, + String.format (getUIString (general,unabletoopenfile), + f.getPath ())); + //"Unable to open: " + f); + + return; + + } + + } + + public static void openURL (Component parent, + URL url) + { + + if (url == null) + { + + return; + + } + + if (url.getProtocol ().equals (Constants.QUOLLWRITER_PROTOCOL)) + { + + String u = Environment.getQuollWriterWebsite (); + + String p = url.getPath (); + + if ((!p.endsWith (".html")) + && + // Only add if the url isn't of the form [name].html?parms + (p.indexOf (".html?") < 1) + && + // Only add if the url isn't of the form [name].html#id + (p.indexOf (".html#") < 1) + ) + { + + p += ".html"; + + } + + u = u + "/" + p; + + if (url.getQuery () != null) + { + + u += "?" + url.getQuery (); + + } + + if (url.getRef () != null) + { + + u += "#" + url.getRef (); + + } + + try + { + + url = new URL (u); + + } catch (Exception e) + { + + Environment.logError ("Unable to open url: " + + u, + e); + + return; + + } + + } + + if (url.getProtocol ().equals (Constants.HELP_PROTOCOL)) + { + + // Prefix it with the website. + String u = Environment.getQuollWriterWebsite (); + + String p = url.getPath (); + + if (p.indexOf (".html") < 0) + { + + p += ".html"; + + } + + u = u + "/user-guide/" + url.getHost () + p; + + if (url.getRef () != null) + { + + u += "#" + url.getRef (); + + } + + try + { + + url = new URL (u); + + } catch (Exception e) + { + + Environment.logError ("Unable to open url: " + + u, + e); + + return; + + } + + if (parent != null) + { + + AbstractViewer pv = UIUtils.getViewer (parent); + + if (pv != null) + { + + Environment.fireUserProjectEvent (new ProjectEvent (pv, + ProjectEvent.Type.help, + ProjectEvent.Action.show)); + + } + + } + + } + + if (url.getProtocol ().equals (Constants.OPENPROJECT_PROTOCOL)) + { + + String projId = url.getPath (); + + Project proj = null; + + try + { + + Environment.openProject (projId, + null, + null); + + } catch (Exception e) { + + Environment.logError ("Unable to get project for id: " + projId, + e); + + } + + return; + + } + + if (url.getProtocol ().equals (Constants.OPENEDITORMESSAGE_PROTOCOL)) + { + + int key = 0; + + try + { + + key = Integer.parseInt (url.getPath ()); + + } catch (Exception e) { + + // Ignore? + + } + + // Get the message. + EditorMessage mess = null; + + try + { + + mess = EditorsEnvironment.getMessageByKey (key); + + } catch (Exception e) { + + Environment.logError ("Unable to get message for key: " + key, + e); + + } + + if (mess != null) + { + + // Need to work out what to do. + //EditorsEnvironment.openEditorMessage (mess); + + } + + return; + + } + + if (url.getProtocol ().equals (Constants.OBJECTREF_PROTOCOL)) + { + + if (parent != null) + { + + AbstractProjectViewer pv = UIUtils.getProjectViewer (parent); + + if (pv != null) + { + + pv.viewObject (pv.getProject ().getObjectForReference (ObjectReference.parseObjectReference (url.getHost ()))); + + return; + + } + + } + + } + + + if (url.getProtocol ().equals (Constants.ACTION_PROTOCOL)) + { + + String action = url.getPath (); + + if (parent != null) + { +/* +TODO + AbstractViewer pv = Environment.getFocusedViewer (); + + if (pv != null) + { + + pv.handleHTMLPanelAction (action); + + return; + + } +*/ + } + + } + + if (url.getProtocol ().equals ("mailto")) + { + + return; + + } + + try + { + + Desktop.getDesktop ().browse (url.toURI ()); + + } catch (Exception e) + { + + Environment.logError ("Unable to browse to: " + + url, + e); + + UIUtils.showErrorMessage (parent, + String.format (getUIString (general,unabletoopenwebpage), + url)); + //"Unable to open web page: " + url); + + } + + } + + public static JTextPane createTextViewPane (final StringWithMarkup description, + final AbstractProjectViewer pv) + { + + // TODO: Markup to html? + return UIUtils.createTextViewPane ((description != null ? description.getMarkedUpText () : null), + pv); + + } + + public static JTextPane createTextViewPane (final String description, + final AbstractProjectViewer pv) + { + + HTMLEditorKit kit = new HTMLEditorKit (); + HTMLDocument doc = (HTMLDocument) kit.createDefaultDocument (); + + final JTextPane desc = new JTextPane (doc) + { + + @Override + public void setText (String t) + { + + if (t == null) + { + + t = ""; + + } + + super.setText (UIUtils.getWithHTMLStyleSheet (this, + UIUtils.markupStringForAssets (t, + pv.getProject (), + null))); + + } + + }; + + desc.setEditorKit (kit); + desc.setEditable (false); + desc.setOpaque (false); + + desc.setSize (new Dimension (500, Short.MAX_VALUE)); + desc.addHyperlinkListener (new HyperlinkAdapter () + { + + public void hyperlinkUpdate (HyperlinkEvent ev) + { + + if (ev.getEventType () == HyperlinkEvent.EventType.ACTIVATED) + { + + URL url = ev.getURL (); + + if (url.getProtocol ().equals (Constants.OBJECTREF_PROTOCOL)) + { + + pv.viewObject (pv.getProject ().getObjectForReference (ObjectReference.parseObjectReference (url.getHost ()))); + + return; + + } + + if (url.getProtocol ().equals (Constants.OBJECTNAME_PROTOCOL)) + { + + String n = url.getHost (); + + try + { + + n = URLDecoder.decode (url.getHost (), "utf-8"); + + } catch (Exception e) { + + // Ignore. + + } + + Set objs = pv.getProject ().getAllAssetsByName (n, + null); + + if ((objs == null) + || + (objs.size () == 0) + ) + { + + return; + + } + + if (objs.size () == 1) + { + + pv.viewObject (objs.iterator ().next ()); + + return; + + } else { + + try + { + + Point point = desc.modelToView (ev.getSourceElement ().getStartOffset ()).getLocation (); + + point = SwingUtilities.convertPoint (desc, + point, + pv); + + UIUtils.showObjectSelectPopup (objs, + pv, + getUIString (selectitem,popup,title), + //"Select an item to view", + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + pv.viewObject (pv.getProject ().getObjectForReference (ObjectReference.parseObjectReference (ev.getActionCommand ()))); + + } + + }, + true, + point); + + } catch (Exception e) { + + Environment.logError ("Unable to show popup", + e); + + pv.viewObject (objs.iterator ().next ()); + + return; + + } + + } + + } + + if (url.getProtocol ().equals ("mailto")) + { + + return; + + } + + UIUtils.openURL (pv, + url); + + } + + } + + }); + + desc.setText (description); + + return desc; + + } + + public static JEditorPane createObjectDescriptionViewPane (final StringWithMarkup description, + final NamedObject n, + final AbstractProjectViewer pv, + final ProjectObjectQuollPanel qp) + { + + // TODO: Markup to html? + return UIUtils.createObjectDescriptionViewPane ((description != null ? description.getMarkedUpText () : null), + n, + pv, + qp); + + } + + public static JFXPanel createJFXObjectDescriptionViewPane (final String description, + final NamedObject n, + final AbstractProjectViewer pv, + final ProjectObjectQuollPanel qp) + { + + final JFXPanel jfxp = new JFXPanel (); + + Platform.runLater (new Runnable () + { + + @Override + public void run () + { + + BorderPane bp = new BorderPane (); + WebView web = new WebView (); + + web.getEngine ().loadContent (UIUtils.getWithHTMLStyleSheet (null, + UIUtils.markupStringForAssets (description, + pv.getProject (), + n))); + + bp.setCenter (web); + + javafx.scene.Scene s = new javafx.scene.Scene (bp); + + jfxp.setScene (s); + + } + + }); + + return jfxp; + + } + + public static JEditorPane createObjectDescriptionViewPane (final String description, + final NamedObject n, + final AbstractProjectViewer pv, + final ProjectObjectQuollPanel qp) + { + + HTMLEditorKit kit = new HTMLEditorKit (); + HTMLDocument doc = (HTMLDocument) kit.createDefaultDocument (); + + //final JTextPane desc = new JTextPane (doc) + final JEditorPane desc = new JEditorPane () + { + + @Override + public void setText (String t) + { + + super.setText (UIUtils.getWithHTMLStyleSheet (this, + UIUtils.markupStringForAssets (t, + pv.getProject (), + n))); + + } + + }; + + desc.setDocument (doc); + desc.setEditorKit (kit); + desc.setEditable (false); + desc.setOpaque (false); + + /* + desc.setMaximumSize (new Dimension (Short.MAX_VALUE, + Short.MAX_VALUE)); +*/ + desc.setSize (new Dimension (250, Short.MAX_VALUE)); + desc.addHyperlinkListener (new HyperlinkListener () + { + + @Override + public void hyperlinkUpdate (HyperlinkEvent ev) + { + + if (ev.getEventType () == HyperlinkEvent.EventType.ACTIVATED) + { + + URL url = ev.getURL (); + + if (url.getProtocol ().equals (Constants.OBJECTREF_PROTOCOL)) + { + + pv.viewObject (pv.getProject ().getObjectForReference (ObjectReference.parseObjectReference (url.getHost ()))); + + return; + + } + + if (url.getProtocol ().equals (Constants.OBJECTNAME_PROTOCOL)) + { + + String un = url.getHost (); + + try + { + + un = URLDecoder.decode (un, "utf-8"); + + } catch (Exception e) { + + // Ignore. + + } + + Set objs = pv.getProject ().getAllNamedObjectsByName (un); + + if ((objs == null) + || + (objs.size () == 0) + ) + { + + return; + + } + + if (objs.size () == 1) + { + + pv.viewObject (objs.iterator ().next ()); + + return; + + } else { + + try + { + + Point point = desc.modelToView (ev.getSourceElement ().getStartOffset ()).getLocation (); + + point = SwingUtilities.convertPoint (desc, + point, + pv); + + UIUtils.showObjectSelectPopup (objs, + pv, + getUIString (selectitem,popup,title), + //"Select an item to view", + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + pv.viewObject (pv.getProject ().getObjectForReference (ObjectReference.parseObjectReference (ev.getActionCommand ()))); + + } + + }, + true, + point); + + } catch (Exception e) { + + Environment.logError ("Unable to show popup", + e); + + pv.viewObject (objs.iterator ().next ()); + + return; + + } + + } + + return; + + } + + if (url.getProtocol ().equals ("mailto")) + { + + return; + + } + + UIUtils.openURL (pv, + url); + + } + + } + + }); + + if (qp != null) + { + + PropertyChangedAdapter pca = new PropertyChangedAdapter () + { + + public void propertyChanged (PropertyChangedEvent ev) + { + + if (ev.getChangeType ().equals (NamedObject.DESCRIPTION)) + { + + desc.setText (description); + + } + + } + + }; + + qp.addObjectPropertyChangedListener (pca); + + pca.propertyChanged (new PropertyChangedEvent (qp, + NamedObject.DESCRIPTION, + null, + null)); + + } else { + + desc.setText (description); + + } + + return desc; + + } + + public static String colorToHex (Color c) + { + + return "#" + Integer.toHexString (c.getRGB ()).substring (2); + + } + + public static String getHTMLStyleSheet (JTextComponent desc, + String textColor, + String linkColor) + { + + return UIUtils.getHTMLStyleSheet (desc, + textColor, + linkColor, + -1); + + } + + public static String getHTMLStyleSheet (JTextComponent desc, + String textColor, + String linkColor, + int textSize) + { + + StringBuilder t = new StringBuilder (); + + Font f = null; + + if (desc != null) + { + + f = desc.getFont (); + + } else { + + f = new JLabel ().getFont (); + + } + + if (linkColor == null) + { + + linkColor = Constants.HTML_LINK_COLOR; + + } + + if (!linkColor.startsWith ("#")) + { + + linkColor = "#" + linkColor; + + } + + if (textColor == null) + { + + textColor = "#000000"; + + } + + if (!textColor.startsWith ("#")) + { + + textColor = "#" + textColor; + + } + + int size = textSize; + + if (size < 1) + { + + size = (int) f.getSize (); + + } + + t.append (""); + + return t.toString (); + + } + + public static String getHTMLStyleSheet (JTextComponent desc) + { + + return UIUtils.getHTMLStyleSheet (desc, + "#000000", + Constants.HTML_LINK_COLOR); + + } + + public static AbstractAction createAddAssetActionListener (final UserConfigurableObjectType forAssetType, + final ProjectViewer viewer, + final String name, + final String desc) + { + + return new AbstractAction () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + Asset as = null; + + try + { + + as = Asset.createAsset (forAssetType); + + } catch (Exception e) { + + Environment.logError ("Unable to create new asset for object type: " + + forAssetType, + e); + + UIUtils.showErrorMessage (viewer, + String.format (getUIString (assets,add,actionerror), + forAssetType.getObjectTypeName ())); + //"Unable to create new asset type."); + + return; + + } + + if (as == null) + { + + Environment.logError ("Unable to create new asset for object type: " + + forAssetType); + + UIUtils.showErrorMessage (viewer, + String.format (getUIString (assets,add,actionerror), + forAssetType.getObjectTypeName ())); + //"Unable to create new asset type."); + + return; + + } + + if (name != null) + { + + as.setName (name); + + } + + if (desc != null) + { + + as.setDescription (new StringWithMarkup (desc)); + + } + + String addAsset = UserProperties.get (Constants.ADD_ASSETS_PROPERTY_NAME); + + // Should we use a popup? + if (((addAsset.equals (Constants.ADD_ASSETS_TRY_POPUP)) + && + (forAssetType.getNonCoreFieldCount () == 0) + ) + || + (addAsset.equals (Constants.ADD_ASSETS_POPUP)) + ) + { + + AssetActionHandler aah = new AssetActionHandler (as, + viewer); + + aah.setPopupOver (viewer); + + aah.actionPerformed (ev); + + return; + + } + + viewer.showAddAsset (as, + null); + + } + + }; + + } + + public static void addNewAssetItemsToPopupMenu (final Container m, + final Component showPopupAt, + final ProjectViewer pv, + final String name, + final String desc) + { + + String pref = getUIString (general,shortcut); + //"Shortcut: "; + + Set types = Environment.getAssetUserConfigurableObjectTypes (true); + + for (UserConfigurableObjectType type : types) + { + + JMenuItem mi = new JMenuItem (type.getObjectTypeName (), + 0); // TODO type.getIcon16x16 ()); + + m.add (mi); + + KeyStroke k = type.getCreateShortcutKeyStroke (); + + if (k != null) + { + + mi.setMnemonic (k.getKeyChar ()); + mi.setToolTipText (pref + Utils.keyStrokeToString (k)); + + } + + mi.addActionListener (UIUtils.createAddAssetActionListener (type, + pv, + name, + desc)); + + } + + } + + public static void addNewAssetItemsAsToolbarToPopupMenu (JPopupMenu m, + Component showPopupAt, + ProjectViewer pv, + String name, + String desc) + { + + List buts = new ArrayList (); + + Set types = Environment.getAssetUserConfigurableObjectTypes (true); + + for (UserConfigurableObjectType type : types) + { + + JButton but = UIUtils.createButton (null, // TODO type.getIcon16x16 (), + String.format (getUIString (assets,add,button,tooltip), + //"Click to add a new %s", + type.getObjectTypeName ()), + null); + + buts.add (but); + + final UserConfigurableObjectType _type = type; + + but.addActionListener (new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + Asset a = null; + + try + { + + a = Asset.createAsset (_type); + + } catch (Exception e) { + + Environment.logError ("Unable to create new asset for object type: " + + _type, + e); + + UIUtils.showErrorMessage (pv, + String.format (getUIString (assets,add,actionerror), + _type.getObjectTypeName ())); + //"Unable to create new asset type."); + + return; + + } + + if (a == null) + { + + Environment.logError ("Unable to create new asset for object type: " + + _type); + + UIUtils.showErrorMessage (pv, + String.format (getUIString (assets,add,actionerror), + _type.getObjectTypeName ())); + //"Unable to create new asset type."); + + return; + + } + + if (name != null) + { + + a.setName (name); + + } + + if (desc != null) + { + + a.setDescription (new StringWithMarkup (desc)); + + } + + AssetActionHandler aah = new AssetActionHandler (a, + pv); + + if (showPopupAt instanceof PopupsSupported) + { + + aah.setPopupOver (pv); + aah.setShowPopupAt (null, + "below"); + + } else + { + + aah.setShowPopupAt (showPopupAt, + "above"); + + } + + aah.actionPerformed (ev); + + } + + }); + + } + + m.add (UIUtils.createPopupMenuButtonBar (null, + m, + buts)); + + } + + public static Color getBorderHighlightColor () + { + + return UIUtils.getColor ("#275C92"); + + } + + public static Color getHintTextColor () + { + + return UIUtils.getColor ("#aaaaaa"); + + } + + public static Color hexToColor (String hexCode) + { + + return UIUtils.getColor (hexCode); + + } + + public static Color getColor (String hexCode) + { + + if (hexCode.startsWith ("#")) + { + + hexCode = hexCode.substring (1); + + } + + hexCode = hexCode.toUpperCase (); + + return new Color (Integer.parseInt (hexCode.substring (0, + 2), + 16), + Integer.parseInt (hexCode.substring (2, + 4), + 16), + Integer.parseInt (hexCode.substring (4), + 16)); + } + + public static String getFrameTitle (String name) + { + + return Environment.replaceObjectNames (name) + Environment.getWindowNameSuffix (); + + } + + public static void setFrameTitle (Frame f, + String name) + { + + f.setTitle (UIUtils.getFrameTitle (name)); + + } + + public static void setFrameTitle (Dialog f, + String name) + { + + f.setTitle (UIUtils.getFrameTitle (name)); + + } + + public static JButton createHelpPageButton (final String helpPage, + final int iconType, + final String helpText) + { + + final JButton helpBut = new JButton (Environment.getIcon ("help", + iconType)); + helpBut.setToolTipText ((helpText != null ? helpText : getUIString (help,button,tooltip))); + //"Click to view the help")); + helpBut.setOpaque (false); + UIUtils.setAsButton (helpBut); + + helpBut.addActionListener (new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + UIUtils.openURL (helpBut, + "help://" + helpPage); + + } + + }); + + return helpBut; + + } + + public static JLabel createWebsiteLabel (final String website, + final String display, + final boolean useLabelText) + { + + final JLabel web = new JLabel (String.format ("%s", + Environment.replaceObjectNames (((display == null) ? website : display)))) + { + + @Override + public void setText (String t) + { + + if (!this.getText ().equals ("")) + { + + throw new IllegalStateException ("Once set the website label text cannot be modified."); + + } + + super.setText (t); + + } + + }; + + // web.setEditable (false); + web.setOpaque (false); + web.setBorder (null); + web.setForeground (new Color (112, + 149, + 226)); + UIUtils.setAsButton (web); + + web.addMouseListener (new MouseEventHandler () + { + + @Override + public void mouseEntered (MouseEvent ev) + { + + Map attrs = new HashMap (); + attrs.put (TextAttribute.UNDERLINE, + TextAttribute.UNDERLINE_LOW_ONE_PIXEL); + + web.setFont (web.getFont ().deriveFont (attrs)); + + } + + @Override + public void mouseExited (MouseEvent ev) + { + + Map attrs = new HashMap (); + attrs.put (TextAttribute.UNDERLINE, + null); + + web.setFont (web.getFont ().deriveFont (attrs)); + + } + + @Override + public void handlePress (MouseEvent ev) + { + + String w = website; + + if (useLabelText) + { + + w = web.getText (); + + } + + if ((w == null) || + (w.trim ().equals (""))) + { + + return; + + } + + if ((!w.toLowerCase ().startsWith ("http://")) && + (!w.toLowerCase ().startsWith ("https://"))) + { + + w = "http://" + w; + + } + + try + { + + UIUtils.openURL (web, + w); + + } catch (Exception e) + { + + Environment.logError ("Unable to visit website: " + + w, + e); + + } + + } + + }); + + return web; + + } + + public static JLabel createClickableLabel (String title, + Icon icon) + { + + String ns = null; + + return UIUtils.createClickableLabel (title, + icon, + ns); + + } + + public static JLabel createClickableLabel (final String title, + final Icon icon, + final String gotoURLOnClick) + { + + return UIUtils.createClickableLabel (title, + icon, + new ActionListener () + { + + public void actionPerformed (ActionEvent ev) + { + + if (gotoURLOnClick != null) + { + + UIUtils.openURL (null, + gotoURLOnClick); + + } + + } + + }); + + } + + public static void makeClickable (final JLabel l, + final ActionListener onClick) + { + + l.addMouseListener (new MouseEventHandler () + { + + @Override + public void handlePress (MouseEvent ev) + { + + if (onClick != null) + { + + try + { + + onClick.actionPerformed (new ActionEvent (l, 1, "clicked")); + + } catch (Exception e) { + + Environment.logError ("Unable to perform action", + e); + + } + + } + + } + + }); + + l.setCursor (Cursor.getPredefinedCursor (Cursor.HAND_CURSOR)); + + } + + public static JLabel createClickableLabel (final String title, + final Icon icon, + final ActionListener onClick) + { + + final JLabel l = new JLabel (null, + icon, + SwingConstants.LEFT) + { + + @Override + public void setText (String t) + { + + if (t == null) + { + + super.setText (null); + + return; + + } + + super.setText (String.format ("%s", + Environment.replaceObjectNames (t))); + + } + + @Override + public void setToolTipText (String t) + { + + if (t == null) + { + + super.setToolTipText (null); + + return; + + } + + super.setToolTipText (String.format ("%s", + Environment.replaceObjectNames (t))); + + } + + }; + + l.setText (title); + l.setForeground (UIUtils.getColor (Constants.HTML_LINK_COLOR)); + l.setCursor (Cursor.getPredefinedCursor (Cursor.HAND_CURSOR)); + l.setVerticalAlignment (SwingConstants.TOP); + l.setVerticalTextPosition (SwingConstants.TOP); + UIUtils.makeClickable (l, + onClick); + + return l; + + } + + public static JLabel createLabel (final String title, + final Icon icon, + final ActionListener onClick) + { + + final JLabel l = new JLabel (null, + icon, + SwingConstants.LEFT) + { + + @Override + public void setText (String t) + { + + if (t == null) + { + + super.setText (null); + + return; + + } + + super.setText (String.format ("%s", + t)); + + } + + @Override + public void setToolTipText (String t) + { + + if (t == null) + { + + super.setToolTipText (null); + + return; + + } + + super.setToolTipText (t); + + } + + }; + + l.setText (title); + + if (onClick != null) + { + + l.setCursor (Cursor.getPredefinedCursor (Cursor.HAND_CURSOR)); + UIUtils.makeClickable (l, + onClick); + + } + + l.setVerticalAlignment (SwingConstants.TOP); + l.setVerticalTextPosition (SwingConstants.TOP); + + return l; + + } + + public static int getA4PageCountForChapter (Chapter c, + String text) + { + + if ((text == null) + || + (text.trim ().length () == 0) + ) + { + + return 0; + + } + + // Create a new editor. + QTextEditor ed = UIUtils.wordCountPerPageEditor; +/* + QTextEditor ed = new QTextEditor (null, + false); + */ + ed.setSectionBreak (Constants.SECTION_BREAK); + + ed.setLineSpacing (c.getPropertyAsFloat (Constants.EDITOR_LINE_SPACING_PROPERTY_NAME)); + ed.setFontSize ((int) (UIUtils.getEditorFontSize (c.getPropertyAsInt (Constants.EDITOR_FONT_SIZE_PROPERTY_NAME)))); + ed.setFontFamily (c.getProperty (Constants.EDITOR_FONT_PROPERTY_NAME)); + ed.setAlignment (c.getProperty (Constants.EDITOR_ALIGNMENT_PROPERTY_NAME)); + + ed.setTextWithMarkup (new StringWithMarkup (text)); + + int ppi = java.awt.Toolkit.getDefaultToolkit ().getScreenResolution (); + + // A4 - 17cm wide, 25.7cm high. + // 6.7" wide, 10.12" high + + float pageHeight = 10.12f; + float pageWidth = 6.7f; + + ed.setSize (new Dimension ((int) (pageWidth * ppi), + Integer.MAX_VALUE)); + + ed.setSize (new Dimension ((int) (pageWidth * ppi), + ed.getPreferredSize ().height)); + + // Get the height, divide by the page size. + int a4PageCount = (int) (ed.getHeight () / (pageHeight * ppi)); + + if (ed.getHeight () > (pageHeight * ppi * a4PageCount)) + { + + a4PageCount++; + + } + + /* + *standard pages count + + ed.setSize (new Dimension (4 * ppi, + ed.getPreferredSize ().height)); + + int standardPageCount = ed.getHeight () / (4 * ppi); + + if (ed.getHeight () > (6.5f * ppi * standardPageCount)) + { + + standardPageCount++; + + } + */ + + return a4PageCount; + + } + + public static JScrollPane createScrollPane (JComponent c, + boolean addTopBorderOnScroll) + { + + final JScrollPane sp = new JScrollPane (c); + sp.setOpaque (true); + sp.getViewport ().setBackground (UIUtils.getComponentColor ()); + sp.setBackground (UIUtils.getComponentColor ()); + sp.setAlignmentX (Component.LEFT_ALIGNMENT); + sp.getVerticalScrollBar ().setUnitIncrement (DEFAULT_SCROLL_BY_AMOUNT); + + // Ease of use thing since you want all tables to scroll on rows. + if (c instanceof JTable) + { + + sp.getVerticalScrollBar ().setUnitIncrement (((JTable) c).getRowHeight ()); + sp.getVerticalScrollBar ().setBlockIncrement (1); + + } + + if (addTopBorderOnScroll) + { + + final Border defBorder = UIUtils.createPadding (1, 0, 0, 0); + + final Border scrollBorder = new MatteBorder (1, 0, 0, 0, + UIUtils.getInnerBorderColor ()); + + sp.setBorder (defBorder); + + sp.getVerticalScrollBar ().addAdjustmentListener (new AdjustmentListener () + { + + public void adjustmentValueChanged (AdjustmentEvent ev) + { + + if (sp.getVerticalScrollBar ().getValue () > 0) + { + + sp.setBorder (scrollBorder); + + } else { + + sp.setBorder (defBorder); + + } + + } + + }); + + } else { + + sp.setBorder (UIUtils.createLineBorder ()); + + } + + return sp; + + } + + public static JScrollPane createScrollPane (JComponent c) + { + + return UIUtils.createScrollPane (c, + false); + + } + + public static JScrollPane createScrollPane (final JTree c) + { + + return UIUtils.createScrollPane (c, + -1); + + } + + public static JScrollPane createScrollPane (final JTree c, + final int maxHeight) + { + + JScrollPane sp = new JScrollPane (c) + { + + public Dimension getPreferredSize () + { + + Dimension d = c.getPreferredSize (); + + if (maxHeight > 0) + { + + if (d.height > maxHeight) + { + + d.height = maxHeight; + + } + + } + + return d; + + } + + }; + + //JScrollPane sp = new JScrollPane (c); + sp.setOpaque (true); + sp.getViewport ().setBackground (UIUtils.getComponentColor ()); + sp.setBackground (UIUtils.getComponentColor ()); + sp.setBorder (UIUtils.createLineBorder ()); + sp.setAlignmentX (Component.LEFT_ALIGNMENT); + sp.getVerticalScrollBar ().setUnitIncrement (DEFAULT_SCROLL_BY_AMOUNT); + + return sp; + + } + + public static JScrollPane createScrollPane (JTextComponent t) + { + + JScrollPane sp = new JScrollPane (t); + sp.setOpaque (false); + + sp.setBorder (new JScrollPane ().getBorder ()); + + t.setMargin (new Insets (3, + 3, + 3, + 3)); + sp.setAlignmentX (Component.LEFT_ALIGNMENT); + + sp.getVerticalScrollBar ().setUnitIncrement (DEFAULT_SCROLL_BY_AMOUNT); + + return sp; + + } + + public static JSplitPane createSplitPane (int orientation) + { + + JSplitPane sp = new JSplitPane (orientation, + false); + sp.setDividerSize (4);//UIUtils.getSplitPaneDividerSize () + 4); + + sp.setUI (new BasicSplitPaneUI () + { + + public BasicSplitPaneDivider createDefaultDivider () + { + + // Probably going to hell for this... + final AtomicBoolean highlight = new AtomicBoolean (false); + + final BasicSplitPaneDivider div = new BasicSplitPaneDivider (this) + { + + @Override + public void paint (Graphics g) + { + + if (highlight.get ()) + { + + g.setColor (UIUtils.getBorderColor ()); + + } else { + + g.setColor(new Color (0, 0, 0, 0)); + + } + + g.fillRect(0, 0, getSize().width, getSize().height); + super.paint (g); + + } + + }; + + div.addMouseListener (new MouseEventHandler () + { + + @Override + public void mouseEntered (MouseEvent ev) + { + + if (UserProperties.getAsBoolean (Constants.HIGHLIGHT_SPLITPANE_DIVIDERS_PROPERTY_NAME)) + { + + highlight.set (true); + div.validate (); + div.repaint (); + + } + + } + + @Override + public void mouseExited (MouseEvent ev) + { + + highlight.set (false); + div.validate (); + div.repaint (); + + } + + @Override + public void mouseReleased (MouseEvent ev) + { + + highlight.set (false); + div.validate (); + div.repaint (); + + } + + }); + + div.addMouseMotionListener (new MouseEventHandler () + { + + @Override + public void mouseDragged (MouseEvent ev) + { + + if (UserProperties.getAsBoolean (Constants.HIGHLIGHT_SPLITPANE_DIVIDERS_PROPERTY_NAME)) + { + + highlight.set (true); + div.validate (); + div.repaint (); + + } + + } + + }); + + return div; + + } + + }); + + sp.setBorder (null); + sp.setOpaque (false); + sp.setContinuousLayout (true); + + return sp; + + } + + public static JTextField createTextField () + { + + JTextField f = new JTextField (); + f.setAlignmentX (JComponent.LEFT_ALIGNMENT); + f.setBorder (new JScrollPane ().getBorder ()); + f.setMargin (new Insets (3, + 3, + 3, + 3)); + + return f; + + } + + public static JPasswordField createPasswordField () + { + + JPasswordField f = new JPasswordField (); + f.setAlignmentX (JComponent.LEFT_ALIGNMENT); + f.setBorder (new JScrollPane ().getBorder ()); + f.setMargin (new Insets (3, + 3, + 3, + 3)); + + return f; + + } + + public static JComponent createOpaqueGlue (int dir) + { + + JComponent c = null; + + if (dir == BoxLayout.Y_AXIS) + { + + c = (JComponent) Box.createVerticalGlue (); + + } else { + + c = (JComponent) Box.createHorizontalGlue (); + + } + + c.setOpaque (true); + c.setBackground (UIUtils.getComponentColor ()); + + return c; + + } + + /** + * Create a text area with the specified placeholder for the number of rows and max chars. The + * dictionary and synonym providers from the passed in viewer are used. + * + * @param pv The project viewer. + * @param placeholder The placeholder text. + * @param rows The number of rows of text. + * @param maxChars The maximum number of characters allowed. + * @returns The text area. + */ + public static TextArea createTextArea (AbstractProjectViewer pv, + String placeholder, + int rows, + int maxChars) + { + + TextArea t = new TextArea (placeholder, + rows, + maxChars); + t.setDictionaryProvider (pv.getDictionaryProvider ()); + t.setSpellCheckEnabled (pv.isSpellCheckingEnabled ()); + + try + { + + t.setSynonymProvider (pv.getSynonymProvider ()); + + } catch (Exception e) { + + Environment.logError ("Unable to set synonym provider.", + e); + + } + + return t; + + } + + /** + * Create a text area with the specified placeholder for the number of rows and max chars. The + * default dictionary provider from Environment.getDefaultDictionaryProvider is used and a + * synonym provider with null language is also used. + * + * @param placeholder The placeholder text. + * @param rows The number of rows of text. + * @param maxChars The maximum number of characters allowed. + * @returns The text area. + */ + public static TextArea createTextArea (String placeholder, + int rows, + int maxChars) + { + + TextArea t = new TextArea (placeholder, + rows, + maxChars); + + try + { + + t.setDictionaryProvider (Environment.getDefaultDictionaryProvider ()); + t.setSpellCheckEnabled (true); + + } catch (Exception e) { + + Environment.logError ("Unable to set dictionary provider", + e); + + } + + try + { + + t.setSynonymProvider (Environment.getSynonymProvider (null)); + + } catch (Exception e) { + + Environment.logError ("Unable to set synonym provider.", + e); + + } + + return t; + + } + + public static JComponent createPopupMenuButtonBar (String title, + final JPopupMenu parent, + List buttons) + { + + ActionListener aa = new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + parent.setVisible (false); + + } + + }; + + for (JComponent but : buttons) + { + + if (but instanceof JButton) + { + + JButton b = (JButton) but; + + b.addActionListener (aa); + + } + + } + + Box b = new Box (BoxLayout.X_AXIS); + + // This is to get around the "icon space" in the menu. + b.add (Box.createHorizontalStrut (32)); + + if (title == null) + { + + title = ""; + + } + + JLabel l = new JLabel (Environment.replaceObjectNames (title)); + + l.setForeground (UIUtils.getColor ("#444444")); + l.setFont (l.getFont ().deriveFont (Font.ITALIC)); + + l.setPreferredSize (new Dimension (Math.max (50, l.getPreferredSize ().width), + l.getPreferredSize ().height)); + + b.add (l); + + b.add (Box.createHorizontalStrut (10)); + + b.add (UIUtils.createButtonBar (buttons)); + + b.add (Box.createHorizontalGlue ()); + + return b; + + } + + public static JPanel createButtonBar2 (JButton[] buts, + float alignment) + { + + ButtonBarBuilder bb = ButtonBarBuilder.create (); + + if (buts == null) + { + + return bb.build (); + + } + + if ((alignment == Component.RIGHT_ALIGNMENT) + || + (alignment == Component.CENTER_ALIGNMENT) + ) + { + + bb.addGlue (); + + } + + bb.addButton (buts); + + if (alignment == Component.CENTER_ALIGNMENT) + { + + bb.addGlue (); + + } + + bb.opaque (false); + + JPanel p = bb.build (); + + p.setAlignmentX (Component.LEFT_ALIGNMENT); + + return p; + + } + + public static JToolBar createButtonBar (List buttons) + { + + JToolBar tb = new JToolBar (); + tb.setOpaque (false); + tb.setFloatable (false); + tb.setRollover (true); + tb.setBackground (new Color (0, + 0, + 0, + 0)); + + for (int i = 0; i < buttons.size (); i++) + { + + JComponent b = buttons.get (i); + + UIUtils.setAsButton2 (b); + tb.add (b); + + } + + tb.setBackground (null); + tb.setAlignmentX (Component.LEFT_ALIGNMENT); + tb.setBorder (null); + + return tb; + + } + + public static JButton createButton (ImageIcon icon) + { + + return UIUtils.createButton (icon, + null, + null); + + } + + public static JButton createButton (ImageIcon icon, + String toolTipText, + ActionListener action) + { + + JButton b = new JButton (icon); + + b.setFocusPainted (false); + b.setToolTipText (toolTipText); + b.setOpaque (false); + UIUtils.setAsButton (b); + + if (action != null) + { + + b.addActionListener (action); + + } + + return b; + + } + + public static JButton createButton (String icon, + int iconType, + String toolTipText, + ActionListener action) + { + + return UIUtils.createButton (Environment.getIcon (icon, + iconType), + toolTipText, + action); + + } + + public static JButton createButton (String label, + String icon) + { + + JButton b = new JButton (Environment.getButtonLabel (label), + (icon == null ? null : Environment.getIcon (icon, + Constants.ICON_MENU))); + + return b; + + } + + public static JButton createButton (String label) + { + + return UIUtils.createButton (label, + (String) null); + + } + + public static JButton createButton (String label, + ActionListener onClick) + { + + JButton b = UIUtils.createButton (label, + (String) null); + + if (onClick != null) + { + + b.addActionListener (onClick); + + } + + return b; + + } + + public static void treeChanged (DataObject d, + JTree tree) + { + + DefaultTreeModel model = (DefaultTreeModel) tree.getModel (); + + DefaultMutableTreeNode node = (DefaultMutableTreeNode) UIUtils.getTreePathForUserObject ((DefaultMutableTreeNode) model.getRoot (), + d).getLastPathComponent (); + + model.nodeStructureChanged (node); + + } + + public static void informTreeOfNodeChange (NamedObject n, + JTree tree) + { + + DefaultTreeModel model = (DefaultTreeModel) tree.getModel (); + + DefaultMutableTreeNode node = (DefaultMutableTreeNode) UIUtils.getTreePathForUserObject ((DefaultMutableTreeNode) model.getRoot (), + n).getLastPathComponent (); + + model.nodeChanged (node); + + } + + public static String formatPrompt (Prompt p) + { + + if (p == null) + { + + return getUIString (warmups,prompt,view,unavailable); + //"Prompt no longer available. Usually this is due to it's removal at the request of the author."; + + } + + String link = ""; + + if (p.isUserPrompt ()) + { + + link = getUIString (warmups,prompt,view,ownprompt); + //"by You"; + + } else + { + + link = String.format (getUIString (warmups,prompt,view, LanguageStrings.link), + //"%s by %s", + p.getURL (), + p.getStoryName (), + p.getAuthor ()); + + } + + return p.getText () + "
    - " + link; + + + } + + public static Font getHeaderFont () + { + + if (UIUtils.headerFont == null) + { + + UIUtils.headerFont = new JLabel ("").getFont ().deriveFont (Font.BOLD, + 16); + + } + + return UIUtils.headerFont; + + } + + public static float getScaledFontSize (int v) + { + + // Ugh, assume a 96 dpi and let the underlying windows manager handle scaling. + // We return a float here so that calls to Font.deriveFont can use the value directly rather than + // having to cast. + return (float) (Math.round ((float) v * ((float) DEFAULT_ASSUMED_SCREEN_RESOLUTION / 72f))); + + } + + @Deprecated + /** + * Use UIUtils.getScaledFontSize instead. + */ + public static float scaleToScreenSize (double h) + { + + // Ugh, assume a 96 dpi and let the underlying windows manager handle scaling. + return UIUtils.getScaledFontSize ((int) h); + + } + + public static int getPrintFontSize () + { + + return UIUtils.getPrintFontSize (new JLabel ().getFont ().getSize ()); + + } + + public static int getPrintFontSize (int size) + { + + return Math.round ((float) size / ((float) java.awt.Toolkit.getDefaultToolkit ().getScreenResolution () / 72f)); + + } + + public static int getEditorFontSize (int size) + { + + // Need to take the screen resolution into account. + float s = (float) size * ((float) java.awt.Toolkit.getDefaultToolkit ().getScreenResolution () / 72f); + + return (int) s; + + } + + public static boolean isChildOf (MouseEvent ev, + Component parent) + { + + return UIUtils.isChildOf ((Component) ev.getSource (), + parent); + + } + + public static boolean isChildOf (Component child, + Component parent) + { + + Container p = child.getParent (); + + while (p != null) + { + + if (p == parent) + { + + return true; + + } + + p = p.getParent (); + + } + + return false; + + } + + public static ImageIcon getColoredIcon (String name, + int type, + Color c) + { + + ImageIcon ic = Environment.getIcon (name, + type); + + if (ic == null) + { + + return null; + + } + + return UIUtils.getColoredIcon (ic.getImage (), + c); + + } + + public static ImageIcon getColoredIcon (Image im, + Color c) + { + + if (im == null) + { + + return null; + + } + + final int crgb = c.getRGB (); + + ImageFilter filter = new RGBImageFilter() + { + public final int filterRGB(int x, int y, int rgb) + { + if (rgb != 0) + { + + } + return (rgb != 0 ? crgb : rgb); + + } + }; + + ImageProducer ip = new FilteredImageSource (im.getSource (), filter); + return new ImageIcon (Toolkit.getDefaultToolkit().createImage(ip)); + + } + + public static Image replaceColorInImage (Image im, + Color orig, + Color changeTo) + { + + if (im == null) + { + + return null; + + } + + final int orgb = orig.getRGB (); + final int crgb = changeTo.getRGB (); + + ImageFilter filter = new RGBImageFilter() + { + public final int filterRGB(int x, int y, int rgb) + { + if (rgb != 0) + { + + } + + return (rgb == orgb ? crgb : rgb); + + } + }; + + ImageProducer ip = new FilteredImageSource (im.getSource (), filter); + return Toolkit.getDefaultToolkit().createImage (ip); + + } + + public static int getSplitPaneDividerSize () + { + + return 2; + + } + + public static Color getTitleColor () + { + + return UIUtils.getColor ("#333333"); + + } + + public static Color getInnerBorderColor () + { + + return UIUtils.getColor ("#dddddd"); + + } + + public static Color getDragIconColor () + { + + return UIUtils.getColor ("#aaaaaa"); + + } + + public static Color getBorderColor () + { + + return UIUtils.getColor ("#aaaaaa"); + + } + + public static Color getComponentColor () + { + + return UIUtils.getColor ("#fdfdfd"); + + } + + public static boolean clipboardHasContent () + { + + try + { + + return (Toolkit.getDefaultToolkit ().getSystemClipboard ().getData (DataFlavor.stringFlavor) != null); + + } catch (Exception e) + { + + } + + return false; + + } + + /** + * Draw a string on the image at a specified "location", supported values for where are: + * - tl - draw the string starting at the top left corner. + * - bl - bottom left corner. + * - tr - top right corner. (so start the text in from the right) + * - br - bottom right corner (start, in from the right and bottom) + * + * @param im The image to draw on, this image is untouched. + * @param text The text to draw on the image. + * @param font The font to use. + * @param color The color to use. + * @param where Where the text should be drawn. + * @returns A new image with the text drawn on top of im. + */ + public static BufferedImage drawStringOnImage (BufferedImage im, + String text, + Font font, + Color color, + String where) + { + + FontMetrics m = im.getGraphics ().getFontMetrics (font); + + int sh = m.getHeight (); + int sw = m.stringWidth (text); + + int imw = im.getWidth (); + int imh = im.getHeight (); + + int nw = 0; + int nh = 0; + + Point w = null; + + if (where.equals ("tr")) + { + + nw = imw - sw; + nh = sh; + + } + + if (where.equals ("bl")) + { + + nh = imh - sh; + + } + + if (where.equals ("br")) + { + + nh = imh;// - sh; + nw = imw - sw; + + } + + return UIUtils.drawStringOnImage (im, + text, + font, + color, + new Point (nw, nh)); + + } + + public static BufferedImage getImageOfComponent (Component c, + int width, + int height) + { + + width = (width > 0 ? width : c.getWidth ()); + height = (height > 0 ? height : c.getHeight ()); + + BufferedImage image = new BufferedImage (width, + height, + BufferedImage.TYPE_INT_ARGB_PRE); + + Graphics2D g = (Graphics2D) image.getGraphics (); + + RenderingHints rh = new RenderingHints( + RenderingHints.KEY_TEXT_ANTIALIASING, + RenderingHints.VALUE_TEXT_ANTIALIAS_ON); + g.setRenderingHints(rh); + + if (c.isOpaque ()) + { + + g.setColor (c.getBackground ()); + + g.fillRect (0, + 0, + width, + height); + + } + + c.paint (g); + + return image; + + } + + public static BufferedImage copyImage (BufferedImage im) + { + + BufferedImage b = new BufferedImage (im.getWidth (), + im.getHeight (), + im.getType ()); + Graphics g = b.getGraphics (); + g.drawImage (im, + 0, + 0, + null); + g.dispose (); + + return b; + + } + + /** + * Draw a string onto an image at the specified point (where). + * + * @param im The image to draw onto. + * @param text The text to draw. + * @param font The font to use. + * @param color The color to use. + * @param where Where to draw the text. + * @returns A new image with the text overlaid on the image. + */ + public static BufferedImage drawStringOnImage (BufferedImage im, + String text, + Font font, + Color color, + Point where) + { + + BufferedImage newIm = UIUtils.copyImage (im); + + Graphics2D g = (Graphics2D) newIm.getGraphics (); + + g.setFont (font); + + g.setRenderingHint (RenderingHints.KEY_TEXT_ANTIALIASING, + RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB); + + g.setColor (color); + + FontMetrics fm = g.getFontMetrics (); + + java.awt.geom.Rectangle2D b = g.getFontMetrics ().getStringBounds (text, + g); + + g.drawString (text, + where.x, + (int) (where.y + b.getHeight ())); + + return newIm; + + } + + public static BufferedImage getBufferedImage (Image im, + Component io) + { + + if (im == null) + { + + return null; + + } + + int height = im.getHeight (io); + int width = im.getWidth (io); + + BufferedImage bi = new BufferedImage (width, + height, + BufferedImage.TYPE_INT_ARGB); + Graphics g = bi.getGraphics (); + g.drawImage (im, + 0, + 0, + Color.black, + io); + + return bi; + + } + +/* + Needed? + public static BufferedImage getScaledImage (DataSource ds, + int width, + int height) + { + + try + { + + return UIUtils.getScaledImage (ImageIO.read (ds.getInputStream ()), + width, + height); + + } catch (Exception e) { + + Environment.logError ("Unable to read image from data source: " + ds, + e); + + return null; + + } + + } +*/ + public static BufferedImage getImage (byte[] bytes) + throws GeneralException + { + + if (bytes == null) + { + + return null; + + } + + try + { + + return ImageIO.read (new ByteArrayInputStream (bytes)); + + } catch (Exception e) { + + throw new GeneralException ("Unable to convert bytes to an image", + e); + + } + + } + + public static byte[] getImageBytes (BufferedImage im) + throws GeneralException + { + + if (im == null) + { + + return null; + + } + + try + { + + ByteArrayOutputStream bout = new ByteArrayOutputStream (); + + // Shouldn't use png here, it is too slow. + if (!ImageIO.write (im, + "png", + bout)) + { + + throw new GeneralException ("Unable to write image using png"); + + } + + bout.flush (); + bout.close (); + return bout.toByteArray (); + + } catch (Exception e) { + + throw new GeneralException ("Unable to get bytes for image", + e); + + } + + } + + public static BufferedImage getImage (File f) + { + + if (f == null) + { + + return null; + + } + + try + { + + return ImageIO.read (f); + + } catch (Exception e) { + + Environment.logError ("Unable to find image for file: " + f, + e); + + return null; + + } + + } + + public static BufferedImage getScaledImage (File f, + int width, + int height) + { + + return UIUtils.getScaledImage (UIUtils.getImage (f), + width, + height); + + } + + public static BufferedImage getScaledImage (File f, + int width) + { + + return UIUtils.getScaledImage (UIUtils.getImage (f), + width); + + } + + public static BufferedImage getScaledImage (BufferedImage img, + int targetWidth) + { + + if (img == null) + { + + return null; + + } + + return Scalr.resize (img, + Scalr.Method.QUALITY, + Scalr.Mode.FIT_TO_WIDTH, + targetWidth, + Scalr.OP_ANTIALIAS); + + } + + public static BufferedImage createBufferedImage (int width, + int height) + { + + BufferedImage im = new BufferedImage (width, + height, + BufferedImage.TYPE_INT_ARGB); + + Graphics2D g = im.createGraphics (); + + g.setBackground (new Color (0, true)); + g.clearRect (0, 0, width, height); + + g.dispose (); + + return im; + + } + + public static Graphics2D createThrowawayGraphicsInstance () + { + + return new BufferedImage (1, 1, BufferedImage.TYPE_INT_ARGB).createGraphics (); + + } + + public static BufferedImage iconToImage(Icon icon) + { + + if (icon == null) + { + + return null; + + } + + if (icon instanceof ImageIcon) + { + + return (BufferedImage) ((ImageIcon)icon).getImage(); + + } else { + + int w = icon.getIconWidth(); + int h = icon.getIconHeight(); + GraphicsEnvironment ge = + GraphicsEnvironment.getLocalGraphicsEnvironment(); + GraphicsDevice gd = ge.getDefaultScreenDevice(); + GraphicsConfiguration gc = gd.getDefaultConfiguration(); + BufferedImage image = gc.createCompatibleImage(w, h); + Graphics2D g = image.createGraphics(); + icon.paintIcon(null, g, 0, 0); + g.dispose(); + return image; + + } + + } + + public static BufferedImage getScaledImage (BufferedImage img, + int targetWidth, + int targetHeight) + { + + return Scalr.resize (img, + Scalr.Method.QUALITY, + Scalr.Mode.FIT_EXACT, + (targetWidth > 0 ? targetWidth : img.getWidth ()), + (targetHeight > 0 ? targetHeight : img.getHeight ()), + Scalr.OP_ANTIALIAS); +/* + BufferedImage tmp = new BufferedImage (targetWidth, targetHeight, BufferedImage.TYPE_INT_ARGB); + Graphics2D g2 = tmp.createGraphics(); + g2.setRenderingHint (RenderingHints.KEY_RENDERING, + RenderingHints.VALUE_RENDER_QUALITY); + g2.drawImage(img, 0, 0, targetWidth, targetHeight, null); + g2.dispose(); + + return tmp; + */ + } + + public static ImageIcon overlayImage (ImageIcon bg, + ImageIcon fg, + String where) + { + + JButton but = new JButton (); + + Image bgi = bg.getImage (); + Image fgi = fg.getImage (); + + BufferedImage n = new BufferedImage (bgi.getWidth (but), + bgi.getHeight (but), + BufferedImage.TYPE_INT_ARGB); + + Graphics2D g = n.createGraphics (); + g.setRenderingHint (RenderingHints.KEY_ANTIALIASING, + RenderingHints.VALUE_ANTIALIAS_ON); + + g.drawImage (bgi, + 0, + 0, + null); + + if (where.equals ("tl")) + { + + g.drawImage (fgi, + 0, + 0, + null); + + } + + if (where.equals ("tr")) + { + + g.drawImage (fgi, + bgi.getWidth (but) - fgi.getWidth (but), + 0, + null); + + } + + if (where.equals ("bl")) + { + + g.drawImage (fgi, + 0, + bgi.getHeight (but) - fgi.getHeight (but), + null); + + } + + if (where.equals ("br")) + { + + g.drawImage (fgi, + bgi.getWidth (but) - fgi.getWidth (but), + bgi.getHeight (but) - fgi.getHeight (but), + null); + + } + + g.dispose (); + + //bg.setImage (bgi); + + return new ImageIcon (n); + + } + + public static FileFinder createFileFind (final String initPath, + final String finderTitle, + final int fileSelectionMode, + final String approveButtonText, + final ActionListener handler) + { + + FileFinder ff = new FileFinder (); + + ff.setOnSelectHandler (handler); + ff.setApproveButtonText (approveButtonText); + ff.setFinderSelectionMode (fileSelectionMode); + ff.setFinderTitle (finderTitle); + + ff.init (); + + if (initPath != null) + { + + ff.setFile (new File (initPath)); + + } + + return ff; + + } + + public static Component getComponentByName (Container parent, + String name) + { + + if (name == null) + { + + return null; + + } + + if (parent == null) + { + + return null; + + } + + Component[] children = parent.getComponents (); + + for (int i = 0; i < children.length; i++) + { + + if (name.equals (children[i].getName ())) + { + + return children[i]; + + } + + } + + return null; + + } + + public static JMenuItem createMenuItem (String label, + String icon, + ActionListener action) + { + + JMenuItem mi = new JMenuItem (Environment.getButtonLabel (label), + Environment.getIcon (icon, + Constants.ICON_MENU)); + mi.addActionListener (action); + + return mi; + + } + + public static JMenuItem createMenuItem (String label, + ImageIcon icon, + ActionListener action) + { + + JMenuItem mi = new JMenuItem (Environment.getButtonLabel (label), + icon); + mi.addActionListener (action); + + return mi; + + } + + public static JMenuItem createMenuItem (String label, + String icon, + ActionListener action, + String actionCommand, + KeyStroke accel) + { + + JMenuItem mi = UIUtils.createMenuItem (label, + icon, + action); + + mi.setActionCommand (actionCommand); + mi.setAccelerator (accel); + + return mi; + + } + + public static void listenToTableForCellChanges (JTable table, + Action action) + { + + // Shouldn't be cleaned up since it adds itself as a property listener to the table. + new TableCellListener (table, + action); + + } + + public static boolean isAnimatedGif (File f) + { + + String type = Utils.getFileType (f); + + if (f == null) + { + + throw new IllegalArgumentException ("Unable to determine file type for file: " + + f); + + } + + int c = 0; + + ImageReader r = null; + + r = ImageIO.getImageReadersBySuffix (type).next (); + + if (r == null) + { + + throw new IllegalArgumentException ("Unsupported file type for file: " + + f); + + } + + try + { + + r.setInput (ImageIO.createImageInputStream (f)); + + } catch (Exception e) { + + throw new IllegalArgumentException ("Unable to read image file: " + + f, + e); + + } + + try + { + + int ind = 0; + + // Upper bound valid? + while (ind < 100) + { + + if (c > 1) + { + + return true; + + } + + r.read (ind); + + ind++; + c++; + + } + + } catch (Exception e) { + + } + + return false; + + } + + public static void doActionWhenPanelIsReady (final QuollPanel p, + final ActionListener action, + final Object contextObject, + final String actionTypeName) + { + + final Exception pe = new Exception (); + + final javax.swing.Timer t = new javax.swing.Timer (100, + null); + + // TODO: Change this to be based on an event that the panel fires when ready. + ActionListener l = new ActionListener () + { + + private int count = 0; + + public void actionPerformed (ActionEvent ev) + { + + if (p.isReadyForUse ()) + { + + t.setRepeats (false); + t.stop (); + + try + { + + action.actionPerformed (new ActionEvent ((contextObject != null ? contextObject : action), + 1, + (actionTypeName != null ? actionTypeName : "any"))); + + } catch (Exception e) { + + Environment.logError ("Unable to perform action: " + action + "\nCause: " + + Utils.getStackTrace (pe), + e); + + } + + return; + + } + + // 2s delay max. + if (count > 50) + { + + Environment.logError ("Unable to perform action: " + action, + new Exception ("Unable to perform action for panel: " + p.getPanelId (), + pe)); + + t.setRepeats (false); + t.stop (); + + } + + count++; + + } + + }; + + t.setRepeats (true); + t.addActionListener (l); + + t.start (); + + } + + public static void doActionLater (final ActionListener action) + { + + UIUtils.doActionLater (action, + null, + null); + + } + + public static void doActionLater (final ActionListener action, + final Object contextObject, + final String actionTypeName) + { + + SwingUtilities.invokeLater (new Runner () + { + + public void run () + { + + try + { + + action.actionPerformed (new ActionEvent ((contextObject != null ? contextObject : action), + 1, + (actionTypeName != null ? actionTypeName : "any"))); + + } catch (Exception e) { + + Environment.logError ("Unable to perform action", + e); + + } + + } + + }); + + } + + public static void addDoActionOnReturnPressed (TextArea text, + ActionListener action) + { + + text.addDoActionOnCtrlReturnPressed (action); + + } + + public static void addDoActionOnReturnPressed (final JTextComponent text, + final ActionListener action) + { + + if (action == null) + { + + return; + + } + + if (text instanceof JTextField) + { + + text.addKeyListener (new KeyAdapter () + { + + public void keyPressed (KeyEvent ev) + { + + if (ev.getKeyCode () == KeyEvent.VK_ENTER) + { + + // This is the same as save for the form. + action.actionPerformed (new ActionEvent (text, + 1, + "return-pressed")); + + } + + } + + }); + + } else { + + text.addKeyListener (new KeyAdapter () + { + + public void keyPressed (KeyEvent ev) + { + + if (((ev.getModifiersEx () & InputEvent.CTRL_DOWN_MASK) == InputEvent.CTRL_DOWN_MASK) && + (ev.getKeyCode () == KeyEvent.VK_ENTER)) + { + + action.actionPerformed (new ActionEvent (text, + 1, + "ctrl-return-pressed")); + + } + + } + + }); + + } + + } + + public static QPopup createQuestionPopup (AbstractViewer viewer, + String title, + String icon, + String message, + String confirmButtonLabel, + String cancelButtonLabel, + final ActionListener onConfirm, + final ActionListener onCancel, + final ActionListener onClose, + Point showAt) + { + + Map buttons = new LinkedHashMap (); + + if (onConfirm != null) + { + + buttons.put (Environment.getButtonLabel (confirmButtonLabel, + getUIString (LanguageStrings.buttons,confirm)), + onConfirm); + + } + + buttons.put (Environment.getButtonLabel (cancelButtonLabel, + getUIString (LanguageStrings.buttons,cancel)), + onCancel); + + return UIUtils.createQuestionPopup (viewer, + title, + icon, + message, + buttons, + onClose, + showAt); + + } + + public static QPopup createQuestionPopup (AbstractViewer viewer, + String title, + String icon, + String message, + Map buttons, + ActionListener onClose, + Point showAt) + { + + JComponent mess = UIUtils.createHelpTextPane (Environment.replaceObjectNames (message), + viewer); + mess.setBorder (null); + mess.setSize (new Dimension (UIUtils.getPopupWidth () - 20, + 500)); + + return UIUtils.createQuestionPopup (viewer, + title, + icon, + mess, + buttons, + onClose, + showAt); + + } + + public static QPopup createQuestionPopup (PopupsSupported viewer, + String title, + String icon, + JComponent mess, + Map buttons, + ActionListener onClose, + Point showAt) + { + + final QPopup qp = UIUtils.createClosablePopup (title, + Environment.getIcon (icon, + Constants.ICON_POPUP), + onClose); + + Box content = new Box (BoxLayout.Y_AXIS); + + content.add (mess); + content.add (Box.createVerticalStrut (10)); + + JButton[] buts = new JButton[buttons.size ()]; + + int i = 0; + + // Too much type information required to do entrySet... + // We will never do much iterating here so simpler and clearer to just do it the "hard way". + Iterator iter = buttons.keySet ().iterator (); + + while (iter.hasNext ()) + { + + String label = iter.next (); + + ActionListener a = buttons.get (label); + + JButton b = UIUtils.createButton (label, + qp.getCloseAction ()); + + if (a != null) + { + + b.addActionListener (a); + + } + + buts[i++] = b; + + } + + JComponent bs = UIUtils.createButtonBar2 (buts, + Component.LEFT_ALIGNMENT); //ButtonBarFactory.buildLeftAlignedBar (buts); + bs.setAlignmentX (Component.LEFT_ALIGNMENT); + content.add (bs); + content.setBorder (new EmptyBorder (10, 10, 10, 10)); + qp.setContent (content); + + content.setPreferredSize (new Dimension (Math.max (UIUtils.getPopupWidth (), bs.getPreferredSize ().width), + content.getPreferredSize ().height)); + + if (showAt == null) + { + + if (viewer instanceof Component) + { + + showAt = UIUtils.getCenterShowPosition ((Component) viewer, + qp); + + } + + } + + viewer.showPopupAt (qp, + showAt, + false); + + if (viewer instanceof Component) + { + + qp.setDraggable ((Component) viewer); + + } + + return qp; + + } + + public static QPopup createHelpPopup (AbstractViewer viewer, + String title, + String text, + ActionListener onClose, + Point showAt) + { + + final QPopup qp = UIUtils.createClosablePopup ((title != null ? title : getUIString (help,popup,title)), + //"Help"), + Environment.getIcon (Constants.HELP_ICON_NAME, + Constants.ICON_POPUP), + onClose); + + Box content = new Box (BoxLayout.Y_AXIS); + + content.add (UIUtils.createHelpTextPane (text, + viewer)); + content.add (Box.createVerticalStrut (10)); + + JButton b = UIUtils.createButton (getUIString (buttons,close)); + + JButton[] buts = { b }; + + JComponent bs = UIUtils.createButtonBar2 (buts, + Component.CENTER_ALIGNMENT); + bs.setAlignmentX (Component.LEFT_ALIGNMENT); + content.add (bs); + content.setBorder (UIUtils.createPadding (10, 10, 10, 10)); + qp.setContent (content); + + content.setPreferredSize (new Dimension (UIUtils.getPopupWidth (), + content.getPreferredSize ().height)); + + if (showAt == null) + { + + if (viewer instanceof Component) + { + + showAt = UIUtils.getCenterShowPosition ((Component) viewer, + qp); + + } + + } + + viewer.showPopupAt (qp, + showAt, + false); + + if (viewer instanceof Component) + { + + qp.setDraggable ((Component) viewer); + + } + + return qp; + + } + + public static QPopup createPasswordInputPopup (final AbstractViewer viewer, + String title, + String icon, + String message, + String confirmButtonLabel, + String cancelButtonLabel, + String initValue, + final ValueValidator validator, + final ActionListener onConfirm, + final ActionListener onCancel, + Point showAt) + { + + return UIUtils.createTextInputPopup (viewer, + title, + icon, + message, + UIUtils.createPasswordField (), + confirmButtonLabel, + cancelButtonLabel, + initValue, + validator, + onConfirm, + onCancel, + showAt); + + } + + public static QPopup createTextInputPopup (final AbstractViewer viewer, + String title, + String icon, + String message, + String confirmButtonLabel, + String cancelButtonLabel, + String initValue, + final ValueValidator validator, + final ActionListener onConfirm, + final ActionListener onCancel, + Point showAt) + { + + return UIUtils.createTextInputPopup (viewer, + title, + icon, + message, + UIUtils.createTextField (), + confirmButtonLabel, + cancelButtonLabel, + initValue, + validator, + onConfirm, + onCancel, + showAt); + + } + + private static QPopup createTextInputPopup (final AbstractViewer viewer, + String title, + String icon, + String message, + JTextField textField, + String confirmButtonLabel, + String cancelButtonLabel, + String initValue, + final ValueValidator validator, + final ActionListener onConfirm, + final ActionListener onCancel, + Point showAt) + { + + final QPopup qp = UIUtils.createPopup (Environment.replaceObjectNames (title), + icon, + null, + true, + onCancel); + + final Box content = new Box (BoxLayout.Y_AXIS); + + JComponent mess = UIUtils.createHelpTextPane (message, + viewer); + mess.setBorder (null); + mess.setSize (new Dimension (UIUtils.getPopupWidth () - 20, + mess.getPreferredSize ().height)); + + content.add (mess); + + content.add (Box.createVerticalStrut (10)); + + final JLabel error = UIUtils.createErrorLabel (getUIString (form,errors,novalue)); + //"Please enter a value."); + + error.setVisible (false); + error.setBorder (UIUtils.createPadding (0, 0, 5, 0)); + + final JTextField text = textField; + + text.setMinimumSize (new Dimension (300, + text.getPreferredSize ().height)); + text.setPreferredSize (new Dimension (300, + text.getPreferredSize ().height)); + text.setMaximumSize (new Dimension (Short.MAX_VALUE, + text.getPreferredSize ().height)); + text.setAlignmentX (Component.LEFT_ALIGNMENT); + + if (initValue != null) + { + + text.setText (initValue); + + } + + error.setAlignmentX (Component.LEFT_ALIGNMENT); + + content.add (error); + content.add (text); + + content.add (Box.createVerticalStrut (10)); + + JButton confirm = null; + JButton cancel = UIUtils.createButton ((cancelButtonLabel != null ? cancelButtonLabel : getUIString (buttons, LanguageStrings.cancel)), + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + if (onCancel != null) + { + + onCancel.actionPerformed (ev); + + } + + qp.removeFromParent (); + + } + + }); + + if (onConfirm != null) + { + + ActionListener confirmAction = new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + if (validator != null) + { + + String mess = validator.isValid (text.getText ().trim ()); + + if (mess != null) + { + + // Should probably wrap this in a + error.setText (mess); + + error.setVisible (true); + + // Got to be an easier way of doing this. + content.setPreferredSize (null); + + content.setPreferredSize (new Dimension (UIUtils.getPopupWidth (), + content.getPreferredSize ().height)); + + viewer.showPopupAt (qp, + qp.getLocation (), + false); + + return; + + } + + } + + onConfirm.actionPerformed (new ActionEvent (text, + 0, + text.getText ().trim ())); + + qp.removeFromParent (); + + } + + }; + + confirm = UIUtils.createButton ((confirmButtonLabel != null ? confirmButtonLabel : getUIString (buttons, LanguageStrings.confirm)), + confirmAction); + + UIUtils.addDoActionOnReturnPressed (text, + confirmAction); + + } + + JButton[] buts = null; + + if (confirm != null) + { + + buts = new JButton[] { confirm, cancel }; + + } else { + + buts = new JButton[] { cancel }; + + } + + JComponent buttons = UIUtils.createButtonBar2 (buts, + Component.LEFT_ALIGNMENT); //ButtonBarFactory.buildLeftAlignedBar (buts); + buttons.setAlignmentX (Component.LEFT_ALIGNMENT); + content.add (buttons); + content.setBorder (UIUtils.createPadding (10, 10, 10, 10)); + qp.setContent (content); + + content.setPreferredSize (new Dimension (UIUtils.getPopupWidth (), + content.getPreferredSize ().height)); + + if (showAt == null) + { + + showAt = UIUtils.getCenterShowPosition (viewer, + qp); + + } + + qp.setDraggable (viewer); + + viewer.showPopupAt (qp, + showAt, + false); + + if (initValue != null) + { + + text.selectAll (); + + } + + text.grabFocus (); + + return qp; + + } + + public static Point getCenterShowPosition (Component parent, + Component show) + { + + Dimension pd = (parent.isShowing () ? parent.getSize () : parent.getPreferredSize ()); + Dimension sd = (show.isShowing () ? show.getSize () : show.getPreferredSize ()); + + return new Point ((pd.width - sd.width) / 2, + (pd.height - sd.height) / 2); + + } + + public static void doLater (ActionListener l) + { + + UIUtils.doLater (l, + null); + + } + + public static void doLater (final ActionListener l, + final Object c) + { + + if (l == null) + { + + return; + + } + + SwingUtilities.invokeLater (new Runnable () + { + + public void run () + { + + try + { + + l.actionPerformed (new ActionEvent ((c != null ? c : this), + 0, + "do")); + + } catch (Exception e) { + + Environment.logError ("Unable to perform action", + e); +/* + if (c instanceof Component) + { + + UIUtils.showErrorMessage ((Component) c, + "Unable to perform action"); + + } +*/ + } + + } + + }); + + + } + + /** + * Set the specified empty border (padding) around the component, this is shorthand for: + * c.setBorder (UIUtils.createPadding (top, left, bottom, right)); + * + * @param c The component to set the border on. + * @param top The top padding. + * @param left The left padding. + * @param bottom The bottom padding. + * @param right The right padding. + */ + public static void setPadding (JComponent c, + int top, + int left, + int bottom, + int right) + { + + c.setBorder (UIUtils.createPadding (top, left, bottom, right)); + + } + + /** + * Is a wrapper for: + * + * new CompoundBorder (new MatteBorder (0, 0, 1, 0, UIUtils.getInnerBorderColor ()), + * UIUtils.createPadding (top, left, bottom, right)); + * + * + * @returns A compound border with an outer line and an inner padding. + */ + public static CompoundBorder createBottomLineWithPadding (int top, + int left, + int bottom, + int right) + { + + return new CompoundBorder (new MatteBorder (0, 0, 1, 0, UIUtils.getInnerBorderColor ()), + UIUtils.createPadding (top, left, bottom, right)); + + } + + /** + * Is a wrapper for: + * + * new CompoundBorder (new MatteBorder (1, 0, 0, 0, UIUtils.getInnerBorderColor ()), + * UIUtils.createPadding (top, left, bottom, right)); + * + * + * @returns A compound border with an outer line and an inner padding. + */ + public static CompoundBorder createTopLineWithPadding (int top, + int left, + int bottom, + int right) + { + + return new CompoundBorder (new MatteBorder (1, 0, 0, 0, UIUtils.getInnerBorderColor ()), + UIUtils.createPadding (top, left, bottom, right)); + + } + + /** + * Is a wrapper for: + * + * new CompoundBorder (new MatteBorder (1, 1, 1, 1, UIUtils.getBorderColor ()), + * UIUtils.createPadding (top, left, bottom, right)); + * + * + * @returns A compound border with an outer line and an inner padding. + */ + public static CompoundBorder createLineBorderWithPadding (int top, + int left, + int bottom, + int right) + { + + return new CompoundBorder (new MatteBorder (1, 1, 1, 1, UIUtils.getBorderColor ()), + UIUtils.createPadding (top, left, bottom, right)); + + } + + public static int getMaxStringLength (Font f, + String... strs) + { + + int maxl = 0; + + java.awt.font.FontRenderContext frc = new java.awt.font.FontRenderContext (new java.awt.geom.AffineTransform (), true, true); + + for (String s : strs) + { + + // We add 1 to prevent issues with half rounding when the cast is performed. + maxl = Math.max ((int) f.getStringBounds (s, + frc).getWidth () + 1, + maxl); + + } + + return maxl; + + } + + public static EmptyBorder createPadding (int top, + int left, + int bottom, + int right) + { + + return new EmptyBorder (top, left, bottom, right); + + } + + public static void closePopupParent (Container parent) + { + + if (parent == null) + { + + return; + + } + + if (parent instanceof QPopup) + { + + ((QPopup) parent).removeFromParent (); + + return; + + } + + UIUtils.closePopupParent (parent.getParent ()); + + } + + public static void resizeParent (final Container parent) + { + + if (parent == null) + { + + return; + + } + + if (parent instanceof QPopup) + { + + ((QPopup) parent).resize (); + + return; + + } + + if (parent instanceof PopupWindow) + { + + ((PopupWindow) parent).resize (); + + return; + + } + + UIUtils.resizeParent (parent.getParent ()); + + } + + public static QPopup createWizardPopup (String title, + String iconType, + ActionListener onClose, + Wizard wizard) + { + + QPopup p = UIUtils.createClosablePopup (title, + (iconType != null ? Environment.getIcon (iconType, Constants.ICON_POPUP) : null), + onClose); + + wizard.init (); + + wizard.setSize (new Dimension (UIUtils.getPopupWidth () - 20, + wizard.getPreferredSize ().height)); + wizard.setBorder (UIUtils.createPadding (10, 10, 10, 10)); + + p.setContent (wizard); + + return p; + + } + + /** + * Return a new value validator that ensures that the word (case-insensitive) "yes" is provided. + * + * @returns The validator. + */ + public static ValueValidator getYesValueValidator () + { + + return new ValueValidator () + { + + public String isValid (String v) + { + + if ((v == null) + || + (!v.trim ().equalsIgnoreCase (getUIString (form,affirmativevalue))) + ) + { + + return getUIString (form,errors,affirmativevalue); + //"Please enter the word Yes below."; + + } + + return null; + + } + + }; + + } + + public static JTextField createSearchBox (final int delay, + final ActionListener onSearch) + { + + final JTextField text = UIUtils.createTextField (); + text.setBorder (new CompoundBorder (UIUtils.createPadding (5, 10, 5, 10), + text.getBorder ())); + + KeyAdapter vis = new KeyAdapter () + { + + private javax.swing.Timer searchT = new javax.swing.Timer (delay, + onSearch); + + public void keyPressed (KeyEvent ev) + { + + this.searchT.setRepeats (false); + this.searchT.stop (); + + // If enter was pressed then search, don't start the timer. + if (ev.getKeyCode () == KeyEvent.VK_ENTER) + { + + if (onSearch != null) + { + + onSearch.actionPerformed (new ActionEvent (text, 1, text.getText ().trim ())); + + } + + + return; + + } + + this.searchT.start (); + + } + + }; + + text.addKeyListener (vis); + text.setMaximumSize (new Dimension (Short.MAX_VALUE, + text.getPreferredSize ().height)); + + text.addMouseListener (new MouseEventHandler () + { + + @Override + public void mouseEntered (MouseEvent ev) + { + + text.grabFocus (); + text.selectAll (); + + } + + }); + + return text; + + } + + public static JComponent showTemporaryNotification (String t, + AbstractProjectViewer parent, + Component showAt, + int showFor) + { + + Box outer = new Box (BoxLayout.Y_AXIS); + + outer.setBorder (QPopup.defaultBorder); + outer.setOpaque (false); + outer.setDoubleBuffered (true); + outer.setMaximumSize (new Dimension (Short.MAX_VALUE, + Short.MAX_VALUE)); + Box inner = new Box (BoxLayout.Y_AXIS); + inner.setBackground (UIUtils.getComponentColor ()); + inner.setOpaque (true); + + inner.setBorder (UIUtils.createPadding (5, 5, 5, 5)); + + JTextPane m = UIUtils.createHelpTextPane (t, + parent); + m.setSize (new Dimension (150 - 20, + m.getPreferredSize ().height)); + + inner.add (m); + + outer.add (inner); + + parent.showPopupAt (outer, + showAt, + false); + + return outer; + + } + + public static javax.swing.Timer createCyclicAnimator (final PropertyChangeListener cycleUp, + final PropertyChangeListener cycleDown, + final int fps, + final int duration, + final int startValue, + final int endValue, + final int repeatCount, + final ActionListener onComplete) + { + + final boolean incr = (startValue <= endValue); + + final AtomicInteger count = new AtomicInteger (0); + + final Map animators = new HashMap (); + + final javax.swing.Timer up = UIUtils.createAnimator (cycleUp, + fps, + duration / 2, + (incr ? startValue : endValue), + (incr ? endValue : startValue), + new ActionListener () + { + + public void actionPerformed (ActionEvent ev) + { + + if (incr) + { + + count.incrementAndGet (); + + } + + if ((!incr) + && + (count.get () == repeatCount) + ) + { + + if (onComplete != null) + { + + onComplete.actionPerformed (new ActionEvent ("complete", endValue, "complete")); + + } + + return; + + } + + animators.get ("down").restart (); + + } + + }); + + animators.put ("up", + up); + + final javax.swing.Timer down = UIUtils.createAnimator (cycleDown, + fps, + duration / 2, + (incr ? endValue : startValue), + (incr ? startValue : endValue), + new ActionListener () + { + + public void actionPerformed (ActionEvent ev) + { + + + if (!incr) + { + + count.incrementAndGet (); + + } + + if ((incr) + && + (count.get () == repeatCount) + ) + { + + if (onComplete != null) + { + + onComplete.actionPerformed (new ActionEvent ("complete", endValue, "complete")); + + } + + return; + + } + + animators.get ("up").restart (); + + } + + }); + + animators.put ("down", + down); + + javax.swing.Timer t = new javax.swing.Timer (0, null); + + t.addActionListener (new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + if (incr) + { + + up.start (); + + } else { + + down.start (); + + } + + } + + }); + + t.setRepeats (false); + + return t; + + } + + public static javax.swing.Timer createAnimator (final PropertyChangeListener l, + final int fps, + final int duration, + final double startValue, + final double endValue, + final ActionListener onComplete) + { + + final javax.swing.Timer t = new javax.swing.Timer (1000 / fps, null); + + final double increment = ((endValue - startValue) / (double) fps) * (1000d / (double) duration); + + final boolean incr = (startValue <= endValue); + + t.addActionListener (new ActionListener () + { + + private double v = startValue; + + @Override + public void actionPerformed (ActionEvent ev) + { + + if ((incr && (this.v >= endValue)) + || + (!incr && (this.v <= endValue)) + ) + { + + t.stop (); + + if (onComplete != null) + { + + this.v = startValue; + + onComplete.actionPerformed (new ActionEvent ("complete", 1, "complete")); + + } + + return; + + } + + double nv = this.v + increment; + + if ((incr) + && + (nv > endValue) + ) + { + + nv = endValue; + + } + + if ((!incr) + && + (nv < endValue) + ) + { + + nv = endValue; + + } + + l.propertyChange (new PropertyChangeEvent (this, + "value", + this.v, + nv)); + + this.v = nv; + + } + + }); + + t.setCoalesce (true); + + return t; + + } + + public static void askForPasswordForProject (final ProjectInfo proj, + ValueValidator validator, + final ActionListener onProvided, + final AbstractViewer parentViewer) + { +/* +TODO + AbstractProjectViewer pv = Environment.getProjectViewer (proj); + + if ((pv == null) + && + (proj != null) + && + (proj.isEncrypted ()) + ) + { + + if (validator == null) + { + + validator = new ValueValidator () + { + + public String isValid (String v) + { + + java.util.List prefix = Arrays.asList (project,actions,openproject,enterpasswordpopup,errors); + + if ((v == null) + || + (v.trim ().equals ("")) + ) + { + + return getUIString (prefix,novalue); + //"Please enter the password."; + + } + + ObjectManager om = null; + + try + { + + om = Environment.getProjectObjectManager (proj, + v); + + } catch (Exception e) { + + if (ObjectManager.isDatabaseAlreadyInUseException (e)) + { + + return getUIString (prefix,projectalreadyopen); + //"Sorry, the {project} appears to already be open in Quoll Writer. Please close all other instances of Quoll Writer first before trying to open the {project}."; + + } + + if (ObjectManager.isEncryptionException (e)) + { + + return getUIString (prefix,invalidpassword); + //"Password is not valid."; + + } + + Environment.logError ("Cant open project: " + + proj, + e); + + UIUtils.showErrorMessage (parentViewer, + getUIString (prefix,general)); + //"Sorry, the {project} can't be opened. Please contact Quoll Writer support for assistance."); + + return null; + + } finally { + + if (om != null) + { + + om.closeConnectionPool (); + + } + + } + + return null; + + } + + }; + + } + + java.util.List prefix = Arrays.asList (project,actions,openproject,enterpasswordpopup); + + UIUtils.createPasswordInputPopup (parentViewer, + getUIString (prefix,title), + //"Password required", + Constants.PROJECT_ICON_NAME, + String.format (getUIString (prefix,text), + //"{Project} %s is encrypted, please enter the password to unlock it below.", + proj.getName ()), + getUIString (prefix,buttons,open), + //"Open", + getUIString (prefix,buttons,cancel), + //Constants.CANCEL_BUTTON_LABEL_ID, + null, + validator, + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + proj.setFilePassword (ev.getActionCommand ()); + + if (onProvided != null) + { + + onProvided.actionPerformed (new ActionEvent (proj, + 1, + "provided")); + + } + + } + + }, + null, + null); + + } else { + + onProvided.actionPerformed (new ActionEvent (proj, 1, "provided")); + + } +*/ + } + + public static JComboBox getSpellCheckLanguagesSelector (final ActionListener onSelect, + final String defLang) + { + + final JComboBox spellcheckLang = new JComboBox (); + + if (onSelect != null) + { + + spellcheckLang.addItemListener (new ItemAdapter () + { + + public void itemStateChanged (ItemEvent ev) + { + + if (ev.getStateChange () != ItemEvent.SELECTED) + { + + return; + + } + + final String lang = spellcheckLang.getSelectedItem ().toString (); + + onSelect.actionPerformed (new ActionEvent (spellcheckLang, 1, lang)); + + } + + }); + + } + + // Get the languages supported by the spellchecker. + new Thread (new Runnable () + { + + public void run () + { + + String l = null; + + try + { + + l = Utils.getUrlFileAsString (new URL (Environment.getQuollWriterWebsite () + "/" + UserProperties.get (Constants.QUOLL_WRITER_SUPPORTED_LANGUAGES_URL_PROPERTY_NAME))); + + } catch (Exception e) { + + // Something gone wrong, so just add english. + l = Constants.ENGLISH; + + Environment.logError ("Unable to get language files url", + e); + + } + + StringTokenizer t = new StringTokenizer (l, + String.valueOf ('\n')); + + final Vector langs = new Vector (); + + while (t.hasMoreTokens ()) + { + + String lang = t.nextToken ().trim (); + + if (lang.equals ("")) + { + + continue; + + } + + langs.add (lang); + + } + + SwingUtilities.invokeLater (new Runnable () + { + + public void run () + { + + spellcheckLang.setModel (new DefaultComboBoxModel (langs)); + spellcheckLang.setSelectedItem (defLang); + spellcheckLang.setEnabled (true); + + } + + }); + + } + + }).start (); + + return spellcheckLang; + + } + + public static JComboBox getUILanguagesSelector (final ActionListener onSelect, + final String defLang) + { + + final JComboBox uiLangs = new JComboBox (); + uiLangs.setEnabled (false); + + if (onSelect != null) + { + + uiLangs.addItemListener (new ItemAdapter () + { + + public void itemStateChanged (ItemEvent ev) + { + + if (ev.getStateChange () != ItemEvent.SELECTED) + { + + return; + + } + + final String lang = uiLangs.getSelectedItem ().toString (); + + onSelect.actionPerformed (new ActionEvent (uiLangs, 1, lang)); + + } + + }); + + } + + new Thread (new Runnable () + { + + public void run () + { + + String l = null; + + Collection ls = null; + + try + { + + l = Utils.getUrlFileAsString (new URL (Environment.getQuollWriterWebsite () + "/" + UserProperties.get (Constants.QUOLL_WRITER_AVAILABLE_UI_LANGUAGE_STRINGS_URL_PROPERTY_NAME) + "?version=" + Environment.getQuollWriterVersion ().toString ())); + + ls = (Collection) JSONDecoder.decode (l); + + } catch (Exception e) { + + // Something gone wrong, so just add our local langs. + + ls = new LinkedHashSet<> (); + + Environment.logError ("Unable to get the ui language strings files url", + e); + + } + + final Map objs = new LinkedHashMap<> (); + + Set langIds = new LinkedHashSet<> (); + + try + { + + // Add in any user generated ones. + for (UILanguageStrings _ls : UILanguageStringsManager.getAllUserUILanguageStrings (Environment.getQuollWriterVersion ())) + { + + langIds.add ("user-" + _ls.getId ()); + objs.put ("user-" + _ls.getId (), + _ls.getNativeName () + " (Created by you)"); + + } + + } catch (Exception e) { + + Environment.logError ("Unable to get the user ui language strings", + e); + + } + + // Add our local ones. + Set uistrs = null; + + try + { + + uistrs = UILanguageStringsManager.getAllUILanguageStrings (Environment.getQuollWriterVersion ()); + + } catch (Exception e) { + + Environment.logError ("Unable to get local ui language strings", + e); + + } + + String format = "%1$s (%2$s, %3$s%%)"; + int s = 0; + UILanguageStrings enStrs = null; + + try + { + enStrs = UILanguageStringsManager.getUserUIEnglishLanguageStrings (Environment.getQuollWriterVersion ()); + s = UILanguageStringsManager.getUserUIEnglishLanguageStrings (Environment.getQuollWriterVersion ()).getAllTextValues ().size (); + + } catch (Exception e) { + + Environment.logError ("Unable to get english ui language strings count.", + e); + + } + + for (UILanguageStrings uistr : uistrs) + { + + int c = uistr.getAllTextValues ().size (); + + langIds.add (uistr.getId ()); + objs.put (uistr.getId (), String.format (format, + uistr.getNativeName (), + uistr.getLanguageName (), + Environment.formatNumber (Utils.getPercent (c, s)))); + + } + + // English is always available. + Map data = new HashMap (); + ls.add (data); + data.put ("id", UILanguageStrings.ENGLISH_ID); + data.put ("nativename", Constants.ENGLISH); + + Iterator iter = ls.iterator (); + + while (iter.hasNext ()) + { + + Map m = (Map) iter.next (); + + String id = (String) m.get ("id"); + + if (!id.equals (UILanguageStrings.ENGLISH_ID)) + { + + int c = 100; + + Object v = m.get ("strcount"); + + if (v != null) + { + + if (v instanceof Number) + { + + c = ((Number) v).intValue (); + + } else { + + try + { + + c = Integer.parseInt (m.get ("strcount").toString ()); + + } catch (Exception e) { + + // Ignore + + } + + } + + } + + objs.put (id, String.format (format, + m.get ("nativename").toString (), + m.get ("languagename"), + Environment.formatNumber (Utils.getPercent (c, s)))); + + } else { + + objs.put (id, m.get ("nativename").toString ()); + + } + + langIds.add (id); + + } + + final Vector langs = new Vector (langIds); + + UIUtils.doLater (e -> + { + + uiLangs.setRenderer (new DefaultListCellRenderer () + { + + @Override + public Component getListCellRendererComponent (JList list, + Object val, + int index, + boolean sel, + boolean hasFocus) + { + + super.getListCellRendererComponent (list, + val, + index, + sel, + hasFocus); + + if (val == null) + { + + return this; + + } + + String name = objs.get (val.toString ()); + + this.setText (name); + + return this; + + } + + }); + + uiLangs.setModel (new DefaultComboBoxModel (langs)); + uiLangs.setSelectedItem (defLang); + uiLangs.setEnabled (true); + uiLangs.setMaximumSize (uiLangs.getPreferredSize ()); + + }); + + } + + }).start (); + + return uiLangs; + + } + + public static void showManageBackups (final ProjectInfo proj, + final AbstractViewer viewer) + { + + String popupName = "managebackups" + proj.getId (); + QPopup popup = viewer.getNamedPopup (popupName); + + if (popup == null) + { + + popup = UIUtils.createClosablePopup (getUIString (backups,show, LanguageStrings.popup,title), + //"Current Backups", + Environment.getIcon (Constants.SNAPSHOT_ICON_NAME, + Constants.ICON_POPUP), + null); + + BackupsManager bm = null; + + try + { + + bm = new BackupsManager (viewer, + proj); + bm.init (); + + } catch (Exception e) { + + Environment.logError ("Unable to show backups manager", + e); + + UIUtils.showErrorMessage (viewer, + getUIString (backups,show,actionerror)); + //"Unable to show backups manager, please contact Quoll Writer support for assistance."); + + return; + + } + + bm.setSize (new Dimension (UIUtils.getPopupWidth () - 20, + bm.getPreferredSize ().height)); + bm.setBorder (UIUtils.createPadding (10, 10, 10, 10)); + + popup.setRemoveOnClose (false); + popup.setContent (bm); + + popup.setDraggable (viewer); + + popup.resize (); + + viewer.showPopupAt (popup, + UIUtils.getCenterShowPosition (viewer, + popup), + false); + + viewer.addNamedPopup (popupName, + popup); + + } else { + + popup.setVisible (true); + popup.toFront (); + + } + + Environment.fireUserProjectEvent (viewer, + ProjectEvent.Type.backups, + ProjectEvent.Action.show); + + } + + public static void showCreateBackup (final Project proj, + final String filePassword, + final AbstractViewer viewer) + { + + UIUtils.showCreateBackup (Environment.getProjectInfo (proj), + filePassword, + viewer); + + } + + public static void showCreateBackup (final ProjectInfo proj, + final String filePassword, + final AbstractViewer viewer) + { + + UIUtils.createQuestionPopup (viewer, + getUIString (backups,_new,popup,title), + //"Create a Backup", + Constants.SNAPSHOT_ICON_NAME, + String.format (getUIString (backups,_new,popup,text), + //"Please confirm you wish to create a backup of {project} %s.", + proj.getName ()), + getUIString (backups,_new,popup,buttons,confirm), + //"Yes, create it", + getUIString (backups,_new,popup,buttons,cancel), + //null, + new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + try + { + + File f = null; + +/* +TODO Moved to BackupsManager. + File f = Environment.createBackupForProject (proj, + false); +*/ + Box b = new Box (BoxLayout.Y_AXIS); + + JTextPane m = UIUtils.createHelpTextPane (String.format (getUIString (backups,_new,confirmpopup,text), + //"A backup has been created and written to:\n\n %s", + f.getParentFile ().toURI ().toString (), + f), + viewer); + + m.setSize (new Dimension (UIUtils.getPopupWidth () - 20, + m.getPreferredSize ().height)); + m.setBorder (null); + + b.add (m); + + b.add (Box.createVerticalStrut (10)); + + JLabel l = UIUtils.createClickableLabel (getUIString (backups,_new,confirmpopup,labels,view), + //"Click to view the backups", + Environment.getIcon (Constants.SNAPSHOT_ICON_NAME, + Constants.ICON_MENU), + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + UIUtils.showManageBackups (proj, + viewer); + + } + + }); + + b.add (l); + + UIUtils.showMessage ((PopupsSupported) viewer, + getUIString (backups,_new,confirmpopup,title), + //"Backup created", + b); + + } catch (Exception e) + { + + Environment.logError ("Unable to create backup of project: " + + proj, + e); + + UIUtils.showErrorMessage (viewer, + getUIString (backups,_new,actionerror)); + //"Unable to create backup."); + + } + + } + + }, + null, + null, + null); + + } + + public static void downloadDictionaryFiles (String lang, + final AbstractViewer parent, + final ActionListener onComplete) + { + + if (UILanguageStrings.isEnglish (lang)) + { + + lang = Constants.ENGLISH; + + } + + final String langOrig = lang; + final String language = lang; + + String fileLang = lang; + + // Legacy, if the user doesn't have the language file but DOES have a thesaurus then just + // download the English-dictionary-only.zip. + if ((UILanguageStrings.isEnglish (lang)) + && + (!Files.exists (DictionaryProvider.getDictionaryFilePath (lang))) + && + (Environment.hasSynonymsDirectory (lang)) + ) + { + + fileLang = "English-dictionary-only"; + + } + + URL url = null; + + try + { + + url = new URL (Environment.getQuollWriterWebsite () + "/" + Utils.replaceString (UserProperties.get (Constants.QUOLL_WRITER_LANGUAGE_FILES_URL_PROPERTY_NAME), + "[[LANG]]", + Utils.replaceString (fileLang, + " ", + "%20"))); + + } catch (Exception e) { + + Environment.logError ("Unable to download language files, cant create url", + e); + + UIUtils.showErrorMessage (parent, + getUIString (dictionary,download,actionerror)); + //"Unable to download language files"); + + return; + + } + + Environment.logDebugMessage ("Downloading language file(s) from: " + url + ", for language: " + lang); + + File _file = null; + + // Create a temp file for it. + try + { + + _file = File.createTempFile ("quollwriter-language-" + fileLang, + null); + + } catch (Exception e) { + + Environment.logError ("Unable to download language files, cant create temp file", + e); + + UIUtils.showErrorMessage (parent, + getUIString (dictionary,download,actionerror)); + //"Unable to download language files"); + + return; + + } + + _file.deleteOnExit (); + + final File file = _file; + + Box b = new Box (BoxLayout.Y_AXIS); + + final JTextPane htmlP = UIUtils.createHelpTextPane (String.format (getUIString (dictionary,download,notification), + //"The language files for %s are now being downloaded.", + language), + parent); + htmlP.setBorder (null); + htmlP.setBackground (null); + htmlP.setOpaque (false); + htmlP.setAlignmentX (Component.LEFT_ALIGNMENT); + + b.add (htmlP); + b.add (Box.createVerticalStrut (10)); + + final JProgressBar prog = new JProgressBar (0, 100); + + prog.setPreferredSize (new Dimension (500, 25)); + prog.setMaximumSize (new Dimension (500, 25)); + prog.setAlignmentX (Component.LEFT_ALIGNMENT); + + b.add (prog); + + final Notification n = parent.addNotification (b, + Constants.DOWNLOAD_ICON_NAME, + -1, + null); + + final ActionListener removeNotification = new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + n.removeNotification (); + + } + }; + + final UrlDownloader downloader = new UrlDownloader (url, + file, + new DownloadListener () + { + + @Override + public void onStop () + { + + } + + public void handleError (Exception e) + { + + UIUtils.doLater (removeNotification); + + Environment.logError ("Unable to download language files", + e); + + UIUtils.showErrorMessage (parent, + getUIString (dictionary,download,actionerror)); + //"A problem has occurred while downloading the language files for " + langOrig + ".

    Please contact Quoll Writer support for assistance."); + + } + + public void progress (final int downloaded, + final int total) + { + + UIUtils.doLater (new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + int val = (int) (((double) downloaded / (double) total) * 100); + + prog.setValue (val); + + } + + }); + + } + + public void finished (int total) + { + + prog.setValue (100); + prog.setIndeterminate (true); + + new Thread (new Runner () + { + + public void run () + { + + // Now extract the file into the relevant directory. + try + { + + Utils.extractZipFile (file, + Environment.getUserQuollWriterDirPath ().toFile ()); + + } catch (Exception e) { + + Environment.logError ("Unable to extract language zip file: " + + file + + " to: " + + Environment.getUserQuollWriterDirPath (), + e); + + UIUtils.showErrorMessage (parent, + getUIString (dictionary,download,actionerror)); + + return; + + } finally { + + file.delete (); + + } + + if (onComplete != null) + { + + UIUtils.doLater (new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + prog.setIndeterminate (false); + + onComplete.actionPerformed (new ActionEvent (parent, 0, langOrig)); + + } + + }); + + } + + UIUtils.doLater (removeNotification); + + } + + }).start (); + + } + + }); + + downloader.start (); + + n.addCancelListener (new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + downloader.stop (); + + file.delete (); + + } + + }); + + } + + public static Form createForm (Set items) + { + + return new Form (Form.Layout.stacked, + items, + (Set) null); + + } + + public static Form createForm (Set items, + Map buttons) + { + + return new Form (Form.Layout.stacked, + items, + buttons); + + } + + public static Form createForm (Set items, + Set buttons) + { + + return new Form (Form.Layout.stacked, + items, + buttons); + + } + + public static void showAddNewProject (AbstractViewer viewer, + Point showAt, + ActionListener onCreate) + { + + final QPopup popup = UIUtils.createClosablePopup (getUIString (newproject, LanguageStrings.popup,title), + //"Create a new {project}", + Environment.getIcon (Constants.ADD_ICON_NAME, + Constants.ICON_POPUP), + null); + + Box content = new Box (BoxLayout.Y_AXIS); + + content.add (UIUtils.createHelpTextPane (getUIString (newproject, LanguageStrings.popup,text), + //"To create a new {Project} enter the name below, select the directory it should be saved to and press the Create button.", + null)); + + final NewProjectPanel newProjPanel = new NewProjectPanel (); + + JComponent cp = newProjPanel.createPanel (popup, + popup.getCloseAction (), + true, + popup.getCloseAction (), + true); + + content.add (cp); + + content.setBorder (UIUtils.createPadding (10, 10, 10, 10)); + + content.setPreferredSize (new Dimension (UIUtils.getPopupWidth (), + content.getPreferredSize ().height)); + + popup.setContent (content); + + viewer.showPopupAt (popup, + (showAt != null ? showAt : UIUtils.getCenterShowPosition (viewer, + popup)), + false); + + popup.resize (); + + popup.setDraggable (viewer); + + } + + public static JComponent getChapterInfoPreview (Chapter c, + String format, + AbstractProjectViewer viewer) + { + + // If there is no key or null chapter then return. + if ((c == null) + || + (c.getKey () == null) + ) + { + + return null; + + } + + String lastEd = ""; + + if (c.getLastModified () != null) + { + + lastEd = String.format (getUIString (project,sidebar,chapters,preview,lastedited), + //"Last edited: %s", + Environment.formatDate (c.getLastModified ())); + + } else { + + lastEd = getUIString (project,sidebar,chapters,preview,notedited); + //"Not yet edited."; + + } + + String text = format; + + if (text == null) + { + + text = UserProperties.get (Constants.CHAPTER_INFO_PREVIEW_FORMAT, + Constants.DEFAULT_CHAPTER_INFO_PREVIEW_FORMAT); + + } + + String nl = String.valueOf ('\n'); + + while (text.endsWith (nl)) + { + + text = text.substring (0, + text.length () - 1); + + } + + text = text.toLowerCase (); + + String desc = c.getDescriptionText (); + String descFirstLine = null; + + if ((desc == null) + || + (desc.length () == 0) + ) + { + + desc = getUIString (project,sidebar,chapters,preview,nodescription); + //"No description."; + descFirstLine = desc; + + } else { + + descFirstLine = new TextIterator (desc).getFirstSentence ().getText (); + + } + + String chapText = viewer.getCurrentChapterText (c); + + if (chapText != null) + { + + chapText = chapText.trim (); + + } else { + + chapText = ""; + + } + + if (chapText.length () > 0) + { + + chapText = new TextIterator (chapText).getFirstSentence ().getText (); + + } else { + + chapText = getUIString (project,sidebar,chapters,preview,emptychapter); + //"{Chapter} is empty."); + + } + + text = Utils.replaceString (text, + " ", + " "); + text = Utils.replaceString (text, + nl, + "
    "); + + text = Utils.replaceString (text, + Constants.DESCRIPTION_TAG, + desc); + + text = Utils.replaceString (text, + Constants.DESCRIPTION_FIRST_LINE_TAG, + descFirstLine); + + text = Utils.replaceString (text, + Constants.CHAPTER_FIRST_LINE_TAG, + chapText); + + ChapterCounts cc = viewer.getChapterCounts (c); + + if (cc == null) + { + + // Get the current text instead. + cc = new ChapterCounts (c.getChapterText ()); + + } + + text = Utils.replaceString (text, + Constants.WORDS_TAG, + String.format (getUIString (project,sidebar,chapters,preview,words), + //"%s words", + Environment.formatNumber (cc.getWordCount ()))); + + text = Utils.replaceString (text, + Constants.LAST_EDITED_TAG, + lastEd); + + int ep = c.getEditPosition (); + + if (c.isEditComplete ()) + { + + ep = 100; + + } else { + + if (ep > 0) + { + + if (ep > chapText.length () - 1) + { + + ep = chapText.length (); + + } + + ChapterCounts ecc = new ChapterCounts (chapText.substring (0, + ep)); + + ep = Utils.getPercent (ecc.getWordCount (), cc.getWordCount ()); + + } + + } + + if (ep < 0) + { + + ep = 0; + + } + + text = Utils.replaceString (text, + Constants.EDIT_COMPLETE_TAG, + String.format (getUIString (project,sidebar,chapters,preview,editcomplete), + //"%s%% complete", + Environment.formatNumber (ep))); + + if (text.contains (Constants.PROBLEM_FINDER_PROBLEM_COUNT_TAG)) + { + + text = Utils.replaceString (text, + Constants.PROBLEM_FINDER_PROBLEM_COUNT_TAG, + String.format (getUIString (project,sidebar,chapters,preview,problemcount), + //"%s problems", + Environment.formatNumber (viewer.getProblems (c).size ()))); + + } + + if (text.contains (Constants.SPELLING_ERROR_COUNT_TAG)) + { + + text = Utils.replaceString (text, + Constants.SPELLING_ERROR_COUNT_TAG, + String.format (getUIString (project,sidebar,chapters,preview,spellingcount), + //"%s spelling errors", + Environment.formatNumber (viewer.getSpellingErrors (c).size ()))); + + } + + ReadabilityIndices ri = viewer.getReadabilityIndices (c); + + if (ri == null) + { + + ri = new ReadabilityIndices (); + ri.add (c.getChapterText ()); + + } + + String na = getUIString (project,sidebar,chapters,preview,notapplicable); + + String GL = na; //"N/A"; + String RE = na; //"N/A"; + String GF = na; //"N/A"; + + if (cc.getWordCount () > Constants.MIN_READABILITY_WORD_COUNT) + { + + GL = Environment.formatNumber (Math.round (ri.getFleschKincaidGradeLevel ())); + RE = Environment.formatNumber (Math.round (ri.getFleschReadingEase ())); + GF = Environment.formatNumber (Math.round (ri.getGunningFogIndex ())); + + } + + text = Utils.replaceString (text, + Constants.READABILITY_TAG, + String.format (getUIString (project,sidebar,chapters,preview,readability), + //"GL: %s, RE: %s, GF: %s", + GL, + RE, + GF)); + + JEditorPane p = UIUtils.createHelpTextPane (text, + null); +/* + p.setSize (new Dimension (380, + 0)); + */ + p.setAlignmentX (Component.LEFT_ALIGNMENT); + + return p; + + } + + public static void showAddNewObjectType (AbstractViewer viewer) + { + + UserConfigurableObjectType utype = new UserConfigurableObjectType (); + + utype.setObjectTypeName (getUIString (userobjects,type,_new,defaults,names,singular)); + //"Widget"); + utype.setObjectTypeNamePlural (getUIString (userobjects,type,_new,defaults,names,plural)); + //"Widgets"); + utype.setLayout (null); + utype.setAssetObjectType (true); + /* + TODO + utype.setIcon24x24 (Environment.getIcon ("whats-new", + Constants.ICON_TITLE)); + utype.setIcon16x16 (Environment.getIcon ("whats-new", + Constants.ICON_SIDEBAR)); +*/ + // Name + ObjectNameUserConfigurableObjectTypeField nameF = new ObjectNameUserConfigurableObjectTypeField (); + + nameF.setFormName (getUIString (userobjects,type,_new,defaults,fields,name)); + //"Name"); + + //TODO Remove utype.addConfigurableField (nameF); + + // Description + ObjectDescriptionUserConfigurableObjectTypeField cdescF = new ObjectDescriptionUserConfigurableObjectTypeField (); + + cdescF.setSearchable (true); + cdescF.setFormName (getUIString (userobjects,type,_new,defaults,fields,description)); + //"Description"); + + // TODO Remove utype.addConfigurableField (cdescF); + + Wizard w = UserConfigurableObjectTypeEdit.getAsWizard (viewer, + utype); + + final QPopup p = UIUtils.createWizardPopup (getUIString (userobjects,type,_new,popup,title), + //"Add a new type of Object", + Constants.NEW_ICON_NAME, + null, + w); + w.setPreferredSize (new Dimension (UIUtils.getPopupWidth () - 20, + w.getPreferredSize ().height)); + + viewer.showPopupAt (p, + UIUtils.getCenterShowPosition (viewer, + p), + false); + p.setDraggable (viewer); + + UIUtils.doLater (new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + UIUtils.resizeParent (p); + + } + + }); + + + } + + public static void showObjectTypeEdit (UserConfigurableObjectType utype, + AbstractViewer viewer) + { + + final QPopup p = UIUtils.createClosablePopup (String.format (getUIString (userobjects,type,edit,popup,title), + //"Edit the %s information", + utype.getObjectTypeName ()), + Environment.getIcon (Constants.EDIT_ICON_NAME, + Constants.ICON_POPUP), + null); + + Box b = new Box (BoxLayout.Y_AXIS); + + b.setBorder (UIUtils.createPadding (10, 10, 10, 10)); + + JTextPane m = UIUtils.createHelpTextPane (String.format (getUIString (userobjects,type,edit,popup,text), + //"Use this popup to add or edit the fields, layout and information for your %s.", + utype.getObjectTypeNamePlural ()), + viewer); + + m.setSize (new Dimension (UIUtils.getPopupWidth () - 20, + m.getPreferredSize ().height)); + m.setBorder (null); + + b.add (m); + + b.add (Box.createVerticalStrut (5)); + + b.add (UserConfigurableObjectTypeEdit.getAsTabs (viewer, + utype)); + + JButton finishb = new JButton (getUIString (userobjects,type,edit,popup,buttons,finish)); + //"Finish"); + + finishb.addActionListener (new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + UIUtils.closePopupParent (p); + + } + + }); + + JButton[] fbuts = new JButton[] { finishb }; + + JPanel bp = UIUtils.createButtonBar2 (fbuts, + Component.CENTER_ALIGNMENT); + bp.setOpaque (false); + + bp.setAlignmentX (Component.LEFT_ALIGNMENT); + b.add (Box.createVerticalStrut (10)); + + b.add (bp); + + p.setContent (b); + + b.setPreferredSize (new Dimension (UIUtils.getPopupWidth (), + b.getPreferredSize ().height)); + + viewer.showPopupAt (p, + UIUtils.getCenterShowPosition (viewer, + p), + false); + p.setDraggable (viewer); + + } + + public static JButton createTagsMenuToolBarButton (final NamedObject obj, + final AbstractProjectViewer viewer) + { + + JButton b = UIUtils.createToolBarButton (Constants.TAG_ICON_NAME, + null, + null, + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + JPopupMenu tagMenu = new JPopupMenu (); + + Set allTags = null; + + try + { + + allTags = Environment.getAllTags (); + + } catch (Exception e) { + + Environment.logError ("Unable to get all tags", + e); + + return; + + } + + for (Tag t : allTags) + { + + final JCheckBox it = new JCheckBox (t.getName (), + obj.hasTag (t)); + it.setBorder (UIUtils.createPadding (3, 3, 3, 3)); + + it.addActionListener (new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + if (it.isSelected ()) + { + + obj.addTag (t); + + } else { + + obj.removeTag (t); + + } + + try + { + + viewer.saveObject (obj, + false); + + } catch (Exception e) { + + Environment.logError ("Unable to update object: " + + obj, + e); + + UIUtils.showErrorMessage (viewer, + getUIString (tags,actions,apply,actionerror)); + //"Unable to add/remove tag."); + + return; + + } + + viewer.reloadTreeForObjectType (TaggedObjectAccordionItem.ID_PREFIX + t.getKey ()); + + } + + }); + + tagMenu.add (it); + + } + + if (allTags.size () > 0) + { + + tagMenu.addSeparator (); + + } + + tagMenu.add (UIUtils.createMenuItem (getUIString (tags,popupmenu,_new), + //"Add New Tag(s)", + Constants.EDIT_ICON_NAME, + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + new AddNewTagActionHandler (obj, + viewer).actionPerformed (ev); + + } + + })); + + Component c = (Component) ev.getSource (); + + tagMenu.show (c, + c.getX (), + c.getY ()); + + } + + }); + + return b; + + } + + public static JMenu createTagsMenu (final NamedObject obj, + final AbstractProjectViewer viewer) + { + + JMenu tagMenu = new JMenu (getUIString (tags,popupmenu,title)); + //"Tags"); + + tagMenu.setIcon (Environment.getIcon (Constants.TAG_ICON_NAME, + Constants.ICON_MENU)); + + Set allTags = null; + + try + { + + allTags = Environment.getAllTags (); + + } catch (Exception e) { + + Environment.logError ("Unable to get all tags", + e); + + return tagMenu; + + } + + for (Tag t : allTags) + { + + final JCheckBox it = new JCheckBox (t.getName (), + obj.hasTag (t)); + it.setBorder (UIUtils.createPadding (3, 3, 3, 3)); + + it.addActionListener (new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + if (it.isSelected ()) + { + + obj.addTag (t); + + } else { + + obj.removeTag (t); + + } + + try + { + + viewer.saveObject (obj, + false); + + } catch (Exception e) { + + Environment.logError ("Unable to update object: " + + obj, + e); + + UIUtils.showErrorMessage (viewer, + getUIString (tags,actions,apply,actionerror)); + //"Unable to add/remove tag."); + + return; + + } + + viewer.reloadTreeForObjectType (TaggedObjectAccordionItem.ID_PREFIX + t.getKey ()); + + } + + }); + + tagMenu.add (it); + + } + + if (allTags.size () > 0) + { + + tagMenu.addSeparator (); + + } + + tagMenu.add (UIUtils.createMenuItem (getUIString (tags,popupmenu,_new), + //"Add New Tag(s)", + Constants.ADD_ICON_NAME, + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + new AddNewTagActionHandler (obj, + viewer).actionPerformed (ev); + + } + + })); + + return tagMenu; + + } + + public static void showEditUILanguageStringsSelectorPopup (final AbstractViewer viewer) + { + + Set objs = null; + + try + { + + objs = UILanguageStringsManager.getAllUserUILanguageStrings (); + + } catch (Exception e) { + + Environment.logError ("Unable to get all user language strings.", + e); + + UIUtils.showErrorMessage (viewer, + getUIString (uilanguage,edit,actionerror)); + + return; + + } + + if (objs.size () == 0) + { + + UIUtils.showMessage ((PopupsSupported) viewer, + getUIString (uilanguage,edit,novalue,title), + getUIString (uilanguage,edit,novalue,text)); + + return; + + } + + UIUtils.showObjectSelectPopup (objs, + viewer, + getUIString (uilanguage,edit,popup,title), + new DefaultListCellRenderer () + { + + @Override + public Component getListCellRendererComponent (JList list, + Object value, + int index, + boolean isSelected, + boolean cellHasFocus) + { + + UILanguageStrings obj = (UILanguageStrings) value; + + JLabel l = (JLabel) super.getListCellRendererComponent (list, + value, + index, + isSelected, + cellHasFocus); + + l.setText (obj.getName () + " (" + obj.getQuollWriterVersion ().toString () + ")"); + + l.setFont (l.getFont ().deriveFont (UIUtils.getScaledFontSize (14)).deriveFont (Font.PLAIN)); +/* + l.setIcon (Environment.getObjectIcon (obj, + Constants.ICON_NOTIFICATION)); + */ + l.setBorder (UIUtils.createBottomLineWithPadding (5, 5, 5, 5)); + + if (cellHasFocus) + { + + l.setBackground (UIUtils.getHighlightColor ()); + + } + + return l; + + } + + }, + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + final UILanguageStrings ls = (UILanguageStrings) ev.getSource (); + + UILanguageStringsManager.editUILanguageStrings (ls, + ls.getQuollWriterVersion ()); + + } + + }, + true, + null); + + } + + public static void showAddNewUILanguageStringsPopup (final AbstractViewer viewer) + { + + java.util.List prefix = Arrays.asList (uilanguage,_new,popup); + + QPopup popup = UIUtils.createTextInputPopup (viewer, + getUIString (prefix,title), + //"Enter the language name", + Constants.ADD_ICON_NAME, + getUIString (prefix,text), + //"Enter the name of the language you want to create the strings for.", + getUIString (prefix,buttons,create), + //"Create", + getUIString (prefix,buttons,cancel), + //"Cancel", + null, + new ValueValidator () + { + + @Override + public String isValid (String v) + { + + if ((v == null) + || + (v.trim ().length () == 0) + ) + { + + return "Please enter the language name"; + + } + + return null; + + } + + }, + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + String v = ev.getActionCommand (); + + UILanguageStrings ls = new UILanguageStrings (UILanguageStringsManager.getDefaultUILanguageStrings ()); + ls.setNativeName (v); + ls.setUser (true); + + try + { + + new LanguageStringsEditor (ls).init (); + + } catch (Exception e) { + + Environment.logError ("Unable to create language strings editor", + e); + + UIUtils.showErrorMessage (viewer, + "Unable to create strings editor."); + + } + + } + + }, + null, + null); + + } + + public static void showAddNewWebsiteLanguageStringsPopup (final AbstractViewer viewer) + { + + java.util.List prefix = Arrays.asList (websiteuilanguage,_new,popup); + + QPopup popup = UIUtils.createTextInputPopup (viewer, + getUIString (prefix,title), + //"Enter the language name", + Constants.ADD_ICON_NAME, + getUIString (prefix,text), + //"Enter the name of the language you want to create the strings for.", + getUIString (prefix,buttons,create), + //"Create", + getUIString (prefix,buttons,cancel), + //"Cancel", + null, + new ValueValidator () + { + + @Override + public String isValid (String v) + { + + if ((v == null) + || + (v.trim ().length () == 0) + ) + { + + return "Please enter the language name"; + + } + + return null; + + } + + }, + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + final String v = ev.getActionCommand (); + + try + { + + WebsiteLanguageStrings enStrs = WebsiteLanguageStringsManager.getWebsiteLanguageStringsFromServer (); + + WebsiteLanguageStringsManager.saveWebsiteLanguageStrings (enStrs); + + WebsiteLanguageStrings ls = new WebsiteLanguageStrings (enStrs); + ls.setNativeName (v); + ls.setUser (true); + + new WebsiteLanguageStringsEditor (ls).init (); + + } catch (Exception e) { + + Environment.logError ("Unable to create website language strings editor", + e); + + UIUtils.showErrorMessage (viewer, + "Unable to create strings editor."); + + } + + } + + }, + null, + null); + + } + + public static void showEditWebsiteLanguageStringsSelectorPopup (final AbstractViewer viewer) + { + + Set objs = null; + + try + { + + objs = WebsiteLanguageStringsManager.getAllWebsiteLanguageStrings (); + + } catch (Exception e) { + + Environment.logError ("Unable to get all user website language strings.", + e); + + UIUtils.showErrorMessage (viewer, + getUIString (uilanguage,edit,actionerror)); + + return; + + } + + if (objs.size () == 0) + { + + UIUtils.showMessage ((PopupsSupported) viewer, + getUIString (uilanguage,edit,novalue,title), + getUIString (uilanguage,edit,novalue,text)); + + return; + + } + + UIUtils.showObjectSelectPopup (objs, + viewer, + getUIString (uilanguage,edit,popup,title), + new DefaultListCellRenderer () + { + + @Override + public Component getListCellRendererComponent (JList list, + Object value, + int index, + boolean isSelected, + boolean cellHasFocus) + { + + AbstractLanguageStrings obj = (AbstractLanguageStrings) value; + + JLabel l = (JLabel) super.getListCellRendererComponent (list, + value, + index, + isSelected, + cellHasFocus); + + l.setText (obj.getDisplayName ()); + + l.setFont (l.getFont ().deriveFont (UIUtils.getScaledFontSize (14)).deriveFont (Font.PLAIN)); +/* + l.setIcon (Environment.getObjectIcon (obj, + Constants.ICON_NOTIFICATION)); + */ + l.setBorder (UIUtils.createBottomLineWithPadding (5, 5, 5, 5)); + + if (cellHasFocus) + { + + l.setBackground (UIUtils.getHighlightColor ()); + + } + + return l; + + } + + }, + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + final WebsiteLanguageStrings ls = (WebsiteLanguageStrings) ev.getSource (); + + WebsiteLanguageStringsManager.editWebsiteLanguageStrings (ls); + + } + + }, + true, + null); + + } + + public static Color getHighlightColor () + { + + // #DAE4FC + return new Color (218, + 228, + 252); + + } + + public static void scrollIntoView (JComponent c) + { + + if (c == null) + { + + return; + + } + + if (!(c.getParent () instanceof JComponent)) + { + + return; + + } + + JComponent parent = (JComponent) c.getParent (); + + if (!(parent instanceof JComponent)) + { + + return; + + } + + if (parent == null) + { + + return; + + } + + if (parent instanceof JViewport) + { + + parent = (JComponent) parent.getParent (); + + } + + parent.scrollRectToVisible (c.getBounds ()); + + } + +} diff --git a/src/com/quollwriter/ui/UserPropertyHandler.java b/src/main/java/com/quollwriter/ui/UserPropertyHandler.java similarity index 100% rename from src/com/quollwriter/ui/UserPropertyHandler.java rename to src/main/java/com/quollwriter/ui/UserPropertyHandler.java diff --git a/src/com/quollwriter/ui/ValueValidator.java b/src/main/java/com/quollwriter/ui/ValueValidator.java similarity index 100% rename from src/com/quollwriter/ui/ValueValidator.java rename to src/main/java/com/quollwriter/ui/ValueValidator.java diff --git a/src/com/quollwriter/ui/WarmupPromptSelect.java b/src/main/java/com/quollwriter/ui/WarmupPromptSelect.java similarity index 99% rename from src/com/quollwriter/ui/WarmupPromptSelect.java rename to src/main/java/com/quollwriter/ui/WarmupPromptSelect.java index 745b7786..5f98426b 100644 --- a/src/com/quollwriter/ui/WarmupPromptSelect.java +++ b/src/main/java/com/quollwriter/ui/WarmupPromptSelect.java @@ -503,7 +503,7 @@ public void actionPerformed (ActionEvent ev) v.init (); // Put it in the user's directory. - v.newProject (Environment.getUserQuollWriterDir (), + v.newProject (Environment.getUserQuollWriterDirPath ().toFile (), p, null); @@ -619,7 +619,7 @@ public void actionPerformed (ActionEvent ev) try { - WarmupsViewer v = (WarmupsViewer) Environment.getProjectViewer (p); + WarmupsViewer v = null; // TODO (WarmupsViewer) Environment.getProjectViewer (p); v.addNewWarmup (w); diff --git a/src/com/quollwriter/ui/WarmupsAccordionItem.java b/src/main/java/com/quollwriter/ui/WarmupsAccordionItem.java similarity index 99% rename from src/com/quollwriter/ui/WarmupsAccordionItem.java rename to src/main/java/com/quollwriter/ui/WarmupsAccordionItem.java index 47b7e892..cc16b700 100644 --- a/src/com/quollwriter/ui/WarmupsAccordionItem.java +++ b/src/main/java/com/quollwriter/ui/WarmupsAccordionItem.java @@ -22,7 +22,7 @@ public class WarmupsAccordionItem extends ProjectObjectsAccordionItem +{ + + private WebsiteLanguageStrings prevEnglishStrings = null; + + public WebsiteLanguageStringsEditor (WebsiteLanguageStrings userStrings) + throws Exception + { + + super (userStrings); + + } + + @Override + public void onForwardLabelClicked () + throws Exception + { + + if ((this.nodeFilter != null) + && + (this.prevEnglishStrings != null) + ) + { + + this.showAllStrings (); + + this.showForwardLabel (String.format ("Click to show what's changed/new between version %1$s and %2$s.", + this.baseStrings.getStringsVersion (), + this.prevEnglishStrings.getStringsVersion ())); + + } else { + + this.limitViewToPreviousVersionDiff (); + + } + + } + + @Override + public void tryOut () + { + + final WebsiteLanguageStringsEditor _this = this; + + try + { + + this.save (); + + } catch (Exception e) { + + Environment.logError ("Unable to save: " + this.userStrings, + e); + + UIUtils.showErrorMessage (this, + "Unable to save strings."); + + return; + + } + + int c = 0; + + for (Value uv : this.userStrings.getAllValues ()) + { + + Value bv = this.baseStrings.getValue (uv.getId ()); + + if (bv == null) + { + + // The string is present in the user strings but not the base! + Environment.logError ("Found string: " + uv.getId () + " present in user strings but not base."); + + continue; + + } + + c += uv.getErrors (this).size (); + + } + + if (c > 0) + { + + UIUtils.showMessage ((PopupsSupported) this, + "Errors found in strings", + String.format ("Sorry, there are %s errors that must be corrected before you can submit the strings.", + Environment.formatNumber (c))); + + return; + + } + + Path _outputFile = null; + + try + { + + _outputFile = _this.createUploadFile (); + + } catch (Exception e) + { + + Environment.logError ("Unable to create upload file for strings: " + _this.userStrings, + e); + + UIUtils.showErrorMessage (_this, + "Unable to upload strings."); + + return; + + } + + final Path outputFile = _outputFile; + + Map headers = new HashMap<> (); + + String submitterid = UserProperties.get (Constants.WEBSITE_LANGUAGE_STRINGS_SUBMITTER_ID_PROPERTY_NAME); + + if (submitterid != null) + { + + headers.put (Constants.WEBSITE_LANGUAGE_STRINGS_SUBMITTER_ID_HEADER_NAME, + submitterid); + + } + + UIUtils.showMessage (this, + "Your strings/images will now be uploaded to the server. Note: your strings/images will be deleted after 2 hours."); + + URL u = null; + + try + { + + u = new URL (Environment.getQuollWriterWebsite () + UserProperties.get (Constants.TRYOUT_WEBSITE_LANGUAGE_STRINGS_URL_PROPERTY_NAME)); + + final ProgressPopup pp = new ProgressPopup (_this, + "Uploading", + "up", + "Uploading strings/images, please wait..."); + + _this.showPopupAt (pp, + UIUtils.getCenterShowPosition (_this, + pp), + false); + + pp.setDraggable (_this); + + Utils.postToURL (u, + headers, + outputFile, + // On success + (res, retCode) -> + { + + pp.removeFromParent (); + + try + { + + Files.deleteIfExists (outputFile); + + } catch (Exception e) { + + Environment.logError ("Unable to delete temp file: " + outputFile, + e); + + } + + Map m = (Map) JSONDecoder.decode (res); + + res = (String) m.get ("result"); + + String sid = (String) m.get ("testid"); + + try + { + + _this.saveToFile (); + + } catch (Exception e) { + + Environment.logError ("Unable to save strings file: " + + _this.userStrings, + e); + + } + + String url = Environment.getQuollWriterWebsite () + "/" + sid + "/"; + + UIUtils.showMessage ((PopupsSupported) _this, + "Strings uploaded", + String.format ("Your strings have been uploaded and are ready to be tested. A browser will now be opened for the {QW} website.

    You can also click here to try out your translation.", + url)); + + UIUtils.openURL (_this, + url); + + }, + // On error + (res, retCode) -> + { + + pp.removeFromParent (); + + try + { + + Files.deleteIfExists (outputFile); + + } catch (Exception e) { + + Environment.logError ("Unable to delete temp file: " + outputFile, + e); + + } + + Map m = (Map) JSONDecoder.decode (res); + + res = (String) m.get ("reason"); + + // Get the errors. + UIUtils.showErrorMessage (_this, + "Unable to submit the strings, reason:
    • " + res + "
    "); + + }, + // On failure + (exp) -> + { + + pp.removeFromParent (); + + // Get the errors. + UIUtils.showErrorMessage (_this, + "Unable to submit the strings, reason:
    • " + exp.getMessage () + "
    "); + + }, + // Updater + (eev) -> + { + + pp.update (eev.getPercent ()); + + }); + + } catch (Exception e) { + + Environment.logError ("Unable to post to the url.", + e); + + UIUtils.showErrorMessage (_this, + "Unable to upload strings."); + + } + + } + + @Override + public void init () + throws Exception + { + + final WebsiteLanguageStringsEditor _this = this; + + super.init (); + + this.updateTitle (); + + this.prevEnglishStrings = WebsiteLanguageStringsManager.getPreviousEnglishWebsiteLanguageStrings (); + + if (this.prevEnglishStrings != null) + { + + this.showForwardLabel (String.format ("Click to show what's changed/new between version %1$s and %2$s.", + this.baseStrings.getStringsVersion (), + this.prevEnglishStrings.getStringsVersion ())); + + } + + // Check to see if a new version of the default strings is available. + Environment.schedule (new Runnable () + { + + @Override + public void run () + { + + WebsiteLanguageStrings enStrs = null; + + try + { + + enStrs = WebsiteLanguageStringsManager.getWebsiteLanguageStringsFromServer (); + + } catch (Exception e) { + + Environment.logError ("Unable to get English Website UI language strings", + e); + + UIUtils.showErrorMessage (_this, + "Unable to get English Website UI language strings."); + + return; + + } + + if (enStrs.getStringsVersion () == _this.userStrings.getDerivedFrom ().getStringsVersion ()) + { + + // Server still has same version. + return; + + } + + try + { + + // Move the existing strings file to a previous veersion. + WebsiteLanguageStringsManager.moveWebsiteLanguageStringsToPrevious (); + + } catch (Exception e) { + + Environment.logError ("Unable to move English Website UI language strings to previous file.", + e); + + UIUtils.showErrorMessage (_this, + "Unable to get English Website UI language strings."); + + return; + + } + + try + { + + // Save the new strings away. + WebsiteLanguageStringsManager.saveWebsiteLanguageStrings (enStrs); + + } catch (Exception e) { + + Environment.logError ("Unable to save new English Website UI language strings", + e); + + UIUtils.showErrorMessage (_this, + "Unable to save new English Website UI language strings."); + + return; + + } + + final WebsiteLanguageStrings _enStrs = enStrs; + + Box content = new Box (BoxLayout.Y_AXIS); + + content.add (UIUtils.createHelpTextPane (String.format ("A new version of the website language strings is available.
    You can view the changes and submit an update to your strings."), + _this)); + + content.add (Box.createVerticalStrut (5)); + + JButton b = UIUtils.createButton ("View the changes"); + + content.add (b); + + // Add a notification. + final Notification n = _this.addNotification (content, + Constants.INFO_ICON_NAME, + -1); + + b.addActionListener (new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + WebsiteLanguageStrings uls = null; + + try + { + + uls = WebsiteLanguageStringsManager.getWebsiteLanguageStrings (_this.userStrings.getId ()); + + } catch (Exception e) { + + Environment.logError ("Unable to get user strings: " + _this.userStrings.getId (), + e); + + UIUtils.showErrorMessage (null, + getUIString (uilanguage,edit,actionerror)); + + return; + + } + + if (uls != null) + { +/* + // Open these instead. + WebsiteLanguageStringsEditor lse = WebsiteLanguageStringsManager.editWebsiteLanguageStrings (uls); + + if (lse == _this) + { + + _this.baseStrings = _enStrs; + + } + + try + { + + lse.limitViewToPreviousVersionDiff (); + + } catch (Exception e) { + + Environment.logError ("Unable to update view", + e); + + UIUtils.showErrorMessage (_this, + "Unable to update view"); + + return; + + } +*/ + _this.removeNotification (n); + + return; + + } + + _this.showChanges (_enStrs); + + _this.removeNotification (n); + + } + + }); + + UIUtils.doLater (e -> + { + + _this.validate (); + _this.repaint (); + + }); + + } + + }, + 5, + -1); + + } + + public void limitViewToPreviousVersionDiff () + throws Exception + { + + try + { + + this.save (); + + } catch (Exception e) { + + Environment.logError ("Unable to save", + e); + + UIUtils.showErrorMessage (this, + "Unable to update view."); + + return; + + } + + final WebsiteLanguageStrings basels = this.baseStrings; + + final WebsiteLanguageStrings prevbasels = WebsiteLanguageStringsManager.getPreviousEnglishWebsiteLanguageStrings (); + + if (prevbasels == null) + { + + // No strings. + return; + + } + + this.prevEnglishStrings = prevbasels; + + this.setNodeFilter (new Filter () + { + + @Override + public boolean accept (Node n) + { + + Node pn = prevbasels.getNode (n.getId ()); + + // Does the node exist in the current base strings but not the previous? + if (pn == null) + { + + // This is a new node. + return true; + + } + + // It exists, but has it changed? + if ((n instanceof Value) + && + (!(pn instanceof Value)) + ) + { + + // Node type changed. + return true; + + } + + if ((pn instanceof Value) + && + (!(n instanceof Value)) + ) + { + + // Node type changed. + return true; + + } + + if ((pn instanceof TextValue) + && + (n instanceof TextValue) + ) + { + + TextValue pnv = (TextValue) pn; + TextValue nv = (TextValue) n; + + // Value changed? + if (pnv.getRawText ().equals (nv.getRawText ())) + { + + return false; + + } + + } + + return true; + + } + + }); + + this.showForwardLabel (String.format ("Click to show all the strings for version %1$s.", + this.baseStrings.getStringsVersion ())); +/* + this.showForwardLabel (String.format ("Click to show what's changed/new between version %s and %s.", + Environment.getQuollWriterVersion ().toString (), + this.userStrings.getQuollWriterVersion ().toString ())); +*/ + + } + + public void showChanges (WebsiteLanguageStrings newls) + { + + try + { + + WebsiteLanguageStringsManager.saveWebsiteLanguageStrings (newls); + + WebsiteLanguageStringsManager.saveWebsiteLanguageStrings (this.userStrings); + + WebsiteLanguageStrings uls = WebsiteLanguageStringsManager.getWebsiteLanguageStrings (this.userStrings.getId ()); + + // Get a diff of the default to this new. + //WebsiteLanguageStringsEditor lse = WebsiteLanguageStringsManager.editWebsiteLanguageStrings (uls); + + //lse.limitViewToPreviousVersionDiff (); + + } catch (Exception e) { + + Environment.logError ("Unable to show strings editor for: " + + newls, + e); + + UIUtils.showErrorMessage (this, + "Unable to show strings."); + + } + + } + + @Override + public Set getTitleHeaderControlIds () + { + + Set ids = new LinkedHashSet (); + + ids.add (SUBMIT_HEADER_CONTROL_ID); + ids.add (FIND_HEADER_CONTROL_ID); + ids.add (USE_HEADER_CONTROL_ID); + //ids.add (REPORT_BUG_HEADER_CONTROL_ID); + ids.add (HELP_HEADER_CONTROL_ID); + ids.add (SETTINGS_HEADER_CONTROL_ID); + + return ids; + + } + + @Override + public JComponent getTitleHeaderControl (String id) + { + + if (id == null) + { + + return null; + + } + + java.util.List prefix = Arrays.asList (allprojects,headercontrols,items); + + final WebsiteLanguageStringsEditor _this = this; + + JComponent c = null; + + if (id.equals (HELP_HEADER_CONTROL_ID)) + { + + c = UIUtils.createButton (Constants.HELP_ICON_NAME, + Constants.ICON_TITLE_ACTION, + "Click to view the help about editing your strings", + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + UIUtils.openURL (_this, + "help:websitelanguage"); + + } + + }); + + } + + if (c != null) + { + + return c; + + } + + return super.getTitleHeaderControl (id); + + } + + private Path createUploadFile () + throws Exception + { + + // Get the file, then send. + String t = JSONEncoder.encode (this.userStrings.getAsJSON ()); + + Map entries = new HashMap<> (); + entries.put ("/strings", t); + + for (ImageValue iv : this.userStrings.getAllImageValues ()) + { + + ImageValue bv = this.baseStrings.getImageValue (iv.getId ()); + + entries.put (BaseStrings.toId (bv.getId ()), + iv.getImageFile ()); + + } + + Path outputFile = Files.createTempFile ("qw-upload", + ".zip"); + + outputFile.toFile ().deleteOnExit (); + + Utils.createZipFile (outputFile, + entries); + + return outputFile; + + } + + @Override + public void submit (ActionListener onSuccess, + ActionListener onFailure) + { + + final WebsiteLanguageStringsEditor _this = this; + + try + { + + this.save (); + + } catch (Exception e) { + + Environment.logError ("Unable to save: " + this.userStrings, + e); + + UIUtils.showErrorMessage (this, + "Unable to save strings."); + + UIUtils.doLater (onFailure); + + return; + + } + + Set vals = this.userStrings.getAllValues (); + + if (vals.size () != this.baseStrings.getAllValues ().size ()) + { + + UIUtils.showMessage ((PopupsSupported) this, + "Strings/images required", + "Sorry, you must provide values for all strings and images."); + + UIUtils.doLater (onFailure); + + return; + + } + + int c = 0; + + for (Value uv : vals) + { + + Value bv = this.baseStrings.getValue (uv.getId ()); + + if (bv == null) + { + + // The string is present in the user strings but not the base! + //Environment.logError ("Found string: " + uv.getId () + " present in user strings but not base."); + + continue; + + } + + c += uv.getErrors (this).size (); + + } + + if (c > 0) + { + + UIUtils.showMessage ((PopupsSupported) this, + "Errors found in strings", + String.format ("Sorry, there are %s errors that must be corrected before you can submit the strings.", + Environment.formatNumber (c))); + + UIUtils.doLater (onFailure); + + return; + + } + + final String popupName = "submit"; + QPopup popup = this.getNamedPopup (popupName); + + if (popup == null) + { + + popup = UIUtils.createClosablePopup ("Submit your strings", + Environment.getIcon (Constants.UP_ICON_NAME, + Constants.ICON_POPUP), + null); + + final QPopup qp = popup; + + Box content = new Box (BoxLayout.Y_AXIS); + + JTextPane help = UIUtils.createHelpTextPane ("Complete the form below to submit your strings. All the values are required.

    Click here to view the language codes", + this); + + help.setBorder (null); + + content.add (help); + content.add (Box.createVerticalStrut (10)); + + final JLabel error = UIUtils.createErrorLabel (""); + error.setVisible (false); + error.setBorder (UIUtils.createPadding (0, 5, 5, 5)); + + content.add (error); + + Set items = new LinkedHashSet (); + + final TextFormItem nativelang = new TextFormItem ("Native Name (i.e. Espa\u00F1ol, Fran\u00E7ais, Deutsch)", + this.userStrings.getNativeName ()); + + items.add (nativelang); + + final TextFormItem langcode = new TextFormItem ("Language Code (ISO 639-1 2 letter code, i.e es)", + this.userStrings.getLanguageCode ()); + + items.add (langcode); + + final TextFormItem email = new TextFormItem ("Contact Email", + this.userStrings.getEmail ()); + + items.add (email); + + final JLabel tc = UIUtils.createClickableLabel ("View the Terms and Conditions for creating a translation", + Environment.getIcon (Constants.INFO_ICON_NAME, + Constants.ICON_CLICKABLE_LABEL), + Environment.getQuollWriterHelpLink ("websitelanguage-terms-and-conditions", + null)); + + final CheckboxFormItem tandc = new CheckboxFormItem (null, "I have read and agree to the Terms and Conditions"); + + if (this.userStrings.getStringsVersion () == 0) + { + + items.add (new AnyFormItem (null, tc)); + items.add (tandc); + + } + + ActionListener saveAction = new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + String em = email.getValue (); + + if (em == null) + { + + error.setText ("Please enter a valid email."); + error.setVisible (true); + qp.resize (); + qp.resize (); + + UIUtils.doLater (onFailure); + + return; + + } + + String nl = nativelang.getValue (); + + if (nl == null) + { + + error.setText ("Please enter the Name Language name."); + error.setVisible (true); + qp.resize (); + + UIUtils.doLater (onFailure); + + return; + + } + + String lc = langcode.getValue (); + + boolean show = false; + + if (lc == null) + { + + show = true; + + } else { + + lc = lc.trim ().toLowerCase (); + + if (lc.length () != 2) + { + + show = true; + + } else { + + if (!Character.isLetter (lc.charAt (0))) + { + + show = true; + + } + + if (!Character.isLetter (lc.charAt (1))) + { + + show = true; + + } + + } + + } + + if (show) + { + + error.setText ("Please enter a valid 2 letter ISO 639-1 language code."); + error.setVisible (true); + qp.resize (); + + UIUtils.doLater (onFailure); + + return; + + } + + if (WebsiteLanguageStrings.isEnglish (lc)) + { + + error.setText ("The {QW} already has an English translation!"); + error.setVisible (true); + qp.resize (); + + UIUtils.doLater (onFailure); + + return; + + } + + if (_this.userStrings.getAllValues ().size () == 0) + { + + error.setText ("No strings provided. Please provide at least 1 string for your translation."); + error.setVisible (true); + qp.resize (); + + UIUtils.doLater (onFailure); + + return; + + } + + if ((_this.userStrings.getStringsVersion () == 0) + && + (!tandc.isSelected ()) + ) + { + + error.setText ("To submit your strings you must agree to the Terms & Conditions, and please give them a quick read ;)"); + error.setVisible (true); + qp.resize (); + + UIUtils.doLater (onFailure); + + return; + + } + + _this.userStrings.setEmail (em); + _this.userStrings.setNativeName (nl); + _this.userStrings.setLanguageCode (lc); + + _this.updateTitle (); + + try + { + + _this.save (); + + } catch (Exception e) { + + Environment.logError ("Unable to save strings: " + _this.userStrings, + e); + + UIUtils.showErrorMessage (_this, + "Unable to save strings."); + + UIUtils.doLater (onFailure); + + return; + + } + + Path _outputFile = null; + + try + { + + _outputFile = _this.createUploadFile (); + + } catch (Exception e) + { + + Environment.logError ("Unable to create upload file for strings: " + _this.userStrings, + e); + + UIUtils.showErrorMessage (_this, + "Unable to upload strings."); + + UIUtils.doLater (onFailure); + + return; + + } + + final Path outputFile = _outputFile; + + Map headers = new HashMap<> (); + + String submitterid = UserProperties.get (Constants.WEBSITE_LANGUAGE_STRINGS_SUBMITTER_ID_PROPERTY_NAME); + + if (submitterid != null) + { + + headers.put (Constants.WEBSITE_LANGUAGE_STRINGS_SUBMITTER_ID_HEADER_NAME, + submitterid); + + } + + URL u = null; + + try + { + + qp.setVisible (false); + + final ProgressPopup pp = new ProgressPopup (_this, + "Uploading", + "up", + "Uploading strings/images, please wait..."); + + _this.showPopupAt (pp, + UIUtils.getCenterShowPosition (_this, + pp), + false); + + pp.setDraggable (_this); + + u = new URL (Environment.getQuollWriterWebsite () + UserProperties.getProperty (Constants.SUBMIT_WEBSITE_LANGUAGE_STRINGS_URL_PROPERTY_NAME)); + + Utils.postToURL (u, + headers, + outputFile, + // On success + (res, retCode) -> + { + + pp.removeFromParent (); + + try + { + + Files.deleteIfExists (outputFile); + + } catch (Exception e) { + + Environment.logError ("Unable to delete temp file: " + outputFile, + e); + + } + + Map m = (Map) JSONDecoder.decode (res); + + res = (String) m.get ("result"); + + String sid = (String) m.get ("submitterid"); + + UserProperties.set (Constants.WEBSITE_LANGUAGE_STRINGS_SUBMITTER_ID_PROPERTY_NAME, + sid); + + //_this.userStrings.setSubmitterId (sid); + _this.userStrings.setStringsVersion (((Number) m.get ("version")).intValue ()); + + try + { + + _this.saveToFile (); + + } catch (Exception e) { + + Environment.logError ("Unable to save strings file: " + + _this.userStrings, + e); + + UIUtils.showErrorMessage (_this, + "Your strings have been submitted to Quoll Writer support for review. However the associated local file, where the strings are kept on your machine, could not be updated."); + + UIUtils.doLater (onFailure); + + return; + + } + + if (_this.userStrings.getStringsVersion () == 1) + { + + UIUtils.showMessage ((PopupsSupported) _this, + "Strings submitted", + String.format ("Your strings have been submitted to Quoll Writer support for review.

    A confirmation email has been sent to %s. Please click on the link in that email to confirm your email address.

    Thank you for taking the time and the effort to create the strings, it is much appreciated!", + _this.userStrings.getEmail ())); + + } else { + + UIUtils.showMessage ((PopupsSupported) _this, + "Strings submitted", + String.format ("Thank you! Your strings have been updated to version %s and will be made available to visitors of the Quoll Writer website.

    Thank you for taking the time and effort to update the strings, it is much appreciated!", + Environment.formatNumber (_this.userStrings.getStringsVersion ()))); + + } + + qp.resize (); + qp.removeFromParent (); + + UIUtils.doLater (onSuccess); + + }, + // On error + (res, retCode) -> + { + + pp.removeFromParent (); + + try + { + + Files.deleteIfExists (outputFile); + + } catch (Exception e) { + + Environment.logError ("Unable to delete temp file: " + outputFile, + e); + + } + + Map m = (Map) JSONDecoder.decode (res); + + res = (String) m.get ("reason"); + + // Get the errors. + UIUtils.showErrorMessage (_this, + "Unable to submit the strings, reason:
    • " + res + "
    "); + + UIUtils.doLater (onFailure); + + }, + // On failure + (exp) -> + { + + pp.removeFromParent (); + + // Get the errors. + UIUtils.showErrorMessage (_this, + "Unable to submit the strings, reason:
    • " + exp.getMessage () + "
    "); + + UIUtils.doLater (onFailure); + + }, + // Updater + (eev) -> + { + + pp.update (eev.getPercent ()); + + }); + + } catch (Exception e) { + + Environment.logError ("Unable to post to the url.", + e); + + UIUtils.showErrorMessage (_this, + "Unable to upload strings."); + + UIUtils.doLater (onFailure); + + return; + + } + + } + + }; + + UIUtils.addDoActionOnReturnPressed (nativelang.getTextField (), + saveAction); + UIUtils.addDoActionOnReturnPressed (email.getTextField (), + saveAction); + + JButton save = UIUtils.createButton ("Submit", + saveAction); + JButton cancel = UIUtils.createButton ("Cancel", + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + qp.removeFromParent (); + _this.removeNamedPopup (popupName); + + } + + }); + + Set buttons = new LinkedHashSet (); + buttons.add (save); + buttons.add (cancel); + + Form f = new Form (Form.Layout.stacked, + items, + buttons); + + content.add (f); + + content.setSize (new Dimension (UIUtils.getPopupWidth () - 20, + content.getPreferredSize ().height)); + content.setBorder (UIUtils.createPadding (10, 10, 10, 10)); + + popup.setContent (content); + + popup.setDraggable (this); + + popup.setPopupName (popupName); + + this.addNamedPopup (popupName, + popup); + + //popup.resize (); + this.showPopupAt (popup, + UIUtils.getCenterShowPosition (this, + popup), + false); + + UIUtils.doLater (new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + //desc.grabFocus (); + qp.resize (); + + } + + }); + + } else { + + popup.setVisible (true); + popup.resize (); + + } + + } + + @Override + public String getViewerIcon () + { + + return Constants.EDIT_ICON_NAME; + + } + + @Override + public void fillSettingsPopup (JPopupMenu popup) + { + + //java.util.List prefix = Arrays.asList (allprojects,settingsmenu,items); + + final WebsiteLanguageStringsEditor _this = this; + + popup.add (this.createMenuItem ("Submit your strings", + Constants.UP_ICON_NAME, + new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + _this.submit (null, + null); + + } + + })); + + popup.add (this.createMenuItem ("Try out your strings", + Constants.PLAY_ICON_NAME, + new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + _this.tryOut (); + + } + + })); + + popup.add (this.createMenuItem ("Create a new translation", + Constants.NEW_ICON_NAME, + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + UIUtils.showAddNewWebsiteLanguageStringsPopup (_this); + + } + + })); + + popup.add (this.createMenuItem ("Edit a translation", + Constants.EDIT_ICON_NAME, + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + UIUtils.showEditWebsiteLanguageStringsSelectorPopup (_this); + + } + + })); + + popup.add (this.createMenuItem ("Delete", + Constants.DELETE_ICON_NAME, + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + try + { + + _this.delete (); + + } catch (Exception e) { + + Environment.logError ("Unable to delete strings: " + _this.userStrings.getId (), + e); + + UIUtils.showErrorMessage (_this, + "Unable to delete strings."); + + } + + } + + })); + + popup.add (this.createMenuItem ("Close", + Constants.CLOSE_ICON_NAME, + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + _this.close (true, + null); + + } + + })); + + popup.addSeparator (); + + popup.add (this.createMenuItem ("Open Project", + Constants.UP_ICON_NAME, + new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + Environment.showAllProjectsViewer (); + + } + + })); + + + } + + public WebsiteLanguageStrings getUserLanguageStrings () + { + + return this.userStrings; + + } + + @Override + public void delete () + throws Exception + { + + final WebsiteLanguageStringsEditor _this = this; + + QPopup qp = UIUtils.createPopup ("Delete the strings", + Constants.DELETE_ICON_NAME, + null, + true, + null); + + final Box content = new Box (BoxLayout.Y_AXIS); + + JComponent mess = UIUtils.createHelpTextPane ("Please confirm you wish to delete your strings. Enter Yes in the box below to confirm deletion.

    Warning! This is an irreverisble operation and cannot be undone. This will make your strings unavailable to {QW} users but will not remove it from anyone who has already downloaded the strings.", + this); + mess.setBorder (null); + mess.setSize (new Dimension (UIUtils.getPopupWidth () - 20, + mess.getPreferredSize ().height)); + + content.add (mess); + + content.add (Box.createVerticalStrut (10)); + + final JLabel error = UIUtils.createErrorLabel ("Please enter the word Yes."); + //"Please enter a value."); + + error.setVisible (false); + error.setBorder (UIUtils.createPadding (0, 0, 5, 0)); + + final JTextField text = UIUtils.createTextField (); + + text.setMinimumSize (new Dimension (300, + text.getPreferredSize ().height)); + text.setPreferredSize (new Dimension (300, + text.getPreferredSize ().height)); + text.setMaximumSize (new Dimension (Short.MAX_VALUE, + text.getPreferredSize ().height)); + text.setAlignmentX (Component.LEFT_ALIGNMENT); + + error.setAlignmentX (Component.LEFT_ALIGNMENT); + + content.add (error); + content.add (text); + + content.add (Box.createVerticalStrut (10)); + + JButton confirm = null; + JButton cancel = UIUtils.createButton ("No, keep them", + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + qp.removeFromParent (); + + } + + }); + + ActionListener confirmAction = new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + String mess = UIUtils.getYesValueValidator ().isValid (text.getText ().trim ()); + + if (mess != null) + { + + // Should probably wrap this in a + error.setText (mess); + + error.setVisible (true); + + // Got to be an easier way of doing this. + content.setPreferredSize (null); + + content.setPreferredSize (new Dimension (UIUtils.getPopupWidth (), + content.getPreferredSize ().height)); + + _this.showPopupAt (qp, + qp.getLocation (), + false); + + return; + + } + + String submitterid = UserProperties.get (Constants.WEBSITE_LANGUAGE_STRINGS_SUBMITTER_ID_PROPERTY_NAME); + + if ((submitterid != null) + && + // Has they been submitted? + (_this.userStrings.getStringsVersion () > 0) + ) + { + + URL u = null; + + try + { + + String p = UserProperties.get (Constants.DELETE_WEBSITE_LANGUAGE_STRINGS_URL_PROPERTY_NAME); + + p = Utils.replaceString (p, + Constants.ID_TAG, + _this.userStrings.getId ()); + + u = new URL (Environment.getQuollWriterWebsite () + p); + + } catch (Exception e) { + + Environment.logError ("Unable to construct the url for delete the website ui language strings.", + e); + + UIUtils.showErrorMessage (_this, + "Unable to delete strings."); + + return; + + } + + Map headers = new HashMap<> (); + + headers.put (Constants.WEBSITE_LANGUAGE_STRINGS_SUBMITTER_ID_HEADER_NAME, + submitterid); + + Utils.postToURL (u, + headers, + "bogus", + // On success + (res, retCode) -> + { + + String r = (String) JSONDecoder.decode (res); + + // Delete our local versions. + try + { + + WebsiteLanguageStringsManager.deleteWebsiteLanguageStrings (_this.userStrings); + + } catch (Exception e) { + + Environment.logError ("Unable to delete user strings: " + _this.userStrings, + e); + + UIUtils.showErrorMessage (_this, + "Unable to delete the strings."); + + qp.removeFromParent (); + + return; + + } + + WebsiteLanguageStringsEditor.super.close (true, + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + UIUtils.showMessage ((Component) null, + "Strings deleted", + "Your strings have been deleted. Please note: your images have not been deleted.

    Thank you for the time and effort you put in to create the strings, it is much appreciated!"); + + } + + }); + + }, + // On error + (res, retCode) -> + { + + Map m = (Map) JSONDecoder.decode (res); + + res = (String) m.get ("reason"); + + // Get the errors. + UIUtils.showErrorMessage (_this, + "Unable to submit the strings, reason:
    • " + res + "
    "); + + }, + // On failure + (exp) -> + { + + //Map m = (Map) JSONDecoder.decode ((String) ev.getSource ()); + + //String res = (String) m.get ("reason"); + + // Get the errors. + UIUtils.showErrorMessage (_this, + "Unable to delete the strings, reason:
    • " + exp.getMessage () + "
    "); + + }, + null); + + } else { + + // Not been submitted. + // Delete our local versions. + try + { + + WebsiteLanguageStringsManager.deleteWebsiteLanguageStrings (_this.userStrings); + + } catch (Exception e) { + + Environment.logError ("Unable to delete website strings: " + _this.userStrings, + e); + + UIUtils.showErrorMessage (_this, + "Unable to delete the strings."); + + qp.removeFromParent (); + + return; + + } + + // Close without saving. + WebsiteLanguageStringsEditor.super.close (true, + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + UIUtils.showMessage ((Component) null, + "Strings deleted", + "Your strings have been deleted."); + + } + + }); + + } + + } + + }; + + confirm = UIUtils.createButton ("Yes, delete them", + confirmAction); + + UIUtils.addDoActionOnReturnPressed (text, + confirmAction); + + JButton[] buts = null; + + if (confirm != null) + { + + buts = new JButton[] { confirm, cancel }; + + } else { + + buts = new JButton[] { cancel }; + + } + + JComponent buttons = UIUtils.createButtonBar2 (buts, + Component.LEFT_ALIGNMENT); //ButtonBarFactory.buildLeftAlignedBar (buts); + buttons.setAlignmentX (Component.LEFT_ALIGNMENT); + content.add (buttons); + content.setBorder (UIUtils.createPadding (10, 10, 10, 10)); + + content.setPreferredSize (new Dimension (UIUtils.getPopupWidth (), + content.getPreferredSize ().height)); + + qp.setContent (content); + qp.setDraggable (this); + + this.showPopupAt (qp, + UIUtils.getCenterShowPosition (this, + qp), + false); + + } + + private void saveToFile () + throws Exception + { + + WebsiteLanguageStringsManager.saveWebsiteLanguageStrings (this.userStrings); + + } + + @Override + public void save () + throws Exception + { + + // Cycle over all the id boxes and set the values if present. + for (LanguageStringsIdsPanel p : this.panels.values ()) + { + + p.saveValues (); + + } + + this.userStrings.setBaseVersion (this.userStrings.getDerivedFrom ().getStringsVersion ()); + + this.saveToFile (); + + } + + private void updateTitle () + { + + this.setViewerTitle (String.format ("Edit Website Language Strings for: %s", + this.userStrings.getNativeName ())); + + } + + @Override + public void showReportProblemForId (String id) + { + + this.showReportProblem ("Website Language Strings Id: " + id + "\n\n"); + + } + + @Override + public boolean isIdValid (String id) + { + + throw new IllegalStateException ("DO NOT USE!"); + + } + +} diff --git a/src/com/quollwriter/ui/WhatsNew.java b/src/main/java/com/quollwriter/ui/WhatsNew.java similarity index 89% rename from src/com/quollwriter/ui/WhatsNew.java rename to src/main/java/com/quollwriter/ui/WhatsNew.java index b1c27f4d..9d31846a 100644 --- a/src/com/quollwriter/ui/WhatsNew.java +++ b/src/main/java/com/quollwriter/ui/WhatsNew.java @@ -14,9 +14,8 @@ import javax.swing.border.*; import javax.swing.event.*; -import org.jdom.*; +import org.dom4j.*; -import com.gentlyweb.xml.*; import com.gentlyweb.properties.*; import com.quollwriter.*; @@ -73,14 +72,12 @@ public WhatsNew (AbstractViewer viewer, try { - String whatsNew = Environment.getResourceFileAsString (Constants.WHATS_NEW_FILE); + String whatsNew = Utils.getResourceFileAsString (Constants.WHATS_NEW_FILE); // Load up all the whats new for greater versions. - Element root = JDOMUtils.getStringAsElement (whatsNew); + Element root = DOM4JUtils.stringAsElement (whatsNew); - java.util.List verEls = JDOMUtils.getChildElements (root, - XMLConstants.version, - false); + java.util.List verEls = root.elements (XMLConstants.version); // Assume they are in the right order // TODO: Enforce the order and/or sort. @@ -89,7 +86,7 @@ public WhatsNew (AbstractViewer viewer, Element vEl = (Element) verEls.get (i); - String id = JDOMUtils.getAttributeValue (vEl, + String id = DOM4JUtils.attributeValue (vEl, XMLConstants.id, true); @@ -118,7 +115,7 @@ public WhatsNew (AbstractViewer viewer, WhatsNewComponentProvider compProv = null; - String cl = JDOMUtils.getAttributeValue (vEl, + String cl = DOM4JUtils.attributeValue (vEl, XMLConstants.clazz, false); @@ -146,9 +143,7 @@ public WhatsNew (AbstractViewer viewer, } // This is a version we are interested in. - java.util.List itemEls = JDOMUtils.getChildElements (vEl, - WhatsNewItem.XMLConstants.root, - true); + java.util.List itemEls = vEl.elements (WhatsNewItem.XMLConstants.root); java.util.List its = new ArrayList (); @@ -199,7 +194,7 @@ public WhatsNew (AbstractViewer viewer, { Environment.logMessage ("Whats new item has no title, referenced by: " + - JDOMUtils.getPath (itEl)); + DOM4JUtils.getPath (itEl)); continue; @@ -212,7 +207,7 @@ public WhatsNew (AbstractViewer viewer, { Environment.logMessage ("Whats new item has no description or component, referenced by: " + - JDOMUtils.getPath (itEl)); + DOM4JUtils.getPath (itEl)); continue; @@ -575,7 +570,7 @@ public WhatsNewItem (Element root, throws Exception { - this.id = JDOMUtils.getAttributeValue (root, + this.id = DOM4JUtils.attributeValue (root, XMLConstants.id, false); @@ -594,15 +589,11 @@ public WhatsNewItem (Element root, } - this.onlyIfCurrentVersion = JDOMUtils.getAttributeValueAsBoolean (root, + this.onlyIfCurrentVersion = DOM4JUtils.attributeValueAsBoolean (root, XMLConstants.onlyIfCurrentVersion, false); - this.title = JDOMUtils.getChildElementContent (root, - XMLConstants.title, - false); - this.description = JDOMUtils.getChildElementContent (root, - XMLConstants.description, - false); + this.title = root.element (XMLConstants.title).getTextTrim (); + this.description = root.element (XMLConstants.description).getTextTrim (); if (this.description.equals ("")) { diff --git a/src/main/java/com/quollwriter/ui/Wizard.java b/src/main/java/com/quollwriter/ui/Wizard.java new file mode 100644 index 00000000..bdd3a500 --- /dev/null +++ b/src/main/java/com/quollwriter/ui/Wizard.java @@ -0,0 +1,569 @@ +package com.quollwriter.ui; + +import java.awt.*; +import java.awt.event.*; + +import java.util.LinkedHashMap; +import java.util.Map; + +import javax.swing.*; +import javax.swing.border.*; +import javax.swing.event.*; + +import com.jgoodies.forms.factories.*; + +import com.quollwriter.*; + +import com.quollwriter.ui.components.*; + +public abstract class Wizard extends Box +{ + + public static final String NEXT_BUTTON_ID = "next"; + public static final String PREVIOUS_BUTTON_ID = "previous"; + public static final String FINISH_BUTTON_ID = "finish"; + public static final String CANCEL_BUTTON_ID = "cancel"; + private boolean inited = false; + private WizardStep current = null; + private String currentStage = null; + private Box contentPanel = null; + private Map stages = new LinkedHashMap (); + private JButton cancelBut = null; + private JButton nextBut = null; + private JButton prevBut = null; + private Header header = null; + private JTextPane helpText = null; + protected E viewer = null; + + public Wizard (E viewer) + { + + super (BoxLayout.Y_AXIS); + + this.contentPanel = new Box (BoxLayout.Y_AXIS); + + this.viewer = viewer; + + } + + public int getContentPreferredHeight () + { + + return 250; + + } + + public void addButtonListener (String type, + ActionListener l) + { + + if (NEXT_BUTTON_ID.equals (type)) + { + + this.nextBut.addActionListener (l); + + } + + if (PREVIOUS_BUTTON_ID.equals (type)) + { + + this.prevBut.addActionListener (l); + + } + + if (CANCEL_BUTTON_ID.equals (type)) + { + + this.cancelBut.addActionListener (l); + + } + + } + + public String getCurrentStage () + { + + return this.currentStage; + + } + + public void resize () + { + + UIUtils.resizeParent (this.getParent ()); + + } + + public void init () + { + + if (this.inited) + { + + return; + + } + + final Wizard _this = this; + + this.helpText = UIUtils.createHelpTextPane (this.viewer); + + this.helpText.setBorder (null); + + this.add (this.helpText); + this.add (Box.createVerticalStrut (10)); + this.setAlignmentX (JComponent.LEFT_ALIGNMENT); + + this.header = UIUtils.createHeader ("", + Constants.SUB_PANEL_TITLE); + + this.header.setBorder (UIUtils.createBottomLineWithPadding (0, 0, 2, 0)); + + this.header.setAlignmentX (JComponent.LEFT_ALIGNMENT); + this.add (Box.createVerticalStrut (10)); + this.add (this.header); + this.add (Box.createVerticalStrut (10)); + this.add (this.contentPanel); + this.contentPanel.setAlignmentX (JComponent.LEFT_ALIGNMENT); + this.contentPanel.setAlignmentY (JComponent.TOP_ALIGNMENT); + + this.contentPanel.setPreferredSize (new Dimension (UIUtils.getPopupWidth (), + this.getContentPreferredHeight ())); + + this.add (Box.createVerticalStrut (10)); + + this.prevBut = new JButton (); + this.prevBut.setText (Environment.getUIString (LanguageStrings.wizard, + LanguageStrings.buttons, + LanguageStrings.previous)); + //"< Back"); + this.prevBut.setEnabled (false); + + this.prevBut.addActionListener (new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + Map _stages = _this.stages; + + WizardStep ws = null; + + String prev = _this.getPreviousStage (_this.currentStage); + + if (prev != null) + { + + if (!_this.handleStageChange (_this.currentStage, + prev)) + { + + return; + + } + + ws = _stages.get (prev); + + if (ws == null) + { + + try + { + + ws = _this.getStage (prev); + + } catch (Exception e) + { + + Environment.logError ("Unable to get stage for: " + + prev, + e); + + } + + _this.stages.put (prev, + ws); + + } + + if (_this.current.panel != null) + { + + _this.contentPanel.remove (_this.current.panel); + + } + + _this.current = ws; + _this.currentStage = prev; + + _this.enableButtons (_this.currentStage); + + _this.initUI (); + + } + + /* + _this.setSize (new Dimension (_this.getSize ().width, + _this.getPreferredSize ().height)); + */ + _this.repaint (); + + } + + }); + + this.nextBut = new JButton (); + this.nextBut.setText (Environment.getUIString (LanguageStrings.wizard, + LanguageStrings.buttons, + LanguageStrings.next)); + //"Next >"); + + this.nextBut.addActionListener (new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + WizardStep ws = null; + + String next = _this.getNextStage (_this.currentStage); + + if (next != null) + { + + if (!_this.handleStageChange (_this.currentStage, + next)) + { + + return; + + } + + Map _stages = _this.stages; + + ws = _stages.get (next); + + if (ws == null) + { + + try + { + + ws = _this.getStage (next); + + } catch (Exception e) + { + + Environment.logError ("Unable to get stage: " + + next, + e); + + } + + if (ws != null) + { + + _this.stages.put (next, + ws); + + } + + } + + if (ws == null) + { + + Environment.logError ("Unable to get stage view component for: " + + next); + + UIUtils.showErrorMessage (this, + Environment.getUIString (LanguageStrings.wizard, + LanguageStrings.nexterror)); + //"Unable to show next stage."); + + return; + + } + + if (_this.current.panel != null) + { + + _this.contentPanel.remove (_this.current.panel); + + } + + _this.current = ws; + _this.currentStage = next; + + _this.enableButtons (_this.currentStage); + + _this.initUI (); + + } else + { + + if (_this.handleFinish ()) + { + + _this.setVisible (false); + + UIUtils.closePopupParent (_this.getParent ()); + + return; + + } + + } + + _this.repaint (); + + } + + }); + + this.cancelBut = new JButton (); + this.cancelBut.setText (Environment.getUIString (LanguageStrings.wizard, + LanguageStrings.buttons, + LanguageStrings.cancel)); + //"Cancel"); + + final ActionAdapter cancel = new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + _this.handleCancel (); + + _this.setVisible (false); + + UIUtils.closePopupParent (_this.getParent ()); + + } + + }; + + this.cancelBut.addActionListener (cancel); + + JButton[] buts = { this.prevBut, this.nextBut, this.cancelBut }; + + JPanel bp = UIUtils.createButtonBar2 (buts, + Component.CENTER_ALIGNMENT); + bp.setOpaque (false); + bp.setBorder (new EmptyBorder (0, + 0, + 0, + 0)); + bp.setAlignmentX (JComponent.LEFT_ALIGNMENT); + this.add (bp); + + //this.add (Box.createVerticalStrut (5)); + + String startStage = this.getStartStage (); + + // Get the stage. + WizardStep ws = this.getStage (startStage); + this.stages.put (startStage, + ws); + this.current = ws; + this.currentStage = startStage; + + this.initUI (); + + this.enableButtons (this.currentStage); + + this.handleStageChange (null, + this.currentStage); + + this.inited = true; + + } + + public void showStage (String stage) + { + + if (!this.handleStageChange (this.currentStage, + stage)) + { + + return; + + } + + WizardStep ws = this.stages.get (stage); + + if ((ws == null) + || + (ws.alwaysRefreshPanel) + ) + { + + try + { + + ws = this.getStage (stage); + + } catch (Exception e) + { + + Environment.logError ("Unable to get stage for: " + + stage, + e); + + } + + this.stages.put (stage, + ws); + + } + + if (this.current.panel != null) + { + + this.contentPanel.remove (this.current.panel); + + } + + this.current = ws; + this.currentStage = stage; + + this.enableButtons (this.currentStage); + + this.initUI (); + + } + + public JButton[] getButtons () + { + + JButton[] buts = { this.prevBut, this.nextBut, this.cancelBut }; + + return buts; + + } + + public void enableButton (String name, + boolean enable) + { + + if ((name.equals (NEXT_BUTTON_ID)) || + (name.equals (FINISH_BUTTON_ID))) + { + + this.nextBut.setEnabled (enable); + + } + + if (name.equals (PREVIOUS_BUTTON_ID)) + { + + this.prevBut.setEnabled (enable); + + } + + if (name.equals (CANCEL_BUTTON_ID)) + { + + this.cancelBut.setEnabled (enable); + + } + + } + + private void initUI () + { + + this.header.setTitle (Environment.replaceObjectNames (this.current.title)); + + if (this.current.helpText == null) + { + + this.helpText.setText (this.getFirstHelpText ()); + + } else + { + + this.helpText.setText (this.current.helpText); + + } + + if (this.current.panel != null) + { + + this.current.panel.setOpaque (false); + this.current.panel.setAlignmentY (Component.TOP_ALIGNMENT); + this.contentPanel.add (this.current.panel); + + } + + UIUtils.resizeParent (this.getParent ()); + + } + + //public abstract int getMaximumContentHeight (); + + public abstract String getNextStage (String currStage); + + public abstract String getPreviousStage (String currStage); + + public abstract String getStartStage (); + + public abstract boolean handleStageChange (String oldStage, + String newStage); + + public abstract boolean handleFinish (); + + public abstract void handleCancel (); + + public abstract String getFirstHelpText (); + + public abstract WizardStep getStage (String stage); + + public String getNextButtonLabel (String currStage) + { + + String next = this.getNextStage (currStage); + + if (next == null) + { + + return Environment.getUIString (LanguageStrings.wizard, + LanguageStrings.buttons, + LanguageStrings.finish); + //return "Finish"; + + } + + return Environment.getUIString (LanguageStrings.wizard, + LanguageStrings.buttons, + LanguageStrings.next); + //return "Next >"; + + } + + protected void enableButtons (String currentStage) + { + + String prev = this.getPreviousStage (currentStage); + String next = this.getNextStage (currentStage); + + if (this.current != null) + { + + this.prevBut.setEnabled (prev != null); + this.nextBut.setEnabled (next != null); + + } + + if (next == null) + { + + this.nextBut.setEnabled (true); + + } + + this.nextBut.setText (this.getNextButtonLabel (currentStage)); + + } + +} diff --git a/src/com/quollwriter/ui/WizardStep.java b/src/main/java/com/quollwriter/ui/WizardStep.java similarity index 100% rename from src/com/quollwriter/ui/WizardStep.java rename to src/main/java/com/quollwriter/ui/WizardStep.java diff --git a/src/com/quollwriter/ui/WordCountTimer.java b/src/main/java/com/quollwriter/ui/WordCountTimer.java similarity index 87% rename from src/com/quollwriter/ui/WordCountTimer.java rename to src/main/java/com/quollwriter/ui/WordCountTimer.java index ba786353..892e49d5 100644 --- a/src/com/quollwriter/ui/WordCountTimer.java +++ b/src/main/java/com/quollwriter/ui/WordCountTimer.java @@ -30,9 +30,9 @@ public class WordCountTimer private java.util.Set listeners = new java.util.LinkedHashSet (); private int percentComplete = 0; private int wordsRemaining = 0; - private int minsRemaining = 0; + private int minsRemaining = 0; private AbstractProjectViewer projectViewer = null; - + private int startCount = 0; public WordCountTimer (AbstractProjectViewer pv, @@ -45,7 +45,7 @@ public WordCountTimer (AbstractProjectViewer pv, this.minsCount = mins; final WordCountTimer _this = this; - + this.timer = new javax.swing.Timer (5 * 1000, new ActionAdapter () { @@ -84,17 +84,17 @@ public void actionPerformed (ActionEvent ev) // Get the word count. ChapterCounts cc = _this.projectViewer.getAllChapterCounts (); - + // Can happen if shutting down. if (cc == null) { - + return; - + } - - wc = cc.wordCount; - + + wc = cc.getWordCount (); + wc -= _this.initWordCount; if (wc > 0) @@ -112,12 +112,12 @@ public void actionPerformed (ActionEvent ev) wp); _this.percentComplete = max; - + if (max >= 100) { - _this.timer.stop (); - + _this.timer.stop (); + _this.projectViewer.fireProjectEvent (Warmup.OBJECT_TYPE, ProjectEvent.TIME_REACHED); _this.projectViewer.fireProjectEvent (Chapter.OBJECT_TYPE, @@ -132,12 +132,12 @@ public void actionPerformed (ActionEvent ev) for (WordCountTimerListener l : new java.util.ArrayList (_this.listeners)) { - l.timerFinished (wev); + l.timerFinished (wev); } - + } else { - + WordCountTimerEvent wev = new WordCountTimerEvent (_this, wc, wp, @@ -147,60 +147,60 @@ public void actionPerformed (ActionEvent ev) for (WordCountTimerListener l : _this.listeners) { - l.timerUpdated (wev); + l.timerUpdated (wev); + + } - } - } } - }); - + }); + } public int getStartCount () { - + return this.startCount; - + } - + public int getPercentComplete () { - + return this.percentComplete; - + } - + public int getWordsRemaining () { - + return this.wordsRemaining; - + } - + public int getMinutesRemaining () { - + return this.minsRemaining; - + } - + public int getMinutes () { - + return this.minsCount; - + } - + public int getWords () { - + return this.wordCount; - + } - + public void stop () { @@ -216,27 +216,27 @@ public void stop () public void start (int mins, int words) { - + this.wordCount = words; this.minsCount = mins; - + this.start (); - + } - + public void start () { - this.startCount++; - + this.startCount++; + final WordCountTimer _this = this; this.percentComplete = 0; this.wordsRemaining = this.wordCount; this.minsRemaining = this.minsCount; - - this.initWordCount = this.projectViewer.getAllChapterCounts ().wordCount; - + + this.initWordCount = this.projectViewer.getAllChapterCounts ().getWordCount (); + this.startTime = System.currentTimeMillis (); // Start the thread that monitors progress. @@ -251,28 +251,28 @@ public void start () for (WordCountTimerListener l : this.listeners) { - l.timerStarted (wev); + l.timerStarted (wev); } - + // Only fire in full screen mode. if (this.projectViewer.isInFullScreen ()) { - + this.projectViewer.fireProjectEvent (Chapter.OBJECT_TYPE, (this.startCount > 1 ? ProjectEvent.TIMER_RESTART : ProjectEvent.TIMER_STARTED)); - } - + } + } public void removeTimerListener (WordCountTimerListener l) { - + this.listeners.remove (l); - + } - + public void addTimerListener (WordCountTimerListener l) { diff --git a/src/com/quollwriter/ui/WordCountTimerBox.java b/src/main/java/com/quollwriter/ui/WordCountTimerBox.java similarity index 100% rename from src/com/quollwriter/ui/WordCountTimerBox.java rename to src/main/java/com/quollwriter/ui/WordCountTimerBox.java diff --git a/src/com/quollwriter/ui/actionHandlers/AbstractFormPopup.java b/src/main/java/com/quollwriter/ui/actionHandlers/AbstractFormPopup.java similarity index 98% rename from src/com/quollwriter/ui/actionHandlers/AbstractFormPopup.java rename to src/main/java/com/quollwriter/ui/actionHandlers/AbstractFormPopup.java index 06b6b48c..71c4fc89 100644 --- a/src/com/quollwriter/ui/actionHandlers/AbstractFormPopup.java +++ b/src/main/java/com/quollwriter/ui/actionHandlers/AbstractFormPopup.java @@ -335,12 +335,12 @@ private void selectAllChildren (DefaultTreeModel model, boolean v) { - Enumeration en = n.children (); + Enumeration en = n.children (); while (en.hasMoreElements ()) { - DefaultMutableTreeNode c = en.nextElement (); + DefaultMutableTreeNode c = (DefaultMutableTreeNode) en.nextElement (); SelectableDataObject s = (SelectableDataObject) c.getUserObject (); @@ -908,12 +908,12 @@ private void getSelectedObjects (DefaultMutableTreeNode n, throws GeneralException { - Enumeration en = n.children (); + Enumeration en = n.children (); while (en.hasMoreElements ()) { - DefaultMutableTreeNode nn = en.nextElement (); + DefaultMutableTreeNode nn = (DefaultMutableTreeNode) en.nextElement (); SelectableDataObject sd = (SelectableDataObject) nn.getUserObject (); diff --git a/src/com/quollwriter/ui/actionHandlers/AddBookActionHandler.java b/src/main/java/com/quollwriter/ui/actionHandlers/AddBookActionHandler.java similarity index 100% rename from src/com/quollwriter/ui/actionHandlers/AddBookActionHandler.java rename to src/main/java/com/quollwriter/ui/actionHandlers/AddBookActionHandler.java diff --git a/src/com/quollwriter/ui/actionHandlers/AddChapterActionHandler.java b/src/main/java/com/quollwriter/ui/actionHandlers/AddChapterActionHandler.java similarity index 100% rename from src/com/quollwriter/ui/actionHandlers/AddChapterActionHandler.java rename to src/main/java/com/quollwriter/ui/actionHandlers/AddChapterActionHandler.java diff --git a/src/com/quollwriter/ui/actionHandlers/AddNewNoteTypeActionHandler.java b/src/main/java/com/quollwriter/ui/actionHandlers/AddNewNoteTypeActionHandler.java similarity index 100% rename from src/com/quollwriter/ui/actionHandlers/AddNewNoteTypeActionHandler.java rename to src/main/java/com/quollwriter/ui/actionHandlers/AddNewNoteTypeActionHandler.java diff --git a/src/com/quollwriter/ui/actionHandlers/AddNewTagActionHandler.java b/src/main/java/com/quollwriter/ui/actionHandlers/AddNewTagActionHandler.java similarity index 82% rename from src/com/quollwriter/ui/actionHandlers/AddNewTagActionHandler.java rename to src/main/java/com/quollwriter/ui/actionHandlers/AddNewTagActionHandler.java index d59ffb02..b4d2e1e6 100644 --- a/src/com/quollwriter/ui/actionHandlers/AddNewTagActionHandler.java +++ b/src/main/java/com/quollwriter/ui/actionHandlers/AddNewTagActionHandler.java @@ -22,65 +22,65 @@ public class AddNewTagActionHandler extends TextInputActionHandler
    The tags will be added to %s.", this.obj.getName ()); - + } public String getConfirmButtonLabel () { - + return Environment.getUIString (LanguageStrings.tags, LanguageStrings.actions, - LanguageStrings.newtag, + LanguageStrings.newtag, LanguageStrings.confirm); //"Add"; - + } - + public String getInitialValue () { - + return null; - + } - + public String isValid (String v) { @@ -89,154 +89,154 @@ public String isValid (String v) (v.trim ().length () == 0) ) { - + return Environment.getUIString (LanguageStrings.tags, LanguageStrings.actions, - LanguageStrings.newtag, + LanguageStrings.newtag, LanguageStrings.errors, LanguageStrings.novalue); //"Please enter a new tag."; - + } - + Set ntags = this.getTags (v); - + if (ntags.size () == 0) { - + return Environment.getUIString (LanguageStrings.tags, LanguageStrings.actions, - LanguageStrings.newtag, + LanguageStrings.newtag, LanguageStrings.errors, LanguageStrings.novalue); //"Please enter a new tag."; - + } - + return null; - + } - + private Set getTags (String v) { - Set ret = new LinkedHashSet (); - + Set ret = new LinkedHashSet<> (); + StringTokenizer t = new StringTokenizer (v.trim (), ";,"); - + while (t.hasMoreTokens ()) { - + ret.add (t.nextToken ().trim ()); - + } - + return ret; - + } - + @Override public boolean onConfirm (String v) throws Exception { - + Set tags = this.getTags (v); - + for (String s : tags) { - + Tag ot = null; - + try { - + ot = Environment.getTagByName (s); - + } catch (Exception e) { - + Environment.logError ("Unable to get tag for name: " + s, e); - + continue; - + } - + if (ot != null) { - + continue; - + } - + Tag tag = new Tag (); tag.setName (s); - + try { - + Environment.saveTag (tag); - + } catch (Exception e) { Environment.logError ("Unable to add tag: " + tag, e); - + UIUtils.showErrorMessage (this.viewer, Environment.getUIString (LanguageStrings.tags, LanguageStrings.actions, - LanguageStrings.newtag, + LanguageStrings.newtag, LanguageStrings.actionerror)); //"Unable to add tag."); - + return false; - + } - + this.obj.addTag (tag); - + } - + try { - + this.viewer.saveObject (this.obj, false); - + } catch (Exception e) { - + Environment.logError ("Unable to update object: " + this.obj, e); - + UIUtils.showErrorMessage (this.viewer, Environment.getUIString (LanguageStrings.tags, LanguageStrings.actions, - LanguageStrings.newtag, + LanguageStrings.newtag, LanguageStrings.actionerror)); //"Unable to add tags."); - + } - + return true; - + } public boolean onCancel () throws Exception { - + return true; - + } - + public Point getShowAt () { - + return null; - + } - + } diff --git a/src/com/quollwriter/ui/actionHandlers/AssetActionHandler.java b/src/main/java/com/quollwriter/ui/actionHandlers/AssetActionHandler.java similarity index 99% rename from src/com/quollwriter/ui/actionHandlers/AssetActionHandler.java rename to src/main/java/com/quollwriter/ui/actionHandlers/AssetActionHandler.java index 1cb67323..b07210a1 100644 --- a/src/com/quollwriter/ui/actionHandlers/AssetActionHandler.java +++ b/src/main/java/com/quollwriter/ui/actionHandlers/AssetActionHandler.java @@ -79,7 +79,7 @@ public JComponent getFocussedField () public Icon getIcon (int iconSizeType) { - return this.object.getUserConfigurableObjectType ().getIcon16x16 (); + return null; // TODO this.object.getUserConfigurableObjectType ().getIcon16x16 (); } @@ -107,7 +107,8 @@ public Set getFormItems (String selectedText) { int c = 0; - +/* +TODO for (UserConfigurableObjectFieldViewEditHandler h : this.object.getViewEditHandlers (this.viewer)) { @@ -134,7 +135,7 @@ public Set getFormItems (String selectedText) c++; } - +*/ Set items = new LinkedHashSet (); items.addAll (this.nameHandler.getInputFormItems (selectedText, diff --git a/src/com/quollwriter/ui/actionHandlers/ChapterItemActionHandler.java b/src/main/java/com/quollwriter/ui/actionHandlers/ChapterItemActionHandler.java similarity index 100% rename from src/com/quollwriter/ui/actionHandlers/ChapterItemActionHandler.java rename to src/main/java/com/quollwriter/ui/actionHandlers/ChapterItemActionHandler.java diff --git a/src/com/quollwriter/ui/actionHandlers/ChapterItemFormatDetails.java b/src/main/java/com/quollwriter/ui/actionHandlers/ChapterItemFormatDetails.java similarity index 100% rename from src/com/quollwriter/ui/actionHandlers/ChapterItemFormatDetails.java rename to src/main/java/com/quollwriter/ui/actionHandlers/ChapterItemFormatDetails.java diff --git a/src/com/quollwriter/ui/actionHandlers/DeleteChapterActionHandler.java b/src/main/java/com/quollwriter/ui/actionHandlers/DeleteChapterActionHandler.java similarity index 100% rename from src/com/quollwriter/ui/actionHandlers/DeleteChapterActionHandler.java rename to src/main/java/com/quollwriter/ui/actionHandlers/DeleteChapterActionHandler.java diff --git a/src/com/quollwriter/ui/actionHandlers/DeleteChapterItemActionHandler.java b/src/main/java/com/quollwriter/ui/actionHandlers/DeleteChapterItemActionHandler.java similarity index 100% rename from src/com/quollwriter/ui/actionHandlers/DeleteChapterItemActionHandler.java rename to src/main/java/com/quollwriter/ui/actionHandlers/DeleteChapterItemActionHandler.java diff --git a/src/com/quollwriter/ui/actionHandlers/DeleteIdeaTypeActionHandler.java b/src/main/java/com/quollwriter/ui/actionHandlers/DeleteIdeaTypeActionHandler.java similarity index 100% rename from src/com/quollwriter/ui/actionHandlers/DeleteIdeaTypeActionHandler.java rename to src/main/java/com/quollwriter/ui/actionHandlers/DeleteIdeaTypeActionHandler.java diff --git a/src/main/java/com/quollwriter/ui/actionHandlers/DeleteProjectActionHandler.java b/src/main/java/com/quollwriter/ui/actionHandlers/DeleteProjectActionHandler.java new file mode 100644 index 00000000..5c695eb3 --- /dev/null +++ b/src/main/java/com/quollwriter/ui/actionHandlers/DeleteProjectActionHandler.java @@ -0,0 +1,132 @@ +package com.quollwriter.ui.actionHandlers; + +import java.awt.*; +import java.awt.event.*; + +import java.io.*; + +import javax.swing.*; + +import com.quollwriter.*; + +import com.quollwriter.data.*; + +import com.quollwriter.ui.*; +import com.quollwriter.editors.*; + +public class DeleteProjectActionHandler extends YesDeleteConfirmTextInputActionHandler +{ + + private ProjectInfo projInfo = null; + private ActionListener onDelete = null; + + public DeleteProjectActionHandler (AbstractViewer viewer, + Project proj, + ActionListener onDelete) + { + + this (viewer, + Environment.getProjectInfo (proj), + onDelete); + + } + + public DeleteProjectActionHandler (AbstractViewer viewer, + ProjectInfo pi, + ActionListener onDelete) + { + + super (viewer, + pi); + + this.projInfo = pi; + this.onDelete = onDelete; + + } + + public String getDeleteType () + { + + return Environment.getUIString (LanguageStrings.project, + LanguageStrings.actions, + LanguageStrings.deleteproject, + LanguageStrings.deletetype); + //"{Project}"; + + } + + public String getWarning () + { + + String m = Environment.getUIString (LanguageStrings.project, + LanguageStrings.actions, + LanguageStrings.deleteproject, + LanguageStrings.warning, + LanguageStrings.normal); + //"Warning! All information/chapters associated with the {project} will be deleted. Once deleted a {project} cannot be restored."; + + if (this.projInfo.isEditorProject ()) + { + + m += String.format (Environment.getUIString (LanguageStrings.project, + LanguageStrings.actions, + LanguageStrings.deleteproject, + LanguageStrings.warning, + LanguageStrings.editor), + //"

    A message will also be sent to %s telling them you are no longer editing the {project}.", + this.projInfo.getForEditor ().getMainName ()); + + } + + return m; + + } + + @Override + public boolean onConfirm (String v) + throws Exception + { + + final DeleteProjectActionHandler _this = this; + + if (this.projInfo.isEditorProject ()) + { + + EditorsEnvironment.sendProjectEditStopMessage (this.projInfo, + () -> + { + + Environment.deleteProject (_this.projInfo, + _this.onDelete); + + UIUtils.showMessage ((Component) null, + Environment.getUIString (LanguageStrings.project, + LanguageStrings.actions, + LanguageStrings.deleteproject, + LanguageStrings.editorproject, + LanguageStrings.confirmpopup, + LanguageStrings.title), + String.format (Environment.getUIString (LanguageStrings.project, + LanguageStrings.actions, + LanguageStrings.deleteproject, + LanguageStrings.editorproject, + LanguageStrings.confirmpopup, + LanguageStrings.text), + _this.projInfo.getForEditor ().getMainName ()), + null, + null); + + }); + + } else { + + Environment.deleteProject (this.projInfo, + this.onDelete); + + } + + return true; + + } + +} diff --git a/src/com/quollwriter/ui/actionHandlers/DeleteWarmupActionHandler.java b/src/main/java/com/quollwriter/ui/actionHandlers/DeleteWarmupActionHandler.java similarity index 100% rename from src/com/quollwriter/ui/actionHandlers/DeleteWarmupActionHandler.java rename to src/main/java/com/quollwriter/ui/actionHandlers/DeleteWarmupActionHandler.java diff --git a/src/com/quollwriter/ui/actionHandlers/EditIdeaTypeActionHandler.java b/src/main/java/com/quollwriter/ui/actionHandlers/EditIdeaTypeActionHandler.java similarity index 97% rename from src/com/quollwriter/ui/actionHandlers/EditIdeaTypeActionHandler.java rename to src/main/java/com/quollwriter/ui/actionHandlers/EditIdeaTypeActionHandler.java index b357501d..ee740ee2 100644 --- a/src/com/quollwriter/ui/actionHandlers/EditIdeaTypeActionHandler.java +++ b/src/main/java/com/quollwriter/ui/actionHandlers/EditIdeaTypeActionHandler.java @@ -98,7 +98,7 @@ public String isValid (String v) } - List its = this.viewer.getProject ().getIdeaTypes (); + List its = null;// TODO this.viewer.getProject ().getIdeaTypes (); for (IdeaType it : its) { diff --git a/src/com/quollwriter/ui/actionHandlers/FindSynonymsActionHandler.java b/src/main/java/com/quollwriter/ui/actionHandlers/FindSynonymsActionHandler.java similarity index 100% rename from src/com/quollwriter/ui/actionHandlers/FindSynonymsActionHandler.java rename to src/main/java/com/quollwriter/ui/actionHandlers/FindSynonymsActionHandler.java diff --git a/src/com/quollwriter/ui/actionHandlers/NewIdeaTypeActionHandler.java b/src/main/java/com/quollwriter/ui/actionHandlers/NewIdeaTypeActionHandler.java similarity index 100% rename from src/com/quollwriter/ui/actionHandlers/NewIdeaTypeActionHandler.java rename to src/main/java/com/quollwriter/ui/actionHandlers/NewIdeaTypeActionHandler.java diff --git a/src/com/quollwriter/ui/actionHandlers/NoteActionHandler.java b/src/main/java/com/quollwriter/ui/actionHandlers/NoteActionHandler.java similarity index 99% rename from src/com/quollwriter/ui/actionHandlers/NoteActionHandler.java rename to src/main/java/com/quollwriter/ui/actionHandlers/NoteActionHandler.java index f5562dfc..4a646b02 100644 --- a/src/com/quollwriter/ui/actionHandlers/NoteActionHandler.java +++ b/src/main/java/com/quollwriter/ui/actionHandlers/NoteActionHandler.java @@ -54,7 +54,7 @@ public NoteActionHandler (final Note n, final int origSelStart = editor.getSelectionStart (); - final BlockPainter highlight = new BlockPainter (Environment.getHighlightColor ()); + final BlockPainter highlight = new BlockPainter (UIUtils.getHighlightColor ()); final Caret origCaret = editor.getCaret (); diff --git a/src/com/quollwriter/ui/actionHandlers/NoteFormatDetails.java b/src/main/java/com/quollwriter/ui/actionHandlers/NoteFormatDetails.java similarity index 97% rename from src/com/quollwriter/ui/actionHandlers/NoteFormatDetails.java rename to src/main/java/com/quollwriter/ui/actionHandlers/NoteFormatDetails.java index 1ca87f4d..1790b3d7 100644 --- a/src/com/quollwriter/ui/actionHandlers/NoteFormatDetails.java +++ b/src/main/java/com/quollwriter/ui/actionHandlers/NoteFormatDetails.java @@ -38,7 +38,7 @@ public String getIcon (Note item) public String getTitle (Note item) { - return Environment.getObjectTypeName (item); + return Environment.getObjectTypeName (item).getValue (); } diff --git a/src/com/quollwriter/ui/actionHandlers/OutlineItemFormatDetails.java b/src/main/java/com/quollwriter/ui/actionHandlers/OutlineItemFormatDetails.java similarity index 99% rename from src/com/quollwriter/ui/actionHandlers/OutlineItemFormatDetails.java rename to src/main/java/com/quollwriter/ui/actionHandlers/OutlineItemFormatDetails.java index c8876ae6..0bd30d07 100644 --- a/src/com/quollwriter/ui/actionHandlers/OutlineItemFormatDetails.java +++ b/src/main/java/com/quollwriter/ui/actionHandlers/OutlineItemFormatDetails.java @@ -26,7 +26,7 @@ public String getIcon (OutlineItem item) public String getTitle (OutlineItem item) { - return Environment.getObjectTypeName (item.getObjectType ()); + return Environment.getObjectTypeName (item.getObjectType ()).getValue (); } diff --git a/src/com/quollwriter/ui/actionHandlers/RenameChapterActionHandler.java b/src/main/java/com/quollwriter/ui/actionHandlers/RenameChapterActionHandler.java similarity index 100% rename from src/com/quollwriter/ui/actionHandlers/RenameChapterActionHandler.java rename to src/main/java/com/quollwriter/ui/actionHandlers/RenameChapterActionHandler.java diff --git a/src/com/quollwriter/ui/actionHandlers/RenameNoteTypeActionHandler.java b/src/main/java/com/quollwriter/ui/actionHandlers/RenameNoteTypeActionHandler.java similarity index 100% rename from src/com/quollwriter/ui/actionHandlers/RenameNoteTypeActionHandler.java rename to src/main/java/com/quollwriter/ui/actionHandlers/RenameNoteTypeActionHandler.java diff --git a/src/com/quollwriter/ui/actionHandlers/RenameProjectActionHandler.java b/src/main/java/com/quollwriter/ui/actionHandlers/RenameProjectActionHandler.java similarity index 90% rename from src/com/quollwriter/ui/actionHandlers/RenameProjectActionHandler.java rename to src/main/java/com/quollwriter/ui/actionHandlers/RenameProjectActionHandler.java index 9755baf3..82c0995a 100644 --- a/src/com/quollwriter/ui/actionHandlers/RenameProjectActionHandler.java +++ b/src/main/java/com/quollwriter/ui/actionHandlers/RenameProjectActionHandler.java @@ -31,51 +31,51 @@ public RenameProjectActionHandler (AbstractProjectViewer pv) public String getIcon () { - + return Constants.EDIT_ICON_NAME; - + } - + public String getTitle () { - + return Environment.getUIString (LanguageStrings.project, LanguageStrings.actions, LanguageStrings.renameproject, LanguageStrings.title); //"Rename {Project}"; - + } - + public String getHelp () { - + return Environment.getUIString (LanguageStrings.project, LanguageStrings.actions, LanguageStrings.renameproject, LanguageStrings.text); //"Enter the new {project} name below. The {project} will then be closed and re-opened."; - + } - + public String getConfirmButtonLabel () { - + return Environment.getUIString (LanguageStrings.project, LanguageStrings.actions, LanguageStrings.renameproject, LanguageStrings.confirm); //"Change"; - + } - + public String getInitialValue () { - + return this.viewer.getProject ().getName (); - + } - + public String isValid (String v) { @@ -84,21 +84,21 @@ public String isValid (String v) (v.trim ().length () == 0) ) { - + return Environment.getUIString (LanguageStrings.project, LanguageStrings.actions, LanguageStrings.renameproject, LanguageStrings.errors, LanguageStrings.novalue); //"Please enter a new name."; - + } v = v.trim (); - + if (!v.equalsIgnoreCase (this.viewer.getProject ().getName ())) { - + File newDir = new File (this.viewer.getProject ().getProjectDirectory ().getParentFile () + "/" + Utils.sanitizeForFilename (v)); if (newDir.exists ()) @@ -110,27 +110,27 @@ public String isValid (String v) LanguageStrings.errors, LanguageStrings.valueexists); //"A {project} with that name already exists."; - + } } - + return null; - + } - + public boolean onConfirm (String v) throws Exception { - + final String newName = v; final String oldName = this.viewer.getProject ().getName (); - + if (!newName.equals (oldName)) { - + final Project proj = this.viewer.getProject (); - + proj.setName (newName); // Save the project. @@ -172,25 +172,25 @@ public boolean onConfirm (String v) e); throw e; - + } } - final File newDir = new File (this.viewer.getProject ().getProjectDirectory ().getParentFile () + "/" + Utils.sanitizeForFilename (newName)); + final File newDir = new File (this.viewer.getProject ().getProjectDirectory ().getParentFile () + "/" + Utils.sanitizeForFilename (newName)); // Close the viewer. this.viewer.close (true, new ActionListener () - { - + { + public void actionPerformed (ActionEvent ev) { - + // Rename the dir. if (!proj.getProjectDirectory ().renameTo (newDir)) { - + Environment.logError ("Unable to rename project directory: " + proj.getProjectDirectory () + " to: " + @@ -202,26 +202,26 @@ public void actionPerformed (ActionEvent ev) LanguageStrings.renameproject, LanguageStrings.actionerror)); //"Unable to rename {project} directory, please contact Quoll Writer support for assistance."); - + return; - + } proj.setProjectDirectory (newDir); - + // Open the project again. try { - + Environment.openProject (proj); - + } catch (Exception e) { - + Environment.logError ("Unable to reopen project: " + proj, e); - + UIUtils.showErrorMessage (null, Environment.getUIString (LanguageStrings.project, LanguageStrings.actions, @@ -231,42 +231,44 @@ public void actionPerformed (ActionEvent ev) //"Unable to reopen project, please contact Quoll Writer support for assistance."); return; - + } - + + /* + TODO AbstractProjectViewer apv = Environment.getProjectViewer (proj); - + if (apv != null) { - + apv.fireProjectEventLater (proj.getObjectType (), ProjectEvent.RENAME); - - } + } +*/ } - + }); - + } - + return true; - + } - + public boolean onCancel () throws Exception { - + return true; - + } - + public Point getShowAt () { - + return null; - + } - + } diff --git a/src/com/quollwriter/ui/actionHandlers/RenameTagActionHandler.java b/src/main/java/com/quollwriter/ui/actionHandlers/RenameTagActionHandler.java similarity index 100% rename from src/com/quollwriter/ui/actionHandlers/RenameTagActionHandler.java rename to src/main/java/com/quollwriter/ui/actionHandlers/RenameTagActionHandler.java diff --git a/src/com/quollwriter/ui/actionHandlers/RenameWarmupActionHandler.java b/src/main/java/com/quollwriter/ui/actionHandlers/RenameWarmupActionHandler.java similarity index 100% rename from src/com/quollwriter/ui/actionHandlers/RenameWarmupActionHandler.java rename to src/main/java/com/quollwriter/ui/actionHandlers/RenameWarmupActionHandler.java diff --git a/src/com/quollwriter/ui/actionHandlers/SceneFormatDetails.java b/src/main/java/com/quollwriter/ui/actionHandlers/SceneFormatDetails.java similarity index 99% rename from src/com/quollwriter/ui/actionHandlers/SceneFormatDetails.java rename to src/main/java/com/quollwriter/ui/actionHandlers/SceneFormatDetails.java index b74e16d3..b88bf0d2 100644 --- a/src/com/quollwriter/ui/actionHandlers/SceneFormatDetails.java +++ b/src/main/java/com/quollwriter/ui/actionHandlers/SceneFormatDetails.java @@ -26,7 +26,7 @@ public String getIcon (Scene item) public String getTitle (Scene item) { - return Environment.getObjectTypeName (item.getObjectType ()); + return Environment.getObjectTypeName (item.getObjectType ()).getValue (); } diff --git a/src/com/quollwriter/ui/actionHandlers/SplitChapterActionHandler.java b/src/main/java/com/quollwriter/ui/actionHandlers/SplitChapterActionHandler.java similarity index 89% rename from src/com/quollwriter/ui/actionHandlers/SplitChapterActionHandler.java rename to src/main/java/com/quollwriter/ui/actionHandlers/SplitChapterActionHandler.java index e0e368c5..ae80b8cb 100644 --- a/src/com/quollwriter/ui/actionHandlers/SplitChapterActionHandler.java +++ b/src/main/java/com/quollwriter/ui/actionHandlers/SplitChapterActionHandler.java @@ -17,7 +17,6 @@ import com.quollwriter.ui.*; import com.quollwriter.ui.forms.*; import com.quollwriter.ui.panels.*; -import com.quollwriter.ui.components.Markup; import com.quollwriter.ui.components.QTextEditor; import com.quollwriter.text.*; @@ -37,7 +36,7 @@ public SplitChapterActionHandler (Chapter addFrom, AbstractFormPopup.ADD); this.addFrom = addFrom; - + this.nameField = new TextFormItem (Environment.getUIString (LanguageStrings.project, LanguageStrings.actions, LanguageStrings.splitchapter, @@ -45,7 +44,7 @@ public SplitChapterActionHandler (Chapter addFrom, LanguageStrings.newchaptername), //"New {Chapter} Name", null); - + final SplitChapterActionHandler _this = this; this.nameField.setDoOnReturnPressed (this.getSaveAction ()); @@ -63,7 +62,7 @@ public void handleCancel () @Override public Set getFormErrors () { - + Set errs = new LinkedHashSet (); if (this.nameField.getValue () == null) @@ -78,44 +77,44 @@ public Set getFormErrors () } return errs; - + } - + @Override public boolean handleSave () { String n = this.nameField.getValue (); - + try - { + { QuollEditorPanel panel = this.viewer.getEditorForChapter (this.addFrom); - + QTextEditor ed = panel.getEditor (); int start = ed.getSelectionStart (); int end = ed.getSelectionEnd (); - + if (start == end) { - + end = ed.getText ().length (); - + } - + int shiftBy = -1 * start; - + Chapter c = this.addFrom.getBook ().createChapterAfter (this.addFrom, n); this.object = c; StringWithMarkup edT = ed.getTextWithMarkup (); - + String newText = edT.getText ().substring (start, end); - + // Get the markup and shift Markup newM = new Markup (edT.getMarkup (), start, @@ -124,51 +123,51 @@ public boolean handleSave () c.setText (new StringWithMarkup (newText, newM)); - + this.viewer.saveObject (c, true); List toSave = new ArrayList (); - + // Handle notes, scenes, outline items. Set its = this.addFrom.getChapterItemsWithPositionBetween (start, end); - + for (ChapterItem it : its) { - + // Null out the standard Position objects and set the underlying start/end positions. it.shiftPositionBy (shiftBy); - + // Set the chapter. it.setChapter (c); // Save the item. toSave.add (it); - - } - + + } + this.viewer.saveObjects (toSave, true); - + ed.removeText (start, end - start); this.viewer.fireProjectEvent (this.object.getObjectType (), ProjectEvent.NEW, this.object); - + // Save the chapter. panel.saveObject (); - + // Reload existing chapter? panel.reinitIconColumn (); - + this.viewer.reloadChapterTree (); - + // Open the new chapter. - this.viewer.editChapter (c); - + this.viewer.editChapter (c); + } catch (Exception e) { @@ -219,22 +218,22 @@ private String getSelectedText () { QTextEditor ed = this.viewer.getEditorForChapter (this.addFrom).getEditor (); - + int start = ed.getSelectionStart (); int end = ed.getSelectionEnd (); if (start == end) { - + end = ed.getText ().length (); - + } - + return ed.getText ().substring (start, - end); - + end); + } - + @Override public String getTitle () { @@ -249,7 +248,7 @@ public String getTitle () @Override public Icon getIcon (int iconSizeType) { - + return Environment.getIcon (Chapter.OBJECT_TYPE + "-split", iconSizeType); @@ -262,52 +261,52 @@ public Set getFormItems (String selectedText) Set items = new LinkedHashSet (); items.add (this.nameField); - + String text = this.getSelectedText (); - + Paragraph para = new Paragraph (text, 0); - + //SentenceIterator iter = new SentenceIterator (text); int count = para.getWordCount (); - + //int count = UIUtils.getWordCount (text); - + // Get the first sentence. text = para.getFirstSentence ().getText (); - + //text = iter.next (); - + if (text != null) { - + text = text.trim (); - + if (text.length () > 150) { - + text = text.trim ().substring (0, 150) + Environment.getUIString (LanguageStrings.project, LanguageStrings.actions, LanguageStrings.splitchapter, LanguageStrings.moretextindicator); //"..."; - + } - + JTextArea t = new JTextArea (text); - + t.setLineWrap (true); t.setWrapStyleWord (true); t.setOpaque (false); t.setBorder (null); t.setEditable (false); t.setSize (new Dimension (300, 300)); - + Box p = new Box (BoxLayout.X_AXIS); p.add (t); p.setOpaque (false); - + items.add (new AnyFormItem (Environment.getUIString (LanguageStrings.project, LanguageStrings.actions, LanguageStrings.splitchapter, @@ -317,40 +316,40 @@ public Set getFormItems (String selectedText) p)); QTextEditor ed = this.viewer.getEditorForChapter (this.addFrom).getEditor (); - + int start = ed.getSelectionStart (); int end = ed.getSelectionEnd (); - + text = para.getLastSentence ().getText ();//iter.last (); - + if ((end > start) && (text != null) ) { - + text = text.trim (); - + if (text.length () > 150) { - + text = "... " + text.trim ().substring (text.length () - 150); - + } - + JTextArea et = new JTextArea (text); - + et.setLineWrap (true); et.setWrapStyleWord (true); et.setOpaque (false); et.setBorder (null); et.setEditable (false); et.setSize (new Dimension (300, 300)); - + Box ep = new Box (BoxLayout.X_AXIS); ep.add (et); ep.setOpaque (false); - + items.add (new AnyFormItem (Environment.getUIString (LanguageStrings.project, LanguageStrings.actions, LanguageStrings.splitchapter, @@ -358,9 +357,9 @@ public Set getFormItems (String selectedText) LanguageStrings.endat), //"End at", ep)); - + } - + items.add (new AnyFormItem (Environment.getUIString (LanguageStrings.project, LanguageStrings.actions, LanguageStrings.splitchapter, @@ -370,12 +369,12 @@ public Set getFormItems (String selectedText) UIUtils.createLabel (Environment.formatNumber (count)))); } - + if (text != null) { - + } - + return items; } diff --git a/src/com/quollwriter/ui/actionHandlers/TextInputActionHandler.java b/src/main/java/com/quollwriter/ui/actionHandlers/TextInputActionHandler.java similarity index 100% rename from src/com/quollwriter/ui/actionHandlers/TextInputActionHandler.java rename to src/main/java/com/quollwriter/ui/actionHandlers/TextInputActionHandler.java diff --git a/src/com/quollwriter/ui/actionHandlers/YesDeleteConfirmTextInputActionHandler.java b/src/main/java/com/quollwriter/ui/actionHandlers/YesDeleteConfirmTextInputActionHandler.java similarity index 100% rename from src/com/quollwriter/ui/actionHandlers/YesDeleteConfirmTextInputActionHandler.java rename to src/main/java/com/quollwriter/ui/actionHandlers/YesDeleteConfirmTextInputActionHandler.java diff --git a/src/com/quollwriter/ui/charts/AbstractQuollChart.java b/src/main/java/com/quollwriter/ui/charts/AbstractQuollChart.java similarity index 100% rename from src/com/quollwriter/ui/charts/AbstractQuollChart.java rename to src/main/java/com/quollwriter/ui/charts/AbstractQuollChart.java diff --git a/src/main/java/com/quollwriter/ui/charts/AllWordCountsChart.java b/src/main/java/com/quollwriter/ui/charts/AllWordCountsChart.java new file mode 100644 index 00000000..ac91936e --- /dev/null +++ b/src/main/java/com/quollwriter/ui/charts/AllWordCountsChart.java @@ -0,0 +1,414 @@ +package com.quollwriter.ui.charts; + +import java.awt.Component; +import java.awt.Font; +import java.awt.event.*; + +import java.util.*; + +import javax.swing.*; + +import org.jfree.chart.*; +import org.jfree.chart.ui.RectangleInsets; +import org.jfree.data.time.*; +import org.jfree.chart.plot.*; +import org.jfree.chart.labels.*; +import org.jfree.chart.axis.*; + +import com.quollwriter.ui.*; +import com.quollwriter.ui.panels.*; +import com.quollwriter.*; +import com.quollwriter.data.*; +import com.quollwriter.db.*; +import com.quollwriter.ui.components.ActionAdapter; +import com.quollwriter.ui.components.Header; + +public class AllWordCountsChart extends AbstractQuollChart +{ + + public static final String CHART_TYPE = "all-word-count"; + //public static final String CHART_TITLE = "Total Word Count"; + + private JComboBox displayB = null; + + private JFreeChart chart = null; + private JComponent controls = null; + + public AllWordCountsChart (AbstractProjectViewer pv) + { + + super (pv); + + } + + public void init (StatisticsPanel wcp) + throws GeneralException + { + + super.init (wcp); + + this.createControls (); + + } + + private void createControls () + { + + final AllWordCountsChart _this = this; + + Box b = new Box (BoxLayout.Y_AXIS); + + Header h = UIUtils.createBoldSubHeader (Environment.getUIString (LanguageStrings.charts, + LanguageStrings.allwordcounts, + LanguageStrings.labels, + LanguageStrings._for), + //"For", + null); + h.setAlignmentY (Component.TOP_ALIGNMENT); + + b.add (h); + + java.util.List prefix = new ArrayList<> (); + prefix.add (LanguageStrings.times); + + Vector displayItems = new Vector (); + displayItems.add (Environment.getUIString (prefix, + LanguageStrings.thisweek)); + //"This week"); + displayItems.add (Environment.getUIString (prefix, + LanguageStrings.lastweek)); + //displayItems.add ("Last week"); + displayItems.add (Environment.getUIString (prefix, + LanguageStrings.thismonth)); + //displayItems.add ("This month"); + displayItems.add (Environment.getUIString (prefix, + LanguageStrings.lastmonth)); + //displayItems.add ("Last month"); + displayItems.add (Environment.getUIString (prefix, + LanguageStrings.alltime)); + //displayItems.add ("All time"); + + b.add (Box.createVerticalStrut (5)); + + this.displayB = new JComboBox (displayItems); + this.displayB.setAlignmentX (Component.LEFT_ALIGNMENT); + this.displayB.setMaximumSize (displayB.getPreferredSize ()); + this.displayB.setAlignmentY (Component.TOP_ALIGNMENT); + + this.displayB.setSelectedIndex (0); + + this.displayB.addActionListener (new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + _this.updateChart (); + + } + + }); + + Box db = new Box (BoxLayout.X_AXIS); + db.setAlignmentX (Component.LEFT_ALIGNMENT); + db.setAlignmentY (Component.TOP_ALIGNMENT); + + db.add (Box.createHorizontalStrut (5)); + + db.add (displayB); + + b.add (db); + + b.add (Box.createVerticalStrut (10)); + + JComponent c = (JComponent) Box.createVerticalGlue (); + c.setOpaque (false); + b.add (c); + + this.controls = b; + + } + + private void createChart () + { + + int days = -1; + + Date minDate = null; + Date maxDate = new Date (); + + // This week. + if (this.displayB.getSelectedIndex () == 0) + { + + // Work out how many days there have been this week. + GregorianCalendar gc = new GregorianCalendar (); + + days = gc.get (Calendar.DAY_OF_WEEK) - gc.getFirstDayOfWeek (); + + if (days < 0) + { + + days -= 7; + + } + + gc.add (Calendar.DATE, + -1 * days); + + minDate = gc.getTime (); + + days++; + + } + + // Last week + if (this.displayB.getSelectedIndex () == 1) + { + + GregorianCalendar gc = new GregorianCalendar (); + + days = gc.get (Calendar.DAY_OF_WEEK) - gc.getFirstDayOfWeek (); + + if (days < 0) + { + + days -= 7; + + } + + gc.add (Calendar.DATE, + (-1 * days) - 1); + + maxDate = gc.getTime (); + + days += 7; + + gc.add (Calendar.DATE, + -6); + + minDate = gc.getTime (); + + days++; + + } + + // This month. + if (this.displayB.getSelectedIndex () == 2) + { + + GregorianCalendar gc = new GregorianCalendar (); + + days = gc.get (Calendar.DATE); + + gc.set (Calendar.DATE, + 1); + + minDate = gc.getTime (); + + days++; + + } + + // Last month. + if (this.displayB.getSelectedIndex () == 3) + { + + GregorianCalendar gc = new GregorianCalendar (); + + gc.add (Calendar.MONTH, + -1); + + days = gc.getActualMaximum (Calendar.DATE); + + gc.set (Calendar.DATE, + days); + + maxDate = gc.getTime (); + + gc.set (Calendar.DATE, + 1); + + minDate = gc.getTime (); + + days++; + + } + + // All time + if (this.displayB.getSelectedIndex () == 4) + { + + days = 1; + + } + + java.util.List prefix = new ArrayList<> (); + prefix.add (LanguageStrings.charts); + prefix.add (LanguageStrings.allwordcounts); + prefix.add (LanguageStrings.labels); + + final TimeSeriesCollection tsc = new TimeSeriesCollection (); + + try + { + + TimeSeries ts = new TimeSeries (Environment.getUIString (prefix, + LanguageStrings.xaxis)); + //"Date"); + + ProjectDataHandler pdh = (ProjectDataHandler) this.viewer.getDataHandler (Project.class); + + // Get all the word counts for the project. + List wordCounts = pdh.getWordCounts (this.viewer.getProject (), + 0); + + for (WordCount wc : wordCounts) + { + + if (ts.getValue (new Day (wc.getEnd ())) == null) + { + + ts.add (new Day (wc.getEnd ()), + wc.getCount ()); + + } + + } + + ts.setRangeDescription (null); + tsc.addSeries (ts); + + } catch (Exception e) + { + + Environment.logError ("Unable to get word counts", + e); + + UIUtils.showErrorMessage (this.parent, + "Unable to word counts"); + + return; + + } + + this.chart = QuollChartUtils.createTimeSeriesChart (Environment.getUIString (prefix, + LanguageStrings.xaxis), + //"Date", + Environment.getUIString (prefix, + LanguageStrings.yaxis), + //"Word Count", + tsc); + + this.chart.setBackgroundPaint (UIUtils.getComponentColor ()); + + XYPlot plot = (XYPlot) this.chart.getPlot (); + + PeriodAxis axis = (PeriodAxis) plot.getDomainAxis (); + + if (minDate != null) + { + + axis.setLowerBound (minDate.getTime ()); + + axis.setUpperBound (maxDate.getTime ()); + + } + + plot.setBackgroundPaint (UIUtils.getComponentColor ()); + plot.setDomainGridlinePaint (UIUtils.getBorderColor ()); + plot.setRangeGridlinePaint (UIUtils.getBorderColor ()); + plot.setAxisOffset (new RectangleInsets (5D, + 5D, + 5D, + 5D)); + + Font f = QuollChartUtils.getLabelFont (); + + plot.setDomainCrosshairVisible (true); + plot.setRangeCrosshairVisible (true); + plot.setDomainGridlinePaint (UIUtils.getColor ("#cfcfcf")); + plot.setRangeGridlinePaint (UIUtils.getColor ("#cfcfcf")); + plot.getDomainAxis ().setLabelFont (f); + plot.getDomainAxis ().setTickLabelFont (f); + plot.getRangeAxis ().setLabelFont (f); + plot.getRangeAxis ().setTickLabelFont (f); + + this.chart.removeLegend (); + + } + + public String getTitle () + { + + return Environment.getUIString (LanguageStrings.charts, + LanguageStrings.allwordcounts, + LanguageStrings.title); + //CHART_TITLE; + + } + + public String getType () + { + + return CHART_TYPE; + + } + + public JComponent getControls (boolean update) + { + + if (update) + { + + this.controls = null; + + } + + if (this.controls == null) + { + + this.createControls (); + + } + + return this.controls; + + } + + public JFreeChart getChart (boolean update) + { + + if (update) + { + + this.chart = null; + + } + + if (this.chart == null) + { + + this.createChart (); + + } + + return this.chart; + + } + + public JComponent getDetail (boolean update) + { + + return null; + + } + + public String toString () + { + + return this.getTitle (); + + } + +} diff --git a/src/main/java/com/quollwriter/ui/charts/PerChapterWordCountsChart.java b/src/main/java/com/quollwriter/ui/charts/PerChapterWordCountsChart.java new file mode 100644 index 00000000..01e45bde --- /dev/null +++ b/src/main/java/com/quollwriter/ui/charts/PerChapterWordCountsChart.java @@ -0,0 +1,858 @@ +package com.quollwriter.ui.charts; + +import java.awt.Component; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.event.*; + +import java.util.*; + +import javax.swing.*; +import javax.swing.border.*; +import javax.swing.tree.*; +import javax.swing.event.*; + +import org.jfree.chart.*; +import org.jfree.chart.ui.RectangleInsets; +import org.jfree.chart.ui.RectangleAnchor; +import org.jfree.data.time.*; +import org.jfree.chart.plot.*; +import org.jfree.chart.labels.*; +import org.jfree.chart.axis.*; +import org.jfree.data.category.*; +import org.jfree.chart.renderer.category.*; + +import static com.quollwriter.LanguageStrings.*; +import static com.quollwriter.Environment.getUIString; + +import com.quollwriter.*; +import com.quollwriter.data.*; +import com.quollwriter.ui.events.*; +import com.quollwriter.ui.*; +import com.quollwriter.ui.panels.*; +import com.quollwriter.db.*; +import com.quollwriter.ui.renderers.*; +import com.quollwriter.ui.components.Header; + +public class PerChapterWordCountsChart extends AbstractQuollChart +{ + + public static final String CHART_TYPE = "per-chapter-word-counts"; + //public static final String CHART_TITLE = "{Chapter} Word Counts"; + + private JFreeChart chart = null; + private JComponent detail = null; + private JComponent controls = null; + private JComboBox displayB = null; + private JTree chapters = null; + private JCheckBox showAvg = null; + private JCheckBox showTarget = null; + private JComponent opts = null; + + public PerChapterWordCountsChart (AbstractProjectViewer pv) + { + + super (pv); + + } + + public void init (StatisticsPanel wcp) + throws GeneralException + { + + super.init (wcp); + + this.createControls (); + + } + + private void createControls () + { + + java.util.List prefix = Arrays.asList (charts, perchapter, labels); + + final PerChapterWordCountsChart _this = this; + + Box b = new Box (BoxLayout.Y_AXIS); + b.setOpaque (false); + + this.showAvg = UIUtils.createCheckBox (getUIString (prefix,showaverage), + //"Show Average", + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + _this.updateChart (); + + } + + }); + + this.showTarget = UIUtils.createCheckBox (getUIString (prefix,showtarget), + //"Show Target", + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + TargetsData targets = _this.viewer.getProjectTargets (); + + if (targets.getMaxChapterCount () == 0) + { + + final java.util.List prefix = Arrays.asList (charts,perchapter,notarget,popup); + + UIUtils.createQuestionPopup (_this.viewer, + getUIString (prefix,title), + //"Set up Target", + Constants.TARGET_ICON_NAME, + getUIString (prefix,text), + //"You currently have no {chapter} word count target set up.

    Would you like to set the target now?

    Note: Targets can be accessed at any time from the {Project} menu.", + getUIString (prefix,buttons,confirm), + //"Yes, show me", + getUIString (prefix,buttons,cancel), + //"No, not now", + new ActionListener () + { + + @Override public void actionPerformed (ActionEvent ev) + { + + try + { + + _this.viewer.viewTargets (); + + } catch (Exception e) { + + Environment.logError ("Unable to show targets", + e); + + UIUtils.showErrorMessage (_this.viewer, + getUIString (charts,perchapter,notarget,actionerror)); + //)"Unable to show targets."); + + } + + } + + }, + null, + null, + null); + + _this.showTarget.setSelected (false); + + return; + + } + + _this.updateChart (); + + } + + }); + + this.opts = new Box (BoxLayout.Y_AXIS); + + b.add (this.opts); + + this.opts.setBorder (UIUtils.createPadding (0, 10, 0, 0)); + + this.opts.add (this.showAvg); + this.opts.add (this.showTarget); + + Header h = UIUtils.createBoldSubHeader (getUIString (prefix,_for), + //Environment.replaceObjectNames ("For"), + null); + h.setAlignmentY (Component.TOP_ALIGNMENT); + + b.add (h); + + Vector displayItems = new Vector (); + displayItems.add (getUIString (times, now)); + displayItems.add (getUIString (times, thisweek)); + displayItems.add (getUIString (times, lastweek)); + displayItems.add (getUIString (times, thismonth)); + displayItems.add (getUIString (times, lastmonth)); + displayItems.add (getUIString (times, alltime)); + + b.add (Box.createVerticalStrut (5)); + + this.displayB = new JComboBox (displayItems); + this.displayB.setAlignmentX (Component.LEFT_ALIGNMENT); + this.displayB.setMaximumSize (displayB.getPreferredSize ()); + + this.displayB.setAlignmentY (Component.TOP_ALIGNMENT); + + this.displayB.addActionListener (new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + _this.opts.setVisible (_this.displayB.getSelectedIndex () == 0); + + _this.updateChart (); + + } + + }); + + Box db = new Box (BoxLayout.X_AXIS); + db.setAlignmentX (Component.LEFT_ALIGNMENT); + db.setAlignmentY (Component.TOP_ALIGNMENT); + + db.add (Box.createHorizontalStrut (5)); + + db.add (this.displayB); + db.setMaximumSize (db.getPreferredSize ()); + + b.add (db); + + b.add (Box.createVerticalStrut (10)); + + h = UIUtils.createBoldSubHeader (getUIString (charts,perchapter,labels,forchapters), + //"For these {Chapters}"), + null); + h.setOpaque (false); + h.setAlignmentY (Component.TOP_ALIGNMENT); + + b.add (h); + + this.chapters = UIUtils.createTree (); + this.chapters.setModel (new DefaultTreeModel (UIUtils.createTree (this.viewer.getProject ().getBook (0), + new ArrayList (), /* exclude */ + this.viewer.getProject ().getBook (0).getChapters (), /* init */ + true))); + + this.chapters.getModel ().addTreeModelListener (new TreeModelAdapter () + { + + public void treeNodesChanged (TreeModelEvent ev) + { + + // Don't care what has changed, just trigger an update to the + // chart. + _this.updateChart (); + + } + + }); + + SelectableProjectTreeCellRenderer rend = new SelectableProjectTreeCellRenderer (); + + rend.setShowIcons (false); + + this.chapters.setCellRenderer (rend); + UIUtils.addSelectableListener (this.chapters); + + this.chapters.setOpaque (false); + + this.chapters.setRootVisible (false); + this.chapters.setShowsRootHandles (false); + this.chapters.setBorder (UIUtils.createPadding (0, 5, 0, 0)); + + // Never toggle. + this.chapters.setToggleClickCount (-1); + + this.chapters.setMaximumSize (this.chapters.getPreferredSize ()); + this.chapters.setAlignmentX (Component.LEFT_ALIGNMENT); + + b.add (this.chapters); + + this.controls = b; + + } + + private void createChart () + throws GeneralException + { + + if (this.displayB.getSelectedIndex () == 0) + { + + this.createCurrentChart (); + + return; + + } + + this.createHistoryChart (); + + } + + private void createCurrentChart () + throws GeneralException + { + + final PerChapterWordCountsChart _this = this; + + ChapterDataHandler dh = (ChapterDataHandler) this.viewer.getDataHandler (Chapter.class); + + Set selected = new HashSet (); + + UIUtils.getSelectedObjects ((DefaultMutableTreeNode) this.chapters.getModel ().getRoot (), + selected); + + int chapterCount = 0; + int totalWords = 0; + int maxWords = 0; + Chapter maxChap = null; + + final DefaultCategoryDataset ds = new DefaultCategoryDataset (); + + try + { + + for (Book book : this.viewer.getProject ().getBooks ()) + { + + for (Chapter c : book.getChapters ()) + { + + if (!selected.contains (c)) + { + + continue; + + } + + ChapterCounts cc = this.viewer.getChapterCounts (c); + + if (cc.getWordCount () > 0) + { + + chapterCount++; + + } + + totalWords += cc.getWordCount (); + + if (cc.getWordCount () > maxWords) + { + + maxChap = c; + maxWords = cc.getWordCount (); + + } + + ds.addValue (cc.getWordCount (), + "Chapters", + c.getName ()); + + } + + } + + } catch (Exception e) + { + + Environment.logError ("Unable to get word counts", + e); + + UIUtils.showErrorMessage (this.parent, + getUIString (charts,actionerror)); + //"Unable to show word counts"); + + return; + + } + + java.util.List prefix = Arrays.asList (charts, perchapter, labels); + + this.chart = QuollChartUtils.createBarChart (getUIString (prefix,xaxis), + //Environment.getObjectTypeNamePlural (Chapter.OBJECT_TYPE), + getUIString (prefix,yaxis), + //"Word Count", + ds); + + this.chart.setBackgroundPaint (UIUtils.getComponentColor ()); + this.chart.removeLegend (); + + CategoryPlot plot = (CategoryPlot) this.chart.getPlot (); + + final CategoryAxis domainAxis = plot.getDomainAxis(); + domainAxis.setCategoryLabelPositions (CategoryLabelPositions.STANDARD);//CategoryLabelPositions.createUpRotationLabelPositions (Math.PI / 0.5)); + + plot.setOrientation (PlotOrientation.HORIZONTAL); + plot.setRangeAxisLocation (AxisLocation.BOTTOM_OR_LEFT); + + QuollChartUtils.customizePlot (plot); + + CategoryToolTipGenerator ttgen = new StandardCategoryToolTipGenerator () + { + + public String generateToolTip (CategoryDataset dataset, + int row, + int column) + { + + DefaultCategoryDataset dsc = (DefaultCategoryDataset) dataset; + + Number n = dsc.getValue (row, + column); +/* + StringBuilder b = new StringBuilder (); + + b.append (Environment.formatNumber (n.intValue ())); + b.append (" words "); +*/ + return String.format (getUIString (charts, perchapter, tooltip), + Environment.formatNumber (n.intValue ())); + //b.toString (); + + } + + }; + + ((CategoryItemRenderer) plot.getRenderer ()).setSeriesToolTipGenerator (0, + ttgen); + + TargetsData ptargs = this.viewer.getProjectTargets (); + + int targetWords = ptargs.getMaxChapterCount (); + + double avgWords = 0; + + if (chapterCount > 0) + { + + avgWords = totalWords / chapterCount; + + } + + double diffAvgWords = avgWords - targetWords; + + if (this.showAvg.isSelected ()) + { + + String tgf = ""; + + if (targetWords > 0) + { + + tgf = String.format (getUIString (charts,perchapter,markers,averagesuffix), + //", %s%s target", + (diffAvgWords < 0 ? "" : "+") + Environment.formatNumber ((long) diffAvgWords)); + + } + + plot.addRangeMarker (QuollChartUtils.createMarker (String.format (getUIString (charts,perchapter,markers,average), + //"Avg %s%s", + Environment.formatNumber ((long) avgWords), + tgf), + avgWords, + 1, + RectangleAnchor.TOP_RIGHT)); + + } + + if (this.showTarget.isSelected ()) + { + + if (targetWords > 0) + { + + plot.addRangeMarker (QuollChartUtils.createMarker (String.format (getUIString (charts,perchapter,markers,target), + //"Target %s", + Environment.formatNumber (targetWords)), + targetWords, + -1, + RectangleAnchor.BOTTOM_LEFT)); + + } + + } + + int over = 0; + + for (Chapter c : selected) + { + + ChapterCounts cc = this.viewer.getChapterCounts (c); + + if (cc.getWordCount () > targetWords) + { + + over++; + + } + + } + + //((NumberAxis) plot.getRangeAxis ()).setAutoRangeIncludesZero (true); + + Set items = new LinkedHashSet (); + + if ((targetWords > 0) + && + (over > 0) + ) + { + + String t = String.format (getUIString (prefix, chaptersovertarget, text), + //"%s {Chapter%s} over target word count", + Environment.formatNumber (over)); + //(over == 1 ? "" : "s")); + + // TODO: Fix this nonsense. + ActionListener _null = null; + + final JLabel l = this.createWarningLabel (UIUtils.createClickableLabel (t, + null, + _null)); + + UIUtils.makeClickable (l, + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + Targets.showChaptersOverWordTarget (_this.viewer, + l); + + } + + }); + + l.setToolTipText (getUIString (prefix,chaptersovertarget,tooltip)); + //"Click to view the " + t); + + items.add (l); + + } + + items.add (this.createDetailLabel (String.format (getUIString (prefix,average), + //"%s - Average word count", + Environment.formatNumber ((long) avgWords)))); + + this.detail = QuollChartUtils.createDetailPanel (items); + + } + + private void createHistoryChart () + throws GeneralException + { + + java.util.List prefix = Arrays.asList (charts,perchapter,history,labels); + + int days = -1; + + Date minDate = null; + Date maxDate = new Date (); + + // This week. + if (this.displayB.getSelectedIndex () == 1) + { + + // Work out how many days there have been this week. + GregorianCalendar gc = new GregorianCalendar (); + + days = gc.get (Calendar.DAY_OF_WEEK) - gc.getFirstDayOfWeek (); + + if (days < 0) + { + + days -= 7; + + } + + gc.add (Calendar.DATE, + -1 * days); + + minDate = gc.getTime (); + + days++; + + } + + // Last week + if (this.displayB.getSelectedIndex () == 2) + { + + GregorianCalendar gc = new GregorianCalendar (); + + days = gc.get (Calendar.DAY_OF_WEEK) - gc.getFirstDayOfWeek (); + + if (days < 0) + { + + days -= 7; + + } + + gc.add (Calendar.DATE, + (-1 * days) - 1); + + maxDate = gc.getTime (); + + days += 7; + + gc.add (Calendar.DATE, + -6); + + minDate = gc.getTime (); + + days++; + + } + + // This month. + if (this.displayB.getSelectedIndex () == 3) + { + + GregorianCalendar gc = new GregorianCalendar (); + + days = gc.get (Calendar.DATE); + + gc.set (Calendar.DATE, + 1); + + minDate = gc.getTime (); + + days++; + + } + + // Last month. + if (this.displayB.getSelectedIndex () == 4) + { + + GregorianCalendar gc = new GregorianCalendar (); + + gc.add (Calendar.MONTH, + -1); + + days = gc.getActualMaximum (Calendar.DATE); + + gc.set (Calendar.DATE, + days); + + maxDate = gc.getTime (); + + gc.set (Calendar.DATE, + 1); + + minDate = gc.getTime (); + + days++; + + } + + // All time + if (this.displayB.getSelectedIndex () == 5) + { + + days = 1; + + } + + ChapterDataHandler dh = (ChapterDataHandler) this.viewer.getDataHandler (Chapter.class); + + Set selected = new HashSet (); + + UIUtils.getSelectedObjects ((DefaultMutableTreeNode) this.chapters.getModel ().getRoot (), + selected); + + final TimeSeriesCollection tscc = new TimeSeriesCollection (); + + try + { + + for (Book book : this.viewer.getProject ().getBooks ()) + { + + for (Chapter c : book.getChapters ()) + { + + if (!selected.contains (c)) + { + + continue; + + } + + TimeSeries ts = new TimeSeries (c.getName ()); + + // Get all the word counts for the chapter. + List wordCounts = dh.getWordCounts (c, + 0);// * days); + + for (WordCount wc : wordCounts) + { + + if (ts.getValue (new Day (wc.getEnd ())) == null) + { + + ts.add (new Day (wc.getEnd ()), + wc.getCount ()); + + } + + } + + ts.setRangeDescription (c.getName ()); + + tscc.addSeries (ts); + + } + + } + + } catch (Exception e) + { + + Environment.logError ("Unable to get word counts", + e); + + UIUtils.showErrorMessage (this.parent, + getUIString (charts,actionerror)); + //"Unable to show word counts"); + + return; + + } + + this.chart = QuollChartUtils.createTimeSeriesChart (getUIString (prefix,xaxis), + //"Date", + getUIString (prefix,yaxis), + //"Word Count", + tscc); + this.chart.setBackgroundPaint (UIUtils.getComponentColor ()); + + XYPlot plot = (XYPlot) this.chart.getPlot (); + + PeriodAxis axis = (PeriodAxis) plot.getDomainAxis (); + + if (minDate != null) + { + + axis.setLowerBound (minDate.getTime ()); + + axis.setUpperBound (maxDate.getTime ()); + + } + + plot.setBackgroundPaint (UIUtils.getComponentColor ()); + plot.setDomainGridlinePaint (UIUtils.getBorderColor ()); + plot.setRangeGridlinePaint (UIUtils.getBorderColor ()); + plot.setAxisOffset (new RectangleInsets (5D, + 5D, + 5D, + 5D)); + + Font f = QuollChartUtils.getLabelFont (); + + plot.setDomainCrosshairVisible (true); + plot.setRangeCrosshairVisible (true); + plot.setDomainGridlinePaint (UIUtils.getColor ("#cfcfcf")); + plot.setRangeGridlinePaint (UIUtils.getColor ("#cfcfcf")); + plot.getDomainAxis ().setLabelFont (f); + plot.getDomainAxis ().setTickLabelFont (f); + plot.getRangeAxis ().setLabelFont (f); + plot.getRangeAxis ().setTickLabelFont (f); + + //QuollChartUtils.customizePlot (xyplot); + + this.detail = null; + + } + + public String getTitle () + { + + return getUIString (charts,perchapter,title); + //return CHART_TITLE; + + } + + public String getType () + { + + return CHART_TYPE; + + } + + public JComponent getControls (boolean update) + throws GeneralException + { + + if (update) + { + + this.controls = null; + + } + + if (this.controls == null) + { + + this.createControls (); + + } + + return this.controls; + + } + + public JFreeChart getChart (boolean update) + throws GeneralException + { + + if (update) + { + + this.chart = null; + + } + + if (this.chart == null) + { + + this.createChart (); + + } + + return this.chart; + + } + + public JComponent getDetail (boolean update) + throws GeneralException + { + + if (update) + { + + this.detail = null; + + } + + if (this.detail == null) + { + + this.createChart (); + + } + + return this.detail; + + } + + public String toString () + { + + return this.getTitle (); + + } + +} diff --git a/src/com/quollwriter/ui/charts/QuollChartUtils.java b/src/main/java/com/quollwriter/ui/charts/QuollChartUtils.java similarity index 93% rename from src/com/quollwriter/ui/charts/QuollChartUtils.java rename to src/main/java/com/quollwriter/ui/charts/QuollChartUtils.java index 861e9ae8..cf004ea8 100644 --- a/src/com/quollwriter/ui/charts/QuollChartUtils.java +++ b/src/main/java/com/quollwriter/ui/charts/QuollChartUtils.java @@ -24,7 +24,8 @@ import org.jfree.chart.renderer.*; import org.jfree.chart.renderer.xy.*; import org.jfree.chart.renderer.category.*; -import org.jfree.ui.*; +import org.jfree.chart.ui.RectangleAnchor; +import org.jfree.chart.ui.RectangleInsets; import org.jfree.data.category.*; import org.jfree.data.time.*; import org.jfree.data.xy.XYDataset; @@ -179,8 +180,8 @@ public static void customizePlot (XYPlot plot) Font f = QuollChartUtils.getLabelFont (); plot.setBackgroundPaint (UIUtils.getComponentColor ()); - plot.setDomainGridlinePaint (Environment.getBorderColor ()); - plot.setRangeGridlinePaint (Environment.getBorderColor ()); + plot.setDomainGridlinePaint (UIUtils.getBorderColor ()); + plot.setRangeGridlinePaint (UIUtils.getBorderColor ()); plot.setAxisOffset (new RectangleInsets (5D, 5D, 5D, @@ -237,14 +238,14 @@ public static ValueMarker createMarker (String label, if (anchor == RectangleAnchor.TOP_LEFT) { - m.setLabelOffset (new org.jfree.ui.RectangleInsets ((s.height / 2) + 3, (s.width / 2) + 5, 0, 0)); + m.setLabelOffset (new RectangleInsets ((s.height / 2) + 3, (s.width / 2) + 5, 0, 0)); } if (anchor == RectangleAnchor.TOP_RIGHT) { - m.setLabelOffset (new org.jfree.ui.RectangleInsets ((s.height / 2) + 3, -1 * ((s.width / 2) + 5), 0, 0)); + m.setLabelOffset (new RectangleInsets ((s.height / 2) + 3, -1 * ((s.width / 2) + 5), 0, 0)); // TOP_RIGHT doesn't work so change to TOP_LEFT and -1 the left value. anchor = RectangleAnchor.TOP_LEFT; @@ -254,14 +255,14 @@ public static ValueMarker createMarker (String label, if (anchor == RectangleAnchor.BOTTOM_LEFT) { - m.setLabelOffset (new org.jfree.ui.RectangleInsets (0, (s.width / 2) + 5, (s.height / 2) + 3, 0)); + m.setLabelOffset (new RectangleInsets (0, (s.width / 2) + 5, (s.height / 2) + 3, 0)); } if (anchor == RectangleAnchor.BOTTOM_RIGHT) { - m.setLabelOffset (new org.jfree.ui.RectangleInsets (0, -1 * ((s.width / 2) + 5), (s.height / 2) + 3, 0)); + m.setLabelOffset (new RectangleInsets (0, -1 * ((s.width / 2) + 5), (s.height / 2) + 3, 0)); anchor = RectangleAnchor.BOTTOM_LEFT; @@ -294,8 +295,8 @@ public static void customizePlot (CategoryPlot plot) Font f = QuollChartUtils.getLabelFont (); plot.setBackgroundPaint (UIUtils.getComponentColor ()); - plot.setDomainGridlinePaint (Environment.getBorderColor ()); - plot.setRangeGridlinePaint (Environment.getBorderColor ()); + plot.setDomainGridlinePaint (UIUtils.getBorderColor ()); + plot.setRangeGridlinePaint (UIUtils.getBorderColor ()); plot.setAxisOffset (new RectangleInsets (5D, 5D, 5D, @@ -344,8 +345,8 @@ public static JFreeChart createBarChart (String xAxisTitle, // get a reference to the plot for further customisation... final CategoryPlot plot = chart.getCategoryPlot(); plot.setBackgroundPaint (UIUtils.getComponentColor ()); - plot.setDomainGridlinePaint (Environment.getBorderColor ()); - plot.setRangeGridlinePaint (Environment.getBorderColor ()); + plot.setDomainGridlinePaint (UIUtils.getBorderColor ()); + plot.setRangeGridlinePaint (UIUtils.getBorderColor ()); /* plot.setAxisOffset (new RectangleInsets (5D, 5D, @@ -409,8 +410,8 @@ public static JFreeChart createTimeSeriesChart (String xAxisTitle, XYPlot xyplot = (XYPlot) chart.getPlot (); xyplot.setBackgroundPaint (UIUtils.getComponentColor ()); - xyplot.setDomainGridlinePaint (Environment.getBorderColor ()); - xyplot.setRangeGridlinePaint (Environment.getBorderColor ()); + xyplot.setDomainGridlinePaint (UIUtils.getBorderColor ()); + xyplot.setRangeGridlinePaint (UIUtils.getBorderColor ()); /* xyplot.setAxisOffset (new RectangleInsets (5D, 5D, @@ -587,11 +588,13 @@ public static JFreeChart createSparkLine (TimeSeries series, XYLineAndShapeRenderer rend = new XYLineAndShapeRenderer (true, false); plot.setRenderer (rend); - rend.setBaseStroke (new java.awt.BasicStroke (10f)); + rend.setDefaultStroke (new java.awt.BasicStroke (10f)); rend.setSeriesStroke (0, new java.awt.BasicStroke (10f)); - rend.setBasePaint (UIUtils.getColor ("#516CA3")); + //rend.setBasePaint (UIUtils.getColor ("#516CA3")); + // TODO Check to see if this is correct to set? Replaces setBasePaint? + rend.setDefaultPaint (UIUtils.getColor ("#516CA3")); rend.setSeriesPaint (0, UIUtils.getColor ("#516CA3")); diff --git a/src/main/java/com/quollwriter/ui/charts/ReadabilityIndicesChart.java b/src/main/java/com/quollwriter/ui/charts/ReadabilityIndicesChart.java new file mode 100644 index 00000000..431138a5 --- /dev/null +++ b/src/main/java/com/quollwriter/ui/charts/ReadabilityIndicesChart.java @@ -0,0 +1,979 @@ +package com.quollwriter.ui.charts; + +import java.awt.Component; +import java.awt.Dimension; +import java.awt.BasicStroke; +import java.awt.event.*; + +import java.util.*; + +import javax.swing.*; +import javax.swing.border.*; +import javax.swing.tree.*; +import javax.swing.event.*; + +import org.jfree.chart.*; +import org.jfree.chart.ui.RectangleAnchor; +import org.jfree.data.time.*; +import org.jfree.data.category.*; +import org.jfree.chart.axis.*; +import org.jfree.chart.plot.*; + +import static com.quollwriter.LanguageStrings.*; +import static com.quollwriter.Environment.getUIString; + +import com.quollwriter.*; +import com.quollwriter.events.*; +import com.quollwriter.data.*; +import com.quollwriter.ui.events.*; +import com.quollwriter.ui.*; +import com.quollwriter.ui.panels.*; +import com.quollwriter.db.*; +import com.quollwriter.ui.renderers.*; +import com.quollwriter.ui.components.Header; + +public class ReadabilityIndicesChart extends AbstractQuollChart +{ + + public static final String CHART_TYPE = "readability-index"; + //public static final String CHART_TITLE = "Readability"; + + private JFreeChart chart = null; + private JComponent detail = null; + private JComponent controls = null; + private JCheckBox showGF = null; + private JCheckBox showFK = null; + private JTree chapters = null; + private JCheckBox showAvg = null; + private JCheckBox showTargets = null; + + public ReadabilityIndicesChart (AbstractProjectViewer pv) + { + + super (pv); + + } + + public void init (StatisticsPanel wcp) + throws GeneralException + { + + super.init (wcp); + + this.createControls (); + + } + + private void createControls () + { + + final java.util.List prefix = Arrays.asList (charts,readability,labels); + + final ReadabilityIndicesChart _this = this; + + Box b = new Box (BoxLayout.Y_AXIS); + b.setOpaque (false); + + this.showGF = UIUtils.createCheckBox (getUIString (prefix,showgf), + //"Show Gunning Fog", + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + _this.updateChart (); + + } + + }); + + this.showGF.setSelected (true); + + this.showGF.addActionListener (new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + if (!_this.showGF.isSelected ()) + { + + _this.showFK.setSelected (true); + + } + } + + }); + + this.showFK = UIUtils.createCheckBox (getUIString (prefix,showfk), + //"Show Flesch-Kincaid", + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + _this.updateChart (); + + } + + }); + + this.showFK.setSelected (true); + + this.showFK.addActionListener (new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + if (!_this.showFK.isSelected ()) + { + + _this.showGF.setSelected (true); + + } + } + + }); + + this.showAvg = UIUtils.createCheckBox (getUIString (prefix,showaverage), + //"Show Average", + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + _this.updateChart (); + + } + + }); + + this.showTargets = UIUtils.createCheckBox (getUIString (prefix,showtargets), + //)"Show Targets", + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + java.util.List prefix = Arrays.asList (charts,readability,notargets,popup); + + TargetsData targets = _this.viewer.getProjectTargets (); + + if ((targets.getReadabilityGF () == 0) + && + (targets.getReadabilityFK () == 0) + ) + { + + UIUtils.createQuestionPopup (_this.viewer, + getUIString (prefix,title), + //"Set up Targets", + Constants.TARGET_ICON_NAME, + getUIString (prefix,text), + //"You currently have no readability targets set up.

    Would you like to set the targets now?

    Note: Targets can be accessed at any time from the {Project} menu.", + getUIString (prefix,buttons,confirm), + //"Yes, show me", + getUIString (prefix,buttons,cancel), + //"No, not now", + new ActionListener () + { + + @Override public void actionPerformed (ActionEvent ev) + { + + try + { + + _this.viewer.viewTargets (); + + } catch (Exception e) { + + Environment.logError ("Unable to show targets", + e); + + UIUtils.showErrorMessage (_this.viewer, + getUIString (charts,readability,notargets,actionerror)); + //"Unable to show targets."); + + } + + } + + }, + null, + null, + null); + + _this.showTargets.setSelected (false); + + return; + + } + + _this.updateChart (); + + } + + }); + + Box opts = new Box (BoxLayout.Y_AXIS); + + b.add (opts); + + opts.setBorder (UIUtils.createPadding (0, 10, 0, 0)); + + opts.add (this.showFK); + opts.add (this.showGF); + opts.add (this.showAvg); + opts.add (this.showTargets); + + b.add (Box.createVerticalStrut (10)); + + Header h = UIUtils.createBoldSubHeader (getUIString (prefix,forchapters), + //"For these {Chapters}"), + null); + h.setOpaque (false); + h.setAlignmentY (Component.TOP_ALIGNMENT); + + b.add (h); + + Set init = new LinkedHashSet (); + + for (Chapter c : this.viewer.getProject ().getBook (0).getChapters ()) + { + + ChapterCounts cc = _this.viewer.getChapterCounts (c); + + if (cc == null) + { + + continue; + + } + + if (cc.getWordCount () > Constants.MIN_READABILITY_WORD_COUNT) + { + + init.add (c); + + } + + } + + this.chapters = new JTree (UIUtils.createTree (this.viewer.getProject ().getBook (0), + new ArrayList (), /* exclude */ + init, /* init */ + true)); + + this.chapters.setOpaque (false); + ToolTipManager.sharedInstance().registerComponent (this.chapters); + + this.chapters.getModel ().addTreeModelListener (new TreeModelAdapter () + { + + public void treeNodesChanged (TreeModelEvent ev) + { + + // Don't care what has changed, just trigger an update to the + // chart. + _this.updateChart (); + + } + + }); + + SelectableProjectTreeCellRenderer rend = new SelectableProjectTreeCellRenderer () + { + + @Override + public boolean shouldEnable (Object v) + { + + if (v instanceof Chapter) + { + + Chapter c = (Chapter) v; + + ChapterCounts cc = _this.viewer.getChapterCounts (c); + + return cc.getWordCount () >= Constants.MIN_READABILITY_WORD_COUNT; + + } + + return true; + + } + + @Override + public String getToolTipText (Object v) + { + + if (v instanceof Chapter) + { + + Chapter c = (Chapter) v; + + ChapterCounts cc = _this.viewer.getChapterCounts (c); + + if (cc.getWordCount () < Constants.MIN_READABILITY_WORD_COUNT) + { + + return getUIString (charts,readability,excluded,single,tooltip); +/* + if (cc.wordCount == 0) + { + + return Environment.replaceObjectNames ("This {chapter} is excluded because it has no words."); + + } else { + + return String.format (getUIString (charts,readability,exlcuded,tooltip) + //"This {chapter} is excluded because it only has %s word%s.", + Environment.formatNumber (cc.wordCount)); + //(cc.wordCount == 1 ? "" : "s"))); + + } +*/ + } + + } + + return super.getToolTipText (v); + + } + + }; + + rend.setShowIcons (false); + this.chapters.setCellRenderer (rend); + + this.chapters.addMouseListener (new MouseEventHandler () + { + + private void selectAllChildren (DefaultTreeModel model, + DefaultMutableTreeNode n, + boolean v) + { + + Enumeration en = n.children (); + + while (en.hasMoreElements ()) + { + + DefaultMutableTreeNode c = (DefaultMutableTreeNode) en.nextElement (); + + SelectableDataObject s = (SelectableDataObject) c.getUserObject (); + + s.selected = v; + + // Tell the model that something has changed. + model.nodeChanged (c); + + // Iterate. + this.selectAllChildren (model, + c, + v); + + } + + } + + @Override + public void handlePress (MouseEvent ev) + { + + TreePath tp = _this.chapters.getPathForLocation (ev.getX (), + ev.getY ()); + + if (tp != null) + { + + DefaultMutableTreeNode n = (DefaultMutableTreeNode) tp.getLastPathComponent (); + + // Tell the model that something has changed. + DefaultTreeModel model = (DefaultTreeModel) _this.chapters.getModel (); + + SelectableDataObject s = (SelectableDataObject) n.getUserObject (); + + if (s.obj instanceof Chapter) + { + + Chapter c = (Chapter) s.obj; + + ChapterCounts cc = _this.viewer.getChapterCounts (c); + + if (cc.getWordCount () < Constants.MIN_READABILITY_WORD_COUNT) + { + + return; + + } + + + } + + s.selected = !s.selected; + + model.nodeChanged (n); + + } + + } + + }); + + //UIUtils.addSelectableListener (this.chapters); + + this.chapters.setRootVisible (false); + this.chapters.setShowsRootHandles (false); + this.chapters.setScrollsOnExpand (true); + this.chapters.setBorder (UIUtils.createPadding (0, 5, 0, 0)); + + // Never toggle. + this.chapters.setToggleClickCount (-1); + + this.chapters.setAlignmentX (Component.LEFT_ALIGNMENT); + + b.add (this.chapters); + + this.controls = b; + + } + + private void createChart () + throws GeneralException + { + + java.util.List prefix = Arrays.asList (charts,readability,labels); + + final ReadabilityIndicesChart _this = this; + + ChapterDataHandler dh = (ChapterDataHandler) this.viewer.getDataHandler (Chapter.class); + + Set selected = new HashSet (); + + UIUtils.getSelectedObjects ((DefaultMutableTreeNode) this.chapters.getModel ().getRoot (), + selected); + + int chapterCount = 0; + float totalFK = 0; + float totalGF = 0; + float maxFK = 0; + float maxGF = 0; + float showMax = 0; + int filteredCount = 0; + + final DefaultCategoryDataset ds = new DefaultCategoryDataset (); + + try + { + + for (Book book : this.viewer.getProject ().getBooks ()) + { + + for (Chapter c : book.getChapters ()) + { + + ChapterCounts cc = this.viewer.getChapterCounts (c); + + // Filter out chapters with less than the min readability word count. + if (cc.getWordCount () < Constants.MIN_READABILITY_WORD_COUNT) + { + + filteredCount++; + + continue; + + } + + if (!selected.contains (c)) + { + + continue; + + } + + ReadabilityIndices ri = this.viewer.getReadabilityIndices (c); + + float fk = ri.getFleschKincaidGradeLevel (); + float gf = ri.getGunningFogIndex (); + + chapterCount++; + totalFK += fk; + totalGF += gf; + + maxFK = Math.max (maxFK, fk); + maxGF = Math.max (maxGF, gf); + + if (this.showFK.isSelected ()) + { + + ds.addValue (fk, + getUIString (prefix, LanguageStrings.fk), + //"Flesch-Kincaid", + c.getName ()); + + } + + if (this.showGF.isSelected ()) + { + + ds.addValue (gf, + getUIString (prefix, LanguageStrings.gf), + //"Gunning Fog", + c.getName ()); + + } + + } + + } + + } catch (Exception e) + { + + Environment.logError ("Unable to get word counts", + e); + + UIUtils.showErrorMessage (this.parent, + getUIString (charts,actionerror)); + //"Unable to word counts"); + + return; + + } + + this.chart = QuollChartUtils.createBarChart (getUIString (prefix,yaxis), + //Environment.getObjectTypeNamePlural (Chapter.OBJECT_TYPE), + getUIString (prefix,xaxis), + //"Reading Level", + ds); + + this.chart.setBackgroundPaint (UIUtils.getComponentColor ()); + + CategoryPlot plot = (CategoryPlot) this.chart.getPlot (); + + QuollChartUtils.customizePlot (plot); + + final CategoryAxis domainAxis = plot.getDomainAxis(); + domainAxis.setCategoryLabelPositions (CategoryLabelPositions.STANDARD);//CategoryLabelPositions.createUpRotationLabelPositions (Math.PI / 0.5)); + + plot.setOrientation (PlotOrientation.HORIZONTAL); + plot.setRangeAxisLocation (AxisLocation.BOTTOM_OR_LEFT); + + TargetsData ptargs = this.viewer.getProjectTargets (); + + int targetGF = ptargs.getReadabilityGF (); + int targetFK = ptargs.getReadabilityFK (); + + double avgGF = 0; + double avgFK = 0; + + if (chapterCount > 0) + { + + avgGF = totalGF / chapterCount; + avgFK = totalFK / chapterCount; + + } + + double diffAvgGF = avgGF - targetGF; + + boolean showGF = this.showGF.isSelected (); + boolean showFK = this.showFK.isSelected (); + + if (this.showAvg.isSelected ()) + { + + String tgf = ""; + + if ((targetGF > 0) + && + (showGF) + ) + { + + tgf = String.format (getUIString (charts,readability,markers,averagegfsuffix), + //", %s%s target", + (diffAvgGF < 0 ? "" : "+") + Environment.formatNumber (diffAvgGF)); + + } + + RectangleAnchor anch = RectangleAnchor.TOP_LEFT; + + if (avgGF > avgFK) + { + + anch = RectangleAnchor.TOP_RIGHT; + + } + + plot.addRangeMarker (QuollChartUtils.createMarker (String.format (getUIString (charts,readability,markers,averagegf), + //"Avg GF %s%s", + Environment.formatNumber (avgGF), + tgf), + avgGF, + 1, + anch)); + + String tfk = ""; + + if ((targetFK > 0) + && + (showFK) + ) + { + + double diffAvgFK = avgFK - targetFK; + + tfk = String.format (getUIString (charts,readability,markers,averagefksuffix), + //", %s%s target", + (diffAvgFK < 0 ? "" : "+") + Environment.formatNumber (diffAvgFK)); + + } + + anch = RectangleAnchor.TOP_LEFT; + + if (avgFK > avgGF) + { + + anch = RectangleAnchor.TOP_RIGHT; + + } + + plot.addRangeMarker (QuollChartUtils.createMarker (String.format (getUIString (charts,readability,markers,averagefk), + //"Avg FK %s%s", + Environment.formatNumber (avgFK), + tfk), + avgFK, + 0, + anch)); + + } + + if (this.showTargets.isSelected ()) + { + + RectangleAnchor anch = RectangleAnchor.BOTTOM_LEFT; + + if (targetGF > targetFK) + { + + anch = RectangleAnchor.BOTTOM_RIGHT; + + } + + if ((targetGF > 0) + && + (showGF) + ) + { + + plot.addRangeMarker (QuollChartUtils.createMarker (String.format (getUIString (charts,readability,markers,targetgf), + //"GF Target %s", + Environment.formatNumber (targetGF)), + targetGF, + -1, + anch)); + + } + + anch = RectangleAnchor.BOTTOM_LEFT; + + if (targetFK > targetGF) + { + + anch = RectangleAnchor.BOTTOM_RIGHT; + + } + + if (targetGF > maxGF) + { + + showMax = targetGF + 1; + + } + + if ((targetFK > 0) + && + (showFK) + ) + { + + plot.addRangeMarker (QuollChartUtils.createMarker (String.format (getUIString (charts,readability,markers,targetfk), + //"FK Target %s", + Environment.formatNumber (targetFK)), + targetFK, + -1, + anch)); + + } + + if ((targetFK > maxFK) + && + (targetFK > showMax) + ) + { + + showMax = targetFK + 1; + + } + + if (showMax > 0) + { + + ((NumberAxis) plot.getRangeAxis()).setUpperBound (showMax); + + } + + } + + int overGF = 0; + int overFK = 0; + + for (Chapter c : selected) + { + + ReadabilityIndices ri = this.viewer.getReadabilityIndices (c); + + float fk = ri.getFleschKincaidGradeLevel (); + float gf = ri.getGunningFogIndex (); + + if (fk > targetFK) + { + + overFK++; + + } + + if (gf > targetGF) + { + + overGF++; + + } + + } + + ((NumberAxis) plot.getRangeAxis ()).setAutoRangeIncludesZero (true); + + Set items = new LinkedHashSet (); + + if ((targetFK > 0) + && + (overFK > 0) + && + (showFK) + ) + { + + String t = String.format (getUIString (charts,readability,labels,overtargetfk), + //"%s {Chapter%s} over target Flesch-Kincaid", + Environment.formatNumber (overFK)); + //(overFK == 1 ? singular : plural)); + + // TODO: Fix this nonsense. + ActionListener _null = null; + + final JLabel l = this.createWarningLabel (UIUtils.createClickableLabel (t, + null, + _null)); + + UIUtils.makeClickable (l, + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + Targets.showChaptersOverReadabilityTarget (_this.viewer, + l); + + } + + }); + + l.setToolTipText (getUIString (charts,readability,labels,clicktoview)); + //"Click to view"); + + items.add (l); + + } + + if ((targetGF > 0) + && + (overGF > 0) + && + (showGF) + ) + { + + String t = String.format (getUIString (charts,readability,labels,overtargetgf), + //"%s {Chapter%s} over target Gunning Fog", + Environment.formatNumber (overGF)); + //(overGF == 1 ? "" : "s")); + + // TODO: Fix this nonsense. + ActionListener _null = null; + + final JLabel l = this.createDetailLabel (UIUtils.createClickableLabel (t, + null, + _null)); + + l.setIcon (Environment.getIcon (Constants.ERROR_ICON_NAME, + Constants.ICON_MENU)); + + UIUtils.makeClickable (l, + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + Targets.showChaptersOverReadabilityTarget (_this.viewer, + l); + + } + + }); + + l.setToolTipText (getUIString (charts,readability,labels,clicktoview)); + //"Click to view the " + t); + + items.add (l); + + } + + if (filteredCount > 0) + { + + items.add (this.createWarningLabel (String.format (getUIString (charts,readability,excluded,plural,text), + //"%s {chapters} have less than %s words and have been excluded", + Environment.formatNumber (filteredCount)))); + //Environment.formatNumber (Constants.MIN_READABILITY_WORD_COUNT)))); + + } + + if (showFK) + { + + items.add (this.createDetailLabel (String.format (getUIString (charts,readability,labels,averagefk), + //"%s - Average Flesch-Kincaid", + Environment.formatNumber (avgFK)))); + + } + + if (showGF) + { + + items.add (this.createDetailLabel (String.format (getUIString (charts,readability,labels,averagegf), + //"%s - Average Gunning Fog", + Environment.formatNumber (avgGF)))); + + } + + this.detail = QuollChartUtils.createDetailPanel (items); + + } + + public String getTitle () + { + + return getUIString (charts,readability,title); + //CHART_TITLE; + + } + + public String getType () + { + + return CHART_TYPE; + + } + + public JComponent getControls (boolean update) + { + + if (update) + { + + this.controls = null; + + } + + if (this.controls == null) + { + + this.createControls (); + + } + + return this.controls; + + } + + public JFreeChart getChart (boolean update) + throws GeneralException + { + + if (update) + { + + this.chart = null; + + } + + if (this.chart == null) + { + + this.createChart (); + + } + + return this.chart; + + } + + public JComponent getDetail (boolean update) + throws GeneralException + { + + if (update) + { + + this.detail = null; + + } + + if (this.detail == null) + { + + this.createChart (); + + } + + return this.detail; + + } + + public String toString () + { + + return this.getTitle (); + + } + +} diff --git a/src/main/java/com/quollwriter/ui/charts/SessionTimeChart.java b/src/main/java/com/quollwriter/ui/charts/SessionTimeChart.java new file mode 100644 index 00000000..11ce1c47 --- /dev/null +++ b/src/main/java/com/quollwriter/ui/charts/SessionTimeChart.java @@ -0,0 +1,700 @@ +package com.quollwriter.ui.charts; + +import java.awt.Component; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.event.*; + +import java.text.*; +import java.util.*; + +import javax.swing.*; +import javax.swing.border.*; +import javax.swing.tree.*; +import javax.swing.event.*; + +import org.jfree.chart.*; +import org.jfree.chart.labels.StandardXYToolTipGenerator; +import org.jfree.chart.labels.XYToolTipGenerator; +//import org.jfree.chart.ui.*; +import org.jfree.data.time.*; +import org.jfree.data.xy.XYDataset; +import org.jfree.chart.renderer.xy.*; +import org.jfree.chart.axis.*; +import org.jfree.chart.plot.*; + +import static com.quollwriter.LanguageStrings.*; +import static com.quollwriter.Environment.getUIString; + +import com.quollwriter.*; +import com.quollwriter.data.*; +import com.quollwriter.ui.events.*; +import com.quollwriter.ui.*; +import com.quollwriter.ui.panels.*; +import com.quollwriter.db.*; +import com.quollwriter.ui.renderers.*; +import com.quollwriter.ui.components.Header; + +public class SessionTimeChart extends AbstractQuollChart +{ + + public static final String CHART_TYPE = "session-time"; + //public static final String CHART_TITLE = "Session Length"; + + private JFreeChart chart = null; + private JComponent controls = null; + private JComboBox displayB = null; + private JCheckBox showAvg = null; + private JCheckBox showZeroWordCount = null; + private JComponent detail = null; + + public SessionTimeChart (AbstractViewer v) + { + + super (v); + + } + + public void init (StatisticsPanel wcp) + throws GeneralException + { + + super.init (wcp); + + this.createControls (); + + } + + private void createControls () + { + + final SessionTimeChart _this = this; + + Box b = new Box (BoxLayout.Y_AXIS); + b.setOpaque (false); + + Header h = UIUtils.createBoldSubHeader (getUIString (charts,sessionlength,labels,_for), + //"For", + null); + h.setAlignmentY (Component.TOP_ALIGNMENT); + + b.add (h); + + Vector displayItems = new Vector (); + displayItems.add (getUIString (times,thisweek));//"This week"); + displayItems.add (getUIString (times,lastweek));//"Last week"); + displayItems.add (getUIString (times,thismonth));//"This month"); + displayItems.add (getUIString (times,lastmonth));//"Last month"); + displayItems.add (getUIString (times,alltime));//"All time"); + + b.add (Box.createVerticalStrut (5)); + + this.displayB = new JComboBox (displayItems); + this.displayB.setAlignmentX (Component.LEFT_ALIGNMENT); + this.displayB.setMaximumSize (displayB.getPreferredSize ()); + + this.displayB.setAlignmentY (Component.TOP_ALIGNMENT); + + this.displayB.addActionListener (new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + _this.updateChart (); + + } + + }); + + Box db = new Box (BoxLayout.X_AXIS); + db.setAlignmentX (Component.LEFT_ALIGNMENT); + db.setAlignmentY (Component.TOP_ALIGNMENT); + + db.add (Box.createHorizontalStrut (5)); + + db.add (this.displayB); + db.setMaximumSize (db.getPreferredSize ()); + + b.add (db); + + b.add (Box.createVerticalStrut (10)); + + this.showAvg = UIUtils.createCheckBox (getUIString (charts,sessionlength,labels,showaverage),//"Show Average", + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + _this.updateChart (); + + } + + }); + + this.showZeroWordCount = UIUtils.createCheckBox (getUIString (charts,sessionlength,labels,showzero),//"Show zero word count sessions", + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + _this.updateChart (); + + } + + }); + + Box opts = new Box (BoxLayout.Y_AXIS); + + b.add (opts); + + opts.setBorder (UIUtils.createPadding (0, 10, 0, 0)); + + opts.add (this.showAvg); + opts.add (this.showZeroWordCount); + + this.controls = b; + + } + + private void createChart () + throws GeneralException + { + + java.util.List lprefix = Arrays.asList (charts,sessionlength,labels); + java.util.List mprefix = Arrays.asList (charts,sessionlength,markers); + + int days = -1; + + Date minDate = null; + Date maxDate = new Date (); + + // This week. + if (this.displayB.getSelectedIndex () == 0) + { + + // Work out how many days there have been this week. + GregorianCalendar gc = new GregorianCalendar (); + + days = gc.get (Calendar.DAY_OF_WEEK) - gc.getFirstDayOfWeek (); + + if (days < 0) + { + + days -= 7; + + } + + gc.add (Calendar.DATE, + -1 * days); + + minDate = gc.getTime (); + + } + + // Last week + if (this.displayB.getSelectedIndex () == 1) + { + + GregorianCalendar gc = new GregorianCalendar (); + + days = gc.get (Calendar.DAY_OF_WEEK) - gc.getFirstDayOfWeek (); + + if (days < 0) + { + + days -= 7; + + } + + gc.add (Calendar.DATE, + (-1 * days) - 1); + + maxDate = gc.getTime (); + + days += 7; + + gc.add (Calendar.DATE, + -6); + + minDate = gc.getTime (); + + } + + // This month. + if (this.displayB.getSelectedIndex () == 2) + { + + GregorianCalendar gc = new GregorianCalendar (); + + days = gc.get (Calendar.DATE); + + gc.set (Calendar.DATE, + 1); + + minDate = gc.getTime (); + + } + + // Last month. + if (this.displayB.getSelectedIndex () == 3) + { + + GregorianCalendar gc = new GregorianCalendar (); + + gc.add (Calendar.MONTH, + -1); + + days = gc.getActualMaximum (Calendar.DATE); + + gc.set (Calendar.DATE, + days); + + maxDate = gc.getTime (); + + gc.set (Calendar.DATE, + 1); + + minDate = gc.getTime (); + + } + + // All time + if (this.displayB.getSelectedIndex () == 4) + { + + days = -1; + + } + + long avg = 0; + long total = 0; + long sessions = 0; + long max = 0; + Date maxSessStart = null; + long zeroSessions = 0; + long zeroSessionsTime = 0; + long longSessions = 0; + long totalWords = 0; + + final TimePeriodValuesCollection ds = new TimePeriodValuesCollection (); + + try + { + + TimePeriodValues vals = new TimePeriodValues (getUIString (lprefix, LanguageStrings.sessions));//"Sessions"); + + for (Session s : Environment.getSessions (days)) + { + + int wc = s.getWordCount (); + + if ((!this.showZeroWordCount.isSelected ()) + && + (wc == 0) + ) + { + + continue; + + } + + if (days == -1) + { + + if (minDate == null) + { + + minDate = s.getStart (); + + } + + if (s.getStart ().before (minDate)) + { + + minDate = s.getStart (); + + } + + } + + long time = s.getEnd ().getTime () - s.getStart ().getTime (); + + if (time < 60 * 1000) + { + + continue; + + } + + if (wc == 0) + { + + zeroSessions++; + zeroSessionsTime += time; + + } + + totalWords += wc; + + total += time; + + if ((time > 1 * 60 * 60 * 1000) + && + (wc > 0) + ) + { + + longSessions++; + + } + + if (time > max) + { + + max = time; + maxSessStart = s.getStart (); + + } + + sessions++; + + vals.add (new SimpleTimePeriod (s.getStart (), + s.getEnd ()), + time); + + } + + ds.addSeries (vals); + + } catch (Exception e) + { + + Environment.logError ("Unable to get sessions", + e); + + UIUtils.showErrorMessage (this.parent, + getUIString (charts,actionerror)); + //"Unable to show sessions"); + + return; + + } + + if (sessions > 0) + { + + avg = total / sessions; + + } + + if (minDate == null) + { + + minDate = new Date (); + + } + + this.chart = QuollChartUtils.createTimeSeriesChart (getUIString (lprefix,xaxis),//"Date", + getUIString (lprefix,yaxis),//"Duration", + ds); + + this.chart.removeLegend (); + + this.chart.setBackgroundPaint (UIUtils.getComponentColor ()); + + XYPlot xyplot = (XYPlot) this.chart.getPlot (); + + PeriodAxis axis = (PeriodAxis) xyplot.getDomainAxis (); + + if (minDate != null) + { + + axis.setLowerBound (minDate.getTime ()); + + axis.setUpperBound (maxDate.getTime ()); + + } + + QuollChartUtils.customizePlot (xyplot); + + if (this.showAvg.isSelected ()) + { + + xyplot.addRangeMarker (QuollChartUtils.createMarker (String.format (getUIString (mprefix,average),//"Avg %s", + Utils.formatAsDuration (avg)), + avg, + 0)); + + } + + ((NumberAxis) xyplot.getRangeAxis ()).setAutoRangeIncludesZero (true); + + ((NumberAxis) xyplot.getRangeAxis ()).setNumberFormatOverride (new NumberFormat () + { + + @Override + public StringBuffer format (double number, + StringBuffer toAppendTo, + FieldPosition pos) + { + + return new StringBuffer (Utils.formatAsDuration (number)); + + } + + @Override + public StringBuffer format (long number, + StringBuffer toAppendTo, + FieldPosition pos) + { + + return new StringBuffer (Utils.formatAsDuration (number)); + + } + + @Override + public Number parse(String source, ParsePosition parsePosition) { + return null; + } + + }); + + long min = 60 * 1000; + long hour = 60 * min; + long day = 24 * hour; + + // Default 5 min tick. + long tick = 5 * min; + + if (max > (hour)) + { + + tick = 20 * min; + + } + + if (max > (3 * hour)) + { + + tick = 30 * min; + + } + + if (max > (6 * hour)) + { + + tick = hour; + + } + + if (max > (12 * hour)) + { + + tick = 2 * hour; + + } + + if (max > (day)) + { + + tick = 3 * hour; + + } + + if (max > (2 * day)) + { + + tick = 6 * hour; + + } + + if (max > (3 * day)) + { + + tick = 12 * hour; + + } + + if (max > (5 * day)) + { + + tick = day; + + } + + ((NumberAxis) xyplot.getRangeAxis ()).setTickUnit (new NumberTickUnit (tick) + { + + @Override + public String valueToString (double number) + { + + return Utils.formatAsDuration (number); + + } + + }); + + final SimpleDateFormat dateFormat = new SimpleDateFormat ("hh:mm a, EEE, dd MMM yyyy"); + + XYToolTipGenerator ttgen = new StandardXYToolTipGenerator () + { + + public String generateToolTip (XYDataset dataset, + int series, + int item) + { + + TimePeriodValuesCollection tsc = (TimePeriodValuesCollection) dataset; + + TimePeriodValues ts = tsc.getSeries (series); + + Number n = ts.getValue (item); + + return String.format (getUIString (charts,sessionlength,tooltip), + dateFormat.format (ts.getTimePeriod (item).getStart ()), + Utils.formatAsDuration (n.intValue ())); + + } + + }; + + ((XYBarRenderer) xyplot.getRenderer ()).setSeriesToolTipGenerator (0, + ttgen); + + Set items = new LinkedHashSet (); + + items.add (this.createDetailLabel (String.format (getUIString (lprefix,numsessions),//"%s - Session%s", + Environment.formatNumber (sessions)))); + //(sessions == 1 ? "" : "s")))); + + items.add (this.createDetailLabel (String.format (getUIString (lprefix,sessionsover1hr),//"%s - Session%s over 1 hour", + Environment.formatNumber (longSessions)))); + //(longSessions == 1 ? "" : "s")))); + + items.add (this.createDetailLabel (String.format (getUIString (lprefix,totalwords),//"%s - Words total", + Environment.formatNumber (totalWords)))); + + items.add (this.createDetailLabel (String.format (getUIString (lprefix,totalsessiontime),//"%s - Total session time", + Utils.formatAsDuration (total)))); + + items.add (this.createDetailLabel (String.format (getUIString (lprefix,averagesessionlength),//"%s - Average session length", + Utils.formatAsDuration (avg)))); + + if (maxSessStart != null) + { + + items.add (this.createDetailLabel (String.format (getUIString (lprefix,longestsession),//"%s, %s - Longest session", + Utils.formatAsDuration (max), + Environment.formatDateTime (maxSessStart)))); + + } + + if (this.showZeroWordCount.isSelected ()) + { + + items.add (this.createDetailLabel (String.format (getUIString (lprefix,numzerowordsessions),//"%s, %s - Zero word count sessions", + Environment.formatNumber (zeroSessions), + Utils.formatAsDuration (zeroSessionsTime)))); + + } + + this.detail = QuollChartUtils.createDetailPanel (items); + + } + + public String getTitle () + { + + return getUIString (charts,sessionlength,title); + //CHART_TITLE; + + } + + public String getType () + { + + return CHART_TYPE; + + } + + public JComponent getControls (boolean update) + throws GeneralException + { + + if (update) + { + + this.controls = null; + + } + + if (this.controls == null) + { + + this.createControls (); + + } + + return this.controls; + + } + + public JFreeChart getChart (boolean update) + throws GeneralException + { + + if (update) + { + + this.chart = null; + + } + + if (this.chart == null) + { + + this.createChart (); + + } + + return this.chart; + + } + + public JComponent getDetail (boolean update) + throws GeneralException + { + + if (update) + { + + this.chart = null; + + } + + if (this.chart == null) + { + + this.createChart (); + + } + + return this.detail; + + } + + public String toString () + { + + return this.getTitle (); + + } + +} diff --git a/src/main/java/com/quollwriter/ui/charts/SessionWordCountChart.java b/src/main/java/com/quollwriter/ui/charts/SessionWordCountChart.java new file mode 100644 index 00000000..319e6cc5 --- /dev/null +++ b/src/main/java/com/quollwriter/ui/charts/SessionWordCountChart.java @@ -0,0 +1,673 @@ +package com.quollwriter.ui.charts; + +import java.awt.Component; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.event.*; + +import java.text.*; +import java.util.*; + +import javax.swing.*; +import javax.swing.border.*; +import javax.swing.tree.*; +import javax.swing.event.*; + +import org.jfree.chart.*; +//import org.jfree.chart.ui.*; +import org.jfree.chart.labels.StandardXYToolTipGenerator; +import org.jfree.chart.labels.XYToolTipGenerator; +import org.jfree.data.time.*; +import org.jfree.data.xy.XYDataset; +import org.jfree.chart.renderer.xy.*; +import org.jfree.chart.axis.*; +import org.jfree.chart.plot.*; + +import static com.quollwriter.LanguageStrings.*; +import static com.quollwriter.Environment.getUIString; + +import com.quollwriter.*; +import com.quollwriter.data.*; +import com.quollwriter.ui.events.*; +import com.quollwriter.ui.*; +import com.quollwriter.ui.panels.*; +import com.quollwriter.db.*; +import com.quollwriter.ui.renderers.*; +import com.quollwriter.ui.components.Header; + +public class SessionWordCountChart extends AbstractQuollChart +{ + + public static final String CHART_TYPE = "session-word-count"; + //public static final String CHART_TITLE = "Session Word Count"; + + private JFreeChart chart = null; + private JComponent controls = null; + private JComboBox displayB = null; + private JCheckBox showAvg = null; + private JCheckBox showTarget = null; + private JComponent detail = null; + + public SessionWordCountChart (AbstractViewer v) + { + + super (v); + + } + + public void init (StatisticsPanel wcp) + throws GeneralException + { + + super.init (wcp); + + this.createControls (); + + } + + private void createControls () + { + + final SessionWordCountChart _this = this; + + Box b = new Box (BoxLayout.Y_AXIS); + b.setOpaque (false); + + Header h = UIUtils.createBoldSubHeader (getUIString (charts,sessionwordcount,labels,_for), + //"For"), + null); + h.setAlignmentY (Component.TOP_ALIGNMENT); + + b.add (h); + + Vector displayItems = new Vector (); + displayItems.add (getUIString (times,thisweek));//"This week"); + displayItems.add (getUIString (times,lastweek));//"Last week"); + displayItems.add (getUIString (times,thismonth));//"This month"); + displayItems.add (getUIString (times,lastmonth));//"Last month"); + displayItems.add (getUIString (times,alltime));//"All time"); + + b.add (Box.createVerticalStrut (5)); + + this.displayB = new JComboBox (displayItems); + this.displayB.setAlignmentX (Component.LEFT_ALIGNMENT); + this.displayB.setMaximumSize (displayB.getPreferredSize ()); + + this.displayB.setAlignmentY (Component.TOP_ALIGNMENT); + + this.displayB.addActionListener (new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + _this.updateChart (); + + } + + }); + + Box db = new Box (BoxLayout.X_AXIS); + db.setAlignmentX (Component.LEFT_ALIGNMENT); + db.setAlignmentY (Component.TOP_ALIGNMENT); + + db.add (Box.createHorizontalStrut (5)); + + db.add (this.displayB); + db.setMaximumSize (db.getPreferredSize ()); + + b.add (db); + + b.add (Box.createVerticalStrut (10)); + + this.showAvg = UIUtils.createCheckBox (getUIString (charts,sessionwordcount,labels,showaverage), + //"Show Average", + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + _this.updateChart (); + + } + + }); + + this.showTarget = UIUtils.createCheckBox (getUIString (charts,sessionwordcount,labels,showtarget),//"Show Target", + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + TargetsData targets = Environment.getUserTargets (); + + if ((targets.getMySessionWriting () == 0) + ) + { + + java.util.List prefix = Arrays.asList (charts,sessionwordcount,notarget,popup); + + UIUtils.createQuestionPopup (_this.viewer, + getUIString (prefix,title),//"Set up Target", + Constants.TARGET_ICON_NAME, + getUIString (prefix,text), + //"You currently have no writing targets set up.

    Would you like to set the targets now?

    Note: Targets can be accessed at any time from the {Project} menu.", + getUIString (prefix,buttons,confirm), + //"Yes, show me", + getUIString (prefix,buttons,cancel), + //"No, not now", + new ActionListener () + { + + @Override public void actionPerformed (ActionEvent ev) + { + + try + { + + _this.viewer.viewTargets (); + + } catch (Exception e) { + + Environment.logError ("Unable to show targets", + e); + + UIUtils.showErrorMessage (_this.viewer, + getUIString (charts,sessionwordcount,notarget,actionerror)); + //"Unable to show targets."); + + } + + } + + }, + null, + null, + null); + + _this.showTarget.setSelected (false); + + return; + + } + + _this.updateChart (); + + } + + }); + + Box opts = new Box (BoxLayout.Y_AXIS); + + b.add (opts); + + opts.setBorder (UIUtils.createPadding (0, 5, 0, 0)); + + opts.add (this.showAvg); + opts.add (this.showTarget); + + this.controls = b; + + } + + private void createChart () + throws GeneralException + { + + int days = -1; + + Date minDate = null; + Date maxDate = new Date (); + + // This week. + if (this.displayB.getSelectedIndex () == 0) + { + + // Work out how many days there have been this week. + GregorianCalendar gc = new GregorianCalendar (); + + days = gc.get (Calendar.DAY_OF_WEEK) - gc.getFirstDayOfWeek (); + + if (days < 0) + { + + days -= 7; + + } + + gc.add (Calendar.DATE, + -1 * days); + + minDate = gc.getTime (); + + } + + // Last week + if (this.displayB.getSelectedIndex () == 1) + { + + GregorianCalendar gc = new GregorianCalendar (); + + days = gc.get (Calendar.DAY_OF_WEEK) - gc.getFirstDayOfWeek (); + + if (days < 0) + { + + days -= 7; + + } + + gc.add (Calendar.DATE, + (-1 * days) - 1); + + maxDate = gc.getTime (); + + days += 7; + + gc.add (Calendar.DATE, + -6); + + minDate = gc.getTime (); + + } + + // This month. + if (this.displayB.getSelectedIndex () == 2) + { + + GregorianCalendar gc = new GregorianCalendar (); + + days = gc.get (Calendar.DATE); + + gc.set (Calendar.DATE, + 1); + + minDate = gc.getTime (); + + } + + // Last month. + if (this.displayB.getSelectedIndex () == 3) + { + + GregorianCalendar gc = new GregorianCalendar (); + + gc.add (Calendar.MONTH, + -1); + + days = gc.getActualMaximum (Calendar.DATE); + + gc.set (Calendar.DATE, + days); + + maxDate = gc.getTime (); + + gc.set (Calendar.DATE, + 1); + + minDate = gc.getTime (); + + } + + // All time + if (this.displayB.getSelectedIndex () == 4) + { + + days = -1; + + } + + long sessions = 0; + long totalWords = 0; + long totalTime = 0; + long sessionsAboveTarget = 0; + long longSessions = 0; + long maxTime = 0; + long maxWords = 0; + Session maxWordsSession = null; + Session longestSession = null; + int target = Environment.getUserTargets ().getMySessionWriting (); + + java.util.List prefix = Arrays.asList (charts,sessionwordcount,labels); + + final TimePeriodValuesCollection ds = new TimePeriodValuesCollection (); + + try + { + + TimePeriodValues vals = new TimePeriodValues (getUIString (prefix, LanguageStrings.sessions));//"Sessions"); + + for (Session s : Environment.getSessions (days)) + { + + int wc = s.getWordCount (); + + if (wc == 0) + { + + continue; + + } + + if (wc > target) + { + + sessionsAboveTarget++; + + } + + if (days == -1) + { + + if (minDate == null) + { + + minDate = s.getStart (); + + } + + if (s.getStart ().before (minDate)) + { + + minDate = s.getStart (); + + } + + } + + long time = s.getEnd ().getTime () - s.getStart ().getTime (); + + totalTime += time; + totalWords += wc; + sessions++; + + if (time > 60 * 60 * 1000) + { + + longSessions++; + + } + + if (time > maxTime) + { + + maxTime = time; + + longestSession = s; + + } + + if (wc > maxWords) + { + + maxWords = wc; + maxWordsSession = s; + + } + + vals.add (new SimpleTimePeriod (s.getStart (), + s.getEnd ()), + wc); + + } + + ds.addSeries (vals); + + } catch (Exception e) + { + + Environment.logError ("Unable to get sessions", + e); + + UIUtils.showErrorMessage (this.parent, + getUIString (charts,actionerror)); + //"Unable to sessions"); + + return; + + } + + if (minDate == null) + { + + minDate = new Date (); + + } + + this.chart = QuollChartUtils.createTimeSeriesChart (getUIString (prefix,xaxis),//"Date", + getUIString (prefix,yaxis),//"Word Count", + ds); + + this.chart.removeLegend (); + + XYPlot xyplot = (XYPlot) this.chart.getPlot (); + + PeriodAxis axis = (PeriodAxis) xyplot.getDomainAxis (); + + if (minDate != null) + { + + axis.setLowerBound (minDate.getTime ()); + + axis.setUpperBound (maxDate.getTime ()); + + } + + QuollChartUtils.customizePlot (xyplot); + + if (this.showAvg.isSelected ()) + { + + long avgWords = (sessions > 0 ? totalWords / sessions : 0); + + String t = ""; + + if (target > 0) + { + + double diffAvg = avgWords - target; + + t = String.format (getUIString (prefix,averagesuffix),//", %s%s target", + (diffAvg < 0 ? "" : "+") + Environment.formatNumber ((long) diffAvg)); + + } + + xyplot.addRangeMarker (QuollChartUtils.createMarker (String.format (getUIString (prefix,average),//"Avg %s%s", + Environment.formatNumber (avgWords), + t), + avgWords, + 0)); + + } + + if (this.showTarget.isSelected ()) + { + + if (target > maxWords) + { + + ((NumberAxis) xyplot.getRangeAxis()).setUpperBound (target + 100); + + } + xyplot.addRangeMarker (QuollChartUtils.createMarker (String.format (getUIString (prefix, LanguageStrings.target),//"Target %s", + Environment.formatNumber (target)), + target, + -1)); + + } + + this.chart.setBackgroundPaint (UIUtils.getComponentColor ()); + + final SimpleDateFormat dateFormat = new SimpleDateFormat ("hh:mm a, EEE, dd MMM yyyy"); + + XYToolTipGenerator ttgen = new StandardXYToolTipGenerator () + { + + public String generateToolTip (XYDataset dataset, + int series, + int item) + { + + TimePeriodValuesCollection tsc = (TimePeriodValuesCollection) dataset; + + TimePeriodValues ts = tsc.getSeries (series); + + Number n = ts.getValue (item); + + return String.format (getUIString (charts,sessionwordcount,tooltip), + dateFormat.format (ts.getTimePeriod (item).getStart ()), + Utils.formatAsDuration (n.intValue ())); +/* + StringBuilder b = new StringBuilder (); + + b.append (dateFormat.format (ts.getTimePeriod (item).getStart ())); + b.append (", "); + + b.append (Utils.formatAsDuration (n.intValue ())); + + return b.toString (); +*/ + } + + }; + + ((XYBarRenderer) xyplot.getRenderer ()).setSeriesToolTipGenerator (0, + ttgen); + + Set items = new LinkedHashSet (); + + items.add (this.createDetailLabel (String.format (getUIString (prefix,numsessions),//"%s - Session%s", + Environment.formatNumber (sessions)))); + //(sessions == 1 ? "" : "s")))); + + if (this.showTarget.isSelected ()) + { + + items.add (this.createDetailLabel (String.format (getUIString (prefix,sessionsovertarget),//"%s - Sessions above word target", + Environment.formatNumber (sessionsAboveTarget)))); + + } + + if (sessions > 0) + { + + // Work out number of sessions over target. + + items.add (this.createDetailLabel (String.format (getUIString (prefix,sessionsover1hr),//"%s - Session%s over 1 hr", + Environment.formatNumber (longSessions)))); + //(longSessions == 1 ? "" : "s")))); + + items.add (this.createDetailLabel (String.format (getUIString (prefix,averagesession),//"%s words, %s - Average session", + Environment.formatNumber (totalWords / sessions), + Utils.formatAsDuration (totalTime / sessions)))); + + items.add (this.createDetailLabel (String.format (getUIString (prefix,longestsession),//"%s words, %s, %s, - Longest session", + Environment.formatNumber (longestSession.getWordCount ()), + Utils.formatAsDuration (longestSession.getSessionDuration ()), + Environment.formatDateTime (longestSession.getStart ())))); + + items.add (this.createDetailLabel (String.format (getUIString (prefix,sessionmostwords),//"%s words, %s, %s - Session with most words", + Environment.formatNumber (maxWordsSession.getWordCount ()), + Utils.formatAsDuration (maxWordsSession.getSessionDuration ()), + Environment.formatDateTime (maxWordsSession.getStart ())))); + + } + + this.detail = QuollChartUtils.createDetailPanel (items); + + } + + public String getTitle () + { + + return getUIString (charts,sessionwordcount,title); + //CHART_TITLE; + + } + + public String getType () + { + + return CHART_TYPE; + + } + + public JComponent getControls (boolean update) + throws GeneralException + { + + if (update) + { + + this.controls = null; + + } + + if (this.controls == null) + { + + this.createControls (); + + } + + return this.controls; + + } + + public JFreeChart getChart (boolean update) + throws GeneralException + { + + if (update) + { + + this.chart = null; + + } + + if (this.chart == null) + { + + this.createChart (); + + } + + return this.chart; + + } + + public JComponent getDetail (boolean update) + throws GeneralException + { + + if (update) + { + + this.detail = null; + + } + + if (this.detail == null) + { + + this.createChart (); + + } + + return this.detail; + + } + + public String toString () + { + + return this.getTitle (); + + } + +} diff --git a/src/com/quollwriter/ui/components/Accordion.java b/src/main/java/com/quollwriter/ui/components/Accordion.java similarity index 100% rename from src/com/quollwriter/ui/components/Accordion.java rename to src/main/java/com/quollwriter/ui/components/Accordion.java diff --git a/src/com/quollwriter/ui/components/AccordionItem.java b/src/main/java/com/quollwriter/ui/components/AccordionItem.java similarity index 100% rename from src/com/quollwriter/ui/components/AccordionItem.java rename to src/main/java/com/quollwriter/ui/components/AccordionItem.java diff --git a/src/com/quollwriter/ui/components/ActionAdapter.java b/src/main/java/com/quollwriter/ui/components/ActionAdapter.java similarity index 100% rename from src/com/quollwriter/ui/components/ActionAdapter.java rename to src/main/java/com/quollwriter/ui/components/ActionAdapter.java diff --git a/src/com/quollwriter/ui/components/BlockPainter.java b/src/main/java/com/quollwriter/ui/components/BlockPainter.java similarity index 100% rename from src/com/quollwriter/ui/components/BlockPainter.java rename to src/main/java/com/quollwriter/ui/components/BlockPainter.java diff --git a/src/com/quollwriter/ui/components/CellEditorAdapter.java b/src/main/java/com/quollwriter/ui/components/CellEditorAdapter.java similarity index 100% rename from src/com/quollwriter/ui/components/CellEditorAdapter.java rename to src/main/java/com/quollwriter/ui/components/CellEditorAdapter.java diff --git a/src/com/quollwriter/ui/components/ChangeAdapter.java b/src/main/java/com/quollwriter/ui/components/ChangeAdapter.java similarity index 100% rename from src/com/quollwriter/ui/components/ChangeAdapter.java rename to src/main/java/com/quollwriter/ui/components/ChangeAdapter.java diff --git a/src/com/quollwriter/ui/components/ColorPainter.java b/src/main/java/com/quollwriter/ui/components/ColorPainter.java similarity index 100% rename from src/com/quollwriter/ui/components/ColorPainter.java rename to src/main/java/com/quollwriter/ui/components/ColorPainter.java diff --git a/src/main/java/com/quollwriter/ui/components/CompoundUndoManager.java b/src/main/java/com/quollwriter/ui/components/CompoundUndoManager.java new file mode 100644 index 00000000..23b20568 --- /dev/null +++ b/src/main/java/com/quollwriter/ui/components/CompoundUndoManager.java @@ -0,0 +1,398 @@ +/** + * Taken from: http://tips4java.wordpress.com/2008/10/27/compound-undo-manager/ + * + * All credit to: Rob Camick + */ +package com.quollwriter.ui.components; + +import java.awt.*; +import java.awt.event.*; + +import javax.swing.*; +import javax.swing.event.*; +import javax.swing.text.*; +import javax.swing.undo.*; + + +public class CompoundUndoManager extends UndoManager implements UndoableEditListener, + DocumentListener +{ + + + class MyCompoundEdit extends CompoundEdit + { + public boolean isInProgress () + { + // in order for the canUndo() and canRedo() methods to work + // assume that the compound edit is never in progress + + return false; + } + + public void undo () + throws CannotUndoException + { + // End the edit so future edits don't get absorbed by this edit + + if (compoundEdit != null) + { + compoundEdit.end (); + } + + super.undo (); + + // Always start a new compound edit after an undo + + compoundEdit = null; + } + } + + /* + * Perform the Undo and update the state of the undo/redo Actions + */ + class UndoAction extends AbstractAction + { + public UndoAction() + { + putValue (Action.NAME, + "Undo"); + putValue (Action.SHORT_DESCRIPTION, + getValue (Action.NAME)); + putValue (Action.MNEMONIC_KEY, + Integer.valueOf (KeyEvent.VK_U)); + putValue (Action.ACCELERATOR_KEY, + KeyStroke.getKeyStroke ("control Z")); + setEnabled (false); + } + + public void actionPerformed (ActionEvent e) + { + + try + { + undoManager.undo (); + textComponent.requestFocusInWindow (); + } catch (CannotUndoException ex) + { + } + + updateUndoState (); + redoAction.updateRedoState (); + } + + private void updateUndoState () + { + setEnabled (undoManager.canUndo ()); + } + } + + /* + * Perform the Redo and update the state of the undo/redo Actions + */ + class RedoAction extends AbstractAction + { + public RedoAction() + { + putValue (Action.NAME, + "Redo"); + putValue (Action.SHORT_DESCRIPTION, + getValue (Action.NAME)); + putValue (Action.MNEMONIC_KEY, + Integer.valueOf (KeyEvent.VK_R)); + putValue (Action.ACCELERATOR_KEY, + KeyStroke.getKeyStroke (KeyEvent.VK_Y, + InputEvent.CTRL_MASK)); + setEnabled (false); + } + + public void actionPerformed (ActionEvent e) + { + + try + { + undoManager.redo (); + textComponent.requestFocusInWindow (); + } catch (CannotRedoException ex) + { + } + + updateRedoState (); + undoAction.updateUndoState (); + } + + protected void updateRedoState () + { + setEnabled (undoManager.canRedo ()); + } + } + + private UndoManager undoManager; + private CompoundEdit compoundEdit; + private JTextComponent textComponent; + private UndoAction undoAction; + private RedoAction redoAction; + private boolean forceCompoundEdit = false; + + private boolean record = false; + + // These fields are used to help determine whether the edit is an + // incremental edit. The offset and length should increase by 1 for + // each character added or decrease by 1 for each character removed. + + private int lastOffset; + private int lastLength; + + public CompoundUndoManager(JTextComponent textComponent) + { + this.textComponent = textComponent; + undoManager = this; + undoAction = new UndoAction (); + redoAction = new RedoAction (); + textComponent.getDocument ().addUndoableEditListener (this); + } + + /* + ** Add a DocumentLister before the undo is done so we can position + ** the Caret correctly as each edit is undone. + */ + public void undo () + { + + textComponent.getDocument ().addDocumentListener (this); + super.undo (); + textComponent.getDocument ().removeDocumentListener (this); + + } + + /* + ** Add a DocumentLister before the redo is done so we can position + ** the Caret correctly as each edit is redone. + */ + public void redo () + { + textComponent.getDocument ().addDocumentListener (this); + super.redo (); + textComponent.getDocument ().removeDocumentListener (this); + } + + public void setRecordUndos (boolean v) + { + + this.record = v; + + } + + public boolean isRecordUndos () + { + + return this.record; + + } + + public void endCompoundEdit () + { + + this.forceCompoundEdit = false; + + compoundEdit.end (); + + compoundEdit = null; + + } + + public void startCompoundEdit () + { + + if (compoundEdit != null) + { + + compoundEdit.end (); + + compoundEdit = null; + + } + + this.forceCompoundEdit = true; + + } + + /* + ** Whenever an UndoableEdit happens the edit will either be absorbed + ** by the current compound edit or a new compound edit will be started + */ + public void undoableEditHappened (UndoableEditEvent e) + { + + // Start a new compound edit + + if (!this.record) + { + + return; + + } + + if (compoundEdit == null) + { + + compoundEdit = startCompoundEdit (e.getEdit ()); + + return; + } + + if (this.forceCompoundEdit) + { + + compoundEdit.addEdit (e.getEdit ()); + + return; + + } + + // Check for an attribute change + AbstractDocument.DefaultDocumentEvent event = (AbstractDocument.DefaultDocumentEvent) e.getEdit (); + + int offsetChange = textComponent.getCaretPosition () - lastOffset; + + if (event.getType ().equals (DocumentEvent.EventType.CHANGE)) + { + + if (offsetChange == 0) + { + + compoundEdit.end (); + compoundEdit = startCompoundEdit (e.getEdit ()); + + return; + } + } + + // Check for an incremental edit or backspace. + // The Change in Caret position and Document length should both be + // either 1 or -1. + +// int offsetChange = textComponent.getCaretPosition() - lastOffset; +// int lengthChange = textComponent.getDocument().getLength() - lastLength; + + + int lengthChange = textComponent.getDocument ().getLength () - lastLength; + + if ((offsetChange == lengthChange) && + (Math.abs (offsetChange) == 1)) + { + + String last = "x"; + + try + { + + last = this.textComponent.getText (this.textComponent.getCaretPosition () - 1, + 1); + + } catch (Exception ex) { + + // Ignore. + + } + + // Get the char, if it's white space then end the edit. + if (Character.isWhitespace (last.charAt (0))) + { + + compoundEdit.end (); + compoundEdit = startCompoundEdit (e.getEdit ()); + + } else { + + compoundEdit.addEdit (e.getEdit ()); + + } + + lastOffset = textComponent.getCaretPosition (); + lastLength = textComponent.getDocument ().getLength (); + + return; + } + + // Not incremental edit, end previous edit and start a new one + + compoundEdit.end (); + compoundEdit = startCompoundEdit (e.getEdit ()); + } + + /* + ** Each CompoundEdit will store a group of related incremental edits + ** (ie. each character typed or backspaced is an incremental edit) + */ + private CompoundEdit startCompoundEdit (UndoableEdit anEdit) + { + // Track Caret and Document information of this compound edit + + lastOffset = textComponent.getCaretPosition (); + lastLength = textComponent.getDocument ().getLength (); + + // The compound edit is used to store incremental edits + + compoundEdit = new MyCompoundEdit (); + compoundEdit.addEdit (anEdit); + + // The compound edit is added to the UndoManager. All incremental + // edits stored in the compound edit will be undone/redone at once + + addEdit (compoundEdit); + + undoAction.updateUndoState (); + redoAction.updateRedoState (); + + return compoundEdit; + } + + /* + * The Action to Undo changes to the Document. + * The state of the Action is managed by the CompoundUndoManager + */ + public Action getUndoAction () + { + return undoAction; + } + + /* + * The Action to Redo changes to the Document. + * The state of the Action is managed by the CompoundUndoManager + */ + public Action getRedoAction () + { + return redoAction; + } + +// +// Implement DocumentListener +// + /* + * Updates to the Document as a result of Undo/Redo will cause the + * Caret to be repositioned + */ + public void insertUpdate (final DocumentEvent e) + { + SwingUtilities.invokeLater (new Runnable () + { + public void run () + { + int offset = e.getOffset () + e.getLength (); + offset = Math.min (offset, + textComponent.getDocument ().getLength ()); + textComponent.setCaretPosition (offset); + } + }); + } + + public void removeUpdate (DocumentEvent e) + { + textComponent.setCaretPosition (e.getOffset ()); + } + + public void changedUpdate (DocumentEvent e) + { + } + +} diff --git a/src/com/quollwriter/ui/components/DnDTabbedPane.java b/src/main/java/com/quollwriter/ui/components/DnDTabbedPane.java similarity index 100% rename from src/com/quollwriter/ui/components/DnDTabbedPane.java rename to src/main/java/com/quollwriter/ui/components/DnDTabbedPane.java diff --git a/src/com/quollwriter/ui/components/DocumentAdapter.java b/src/main/java/com/quollwriter/ui/components/DocumentAdapter.java similarity index 100% rename from src/com/quollwriter/ui/components/DocumentAdapter.java rename to src/main/java/com/quollwriter/ui/components/DocumentAdapter.java diff --git a/src/com/quollwriter/ui/components/DragEvent.java b/src/main/java/com/quollwriter/ui/components/DragEvent.java similarity index 100% rename from src/com/quollwriter/ui/components/DragEvent.java rename to src/main/java/com/quollwriter/ui/components/DragEvent.java diff --git a/src/com/quollwriter/ui/components/DragListener.java b/src/main/java/com/quollwriter/ui/components/DragListener.java similarity index 100% rename from src/com/quollwriter/ui/components/DragListener.java rename to src/main/java/com/quollwriter/ui/components/DragListener.java diff --git a/src/com/quollwriter/ui/components/DraggableToolbar.java b/src/main/java/com/quollwriter/ui/components/DraggableToolbar.java similarity index 100% rename from src/com/quollwriter/ui/components/DraggableToolbar.java rename to src/main/java/com/quollwriter/ui/components/DraggableToolbar.java diff --git a/src/com/quollwriter/ui/components/Dragger.java b/src/main/java/com/quollwriter/ui/components/Dragger.java similarity index 100% rename from src/com/quollwriter/ui/components/Dragger.java rename to src/main/java/com/quollwriter/ui/components/Dragger.java diff --git a/src/com/quollwriter/ui/components/DropShadowBorderX.java b/src/main/java/com/quollwriter/ui/components/DropShadowBorderX.java similarity index 100% rename from src/com/quollwriter/ui/components/DropShadowBorderX.java rename to src/main/java/com/quollwriter/ui/components/DropShadowBorderX.java diff --git a/src/com/quollwriter/ui/components/FileFindField.java b/src/main/java/com/quollwriter/ui/components/FileFindField.java similarity index 100% rename from src/com/quollwriter/ui/components/FileFindField.java rename to src/main/java/com/quollwriter/ui/components/FileFindField.java diff --git a/src/com/quollwriter/ui/components/FindBar.java b/src/main/java/com/quollwriter/ui/components/FindBar.java similarity index 100% rename from src/com/quollwriter/ui/components/FindBar.java rename to src/main/java/com/quollwriter/ui/components/FindBar.java diff --git a/src/com/quollwriter/ui/components/FormattedTextField.java b/src/main/java/com/quollwriter/ui/components/FormattedTextField.java similarity index 100% rename from src/com/quollwriter/ui/components/FormattedTextField.java rename to src/main/java/com/quollwriter/ui/components/FormattedTextField.java diff --git a/src/com/quollwriter/ui/components/GradientPainter.java b/src/main/java/com/quollwriter/ui/components/GradientPainter.java similarity index 100% rename from src/com/quollwriter/ui/components/GradientPainter.java rename to src/main/java/com/quollwriter/ui/components/GradientPainter.java diff --git a/src/com/quollwriter/ui/components/GradientPanel.java b/src/main/java/com/quollwriter/ui/components/GradientPanel.java similarity index 100% rename from src/com/quollwriter/ui/components/GradientPanel.java rename to src/main/java/com/quollwriter/ui/components/GradientPanel.java diff --git a/src/com/quollwriter/ui/components/Header.java b/src/main/java/com/quollwriter/ui/components/Header.java similarity index 100% rename from src/com/quollwriter/ui/components/Header.java rename to src/main/java/com/quollwriter/ui/components/Header.java diff --git a/src/com/quollwriter/ui/components/HeaderFactory.java b/src/main/java/com/quollwriter/ui/components/HeaderFactory.java similarity index 100% rename from src/com/quollwriter/ui/components/HeaderFactory.java rename to src/main/java/com/quollwriter/ui/components/HeaderFactory.java diff --git a/src/com/quollwriter/ui/components/HyperlinkAdapter.java b/src/main/java/com/quollwriter/ui/components/HyperlinkAdapter.java similarity index 100% rename from src/com/quollwriter/ui/components/HyperlinkAdapter.java rename to src/main/java/com/quollwriter/ui/components/HyperlinkAdapter.java diff --git a/src/com/quollwriter/ui/components/IconProvider.java b/src/main/java/com/quollwriter/ui/components/IconProvider.java similarity index 100% rename from src/com/quollwriter/ui/components/IconProvider.java rename to src/main/java/com/quollwriter/ui/components/IconProvider.java diff --git a/src/com/quollwriter/ui/components/ImagePanel.java b/src/main/java/com/quollwriter/ui/components/ImagePanel.java similarity index 100% rename from src/com/quollwriter/ui/components/ImagePanel.java rename to src/main/java/com/quollwriter/ui/components/ImagePanel.java diff --git a/src/com/quollwriter/ui/components/ItemAdapter.java b/src/main/java/com/quollwriter/ui/components/ItemAdapter.java similarity index 100% rename from src/com/quollwriter/ui/components/ItemAdapter.java rename to src/main/java/com/quollwriter/ui/components/ItemAdapter.java diff --git a/src/com/quollwriter/ui/components/LineHighlighter.java b/src/main/java/com/quollwriter/ui/components/LineHighlighter.java similarity index 100% rename from src/com/quollwriter/ui/components/LineHighlighter.java rename to src/main/java/com/quollwriter/ui/components/LineHighlighter.java diff --git a/src/com/quollwriter/ui/components/LinePainter.java b/src/main/java/com/quollwriter/ui/components/LinePainter.java similarity index 100% rename from src/com/quollwriter/ui/components/LinePainter.java rename to src/main/java/com/quollwriter/ui/components/LinePainter.java diff --git a/src/com/quollwriter/ui/components/MultiImagePanel.java b/src/main/java/com/quollwriter/ui/components/MultiImagePanel.java similarity index 100% rename from src/com/quollwriter/ui/components/MultiImagePanel.java rename to src/main/java/com/quollwriter/ui/components/MultiImagePanel.java diff --git a/src/com/quollwriter/ui/components/NonEditableDefaultTableModel.java b/src/main/java/com/quollwriter/ui/components/NonEditableDefaultTableModel.java similarity index 100% rename from src/com/quollwriter/ui/components/NonEditableDefaultTableModel.java rename to src/main/java/com/quollwriter/ui/components/NonEditableDefaultTableModel.java diff --git a/src/com/quollwriter/ui/components/PaintProvider.java b/src/main/java/com/quollwriter/ui/components/PaintProvider.java similarity index 100% rename from src/com/quollwriter/ui/components/PaintProvider.java rename to src/main/java/com/quollwriter/ui/components/PaintProvider.java diff --git a/src/com/quollwriter/ui/components/PopupAdapter.java b/src/main/java/com/quollwriter/ui/components/PopupAdapter.java similarity index 100% rename from src/com/quollwriter/ui/components/PopupAdapter.java rename to src/main/java/com/quollwriter/ui/components/PopupAdapter.java diff --git a/src/com/quollwriter/ui/components/PopupEvent.java b/src/main/java/com/quollwriter/ui/components/PopupEvent.java similarity index 100% rename from src/com/quollwriter/ui/components/PopupEvent.java rename to src/main/java/com/quollwriter/ui/components/PopupEvent.java diff --git a/src/com/quollwriter/ui/components/PopupListener.java b/src/main/java/com/quollwriter/ui/components/PopupListener.java similarity index 100% rename from src/com/quollwriter/ui/components/PopupListener.java rename to src/main/java/com/quollwriter/ui/components/PopupListener.java diff --git a/src/com/quollwriter/ui/components/ProgressBar.java b/src/main/java/com/quollwriter/ui/components/ProgressBar.java similarity index 100% rename from src/com/quollwriter/ui/components/ProgressBar.java rename to src/main/java/com/quollwriter/ui/components/ProgressBar.java diff --git a/src/com/quollwriter/ui/components/QCaret.java b/src/main/java/com/quollwriter/ui/components/QCaret.java similarity index 100% rename from src/com/quollwriter/ui/components/QCaret.java rename to src/main/java/com/quollwriter/ui/components/QCaret.java diff --git a/src/com/quollwriter/ui/components/QPopup.java b/src/main/java/com/quollwriter/ui/components/QPopup.java similarity index 100% rename from src/com/quollwriter/ui/components/QPopup.java rename to src/main/java/com/quollwriter/ui/components/QPopup.java diff --git a/src/main/java/com/quollwriter/ui/components/QSpellChecker.java b/src/main/java/com/quollwriter/ui/components/QSpellChecker.java new file mode 100644 index 00000000..65d13fc0 --- /dev/null +++ b/src/main/java/com/quollwriter/ui/components/QSpellChecker.java @@ -0,0 +1,821 @@ +package com.quollwriter.ui.components; + +import java.awt.Color; +import java.awt.Point; +import java.awt.event.*; + +import java.util.List; +import java.util.Map; +import java.util.Timer; +import java.util.WeakHashMap; + +import javax.swing.*; +import javax.swing.event.*; +import javax.swing.text.*; + +import com.quollwriter.text.*; +import com.quollwriter.BlankTimerTask; +import com.quollwriter.DictionaryProvider2; +import com.quollwriter.synonyms.SynonymProvider; + +import com.quollwriter.ui.events.DictionaryChangedEvent; +import com.quollwriter.ui.events.DictionaryChangedListener; + +public class QSpellChecker implements DocumentListener, + CaretListener, + DictionaryChangedListener +{ + + private static final char NULL_CHAR = (char) 0; + + private QTextEditor text = null; + private com.quollwriter.ui.fx.SpellChecker checker = null; + private LinePainter painter = new LinePainter (Color.RED); + private Map elsToCheck = new WeakHashMap (); + private boolean enabled = false; + private int lastCaret = -1; + private char lastCharacterOver = QSpellChecker.NULL_CHAR; + private DictionaryProvider2 dictProvider = null; + private SynonymProvider synonymProvider = null; + + public QSpellChecker(QTextEditor text, + DictionaryProvider2 prov) + { + + this.text = text; + + this.text.getDocument ().addDocumentListener (this); + this.text.addCaretListener (this); + + this.setDictionaryProvider (prov); + + } + + public SynonymProvider getSynonymProvider () + { + + return this.synonymProvider; + + } + + public void setSynonymProvider (SynonymProvider sp) + { + + this.synonymProvider = sp; + + } + + public void setDictionaryProvider (DictionaryProvider2 dp) + { + + if (this.dictProvider != null) + { + + this.dictProvider.removeDictionaryChangedListener (this); + + } + + if (dp == null) + { + + this.checker = null; + this.dictProvider = null; + + return; + + } + + this.checker = dp.getSpellChecker (); + + //this.checker = new SpellChecker (); + + this.dictProvider = dp; + this.dictProvider.addDictionaryChangedListener (this); +/* + List dicts = dp.getDictionaries (); + + for (int i = 0; i < dicts.size (); i++) + { + + this.checker.addDictionary ((SpellDictionaryHashMap) (dicts.get (i))); + + } + + this.checker.setUserDictionary (dp.getUserDictionary ()); + + this.dictProvider = dp; + this.dictProvider.addDictionaryChangedListener (this); +*/ + } + + public void dictionaryChanged (DictionaryChangedEvent ev) + { + + if (ev.getType () == DictionaryChangedEvent.WORD_ADDED) + { + + // Recheck the document. + this.checkAll (); + + } + + if (ev.getType () == DictionaryChangedEvent.WORD_REMOVED) + { + + // Recheck the document. + this.checkAll (); + + } + + } + + public boolean isWordCorrect (Word word) + { + + if (this.checker == null) + { + + return false; + + } + + return this.checker.isCorrect (word); + +/* + if (w.isPunctuation ()) + { + + continue; + + } + + // See if the word is a number. + try + { + + Double.parseDouble (word); + + return true; + + } catch (Exception e) { + + // Not a number. + + } + + boolean v = this.checker.isCorrect (word) + || + this.checker.isIgnored (word); + + if (!v) + { + + // See if we have a synonym provider, if so check to see if the word ends with + // "s", "ed" or "er", if it does strip the ending then look for the synonym, if it has + // one then allow it through. + if (((word.endsWith ("s")) + || + (word.endsWith ("ed")) + || + (word.endsWith ("er")) + ) + && + (this.synonymProvider != null) + ) + { + + if (word.endsWith ("s")) + { + + word = word.substring (0, + word.length () - 1); + + } else { + + word = word.substring (0, + word.length () - 2); + + } + + try + { + + v = this.synonymProvider.hasSynonym (word); + + } catch (Exception e) { + + // Ignore it. + + } + + } + + } + + return v; +*/ + } + + public void addWord (String w) + { + + this.dictProvider.addWord (w); + + } + + public List getSuggestions (Point p) + { + + TextIterator ti = new TextIterator (this.text.getText ()); + + int start = this.text.viewToModel (p); + + Word word = null; + + if (start > -1) + { + + word = ti.getWordAt (start); + + } + + return this.getSuggestions (word); + + } + + public List getSuggestions (Word word) + { + + if (word == null) + { + + return null; + + } + + if (this.checker == null) + { + + return null; + + } + + return this.checker.getSuggestions (word); + + } + + public void checkElements (final int start) + { + + // Get the element for the offset. + final Element el; + + try + { + + el = ((AbstractDocument) this.text.getDocument ()).getParagraphElement (start); + + } catch (Exception ex) + { + + return; + + } + + // See if we have it scheduled for checking. + if (this.elsToCheck.containsKey (el)) + { + + // Already scheduled. + return; + + } + + this.elsToCheck.put (el, + el); + + final QSpellChecker _this = this; + + SwingUtilities.invokeLater (new Runnable () + { + + public void run () + { + + _this.checkElement (el); + + final Object o = new Object (); + + synchronized (o) + { + + _this.elsToCheck.remove (el); + + } + + } + + }); + + } + + private void checkElements (int start, + int length) + { + + int end = start + length; + + Document document = this.text.getDocument (); + + Element element; + + do + { + + try + { + + element = ((AbstractDocument) document).getParagraphElement (start); + + } catch (Exception ex) + { + + return; + + } + + this.checkElement (element); + + start = element.getEndOffset (); + + } while ((start <= end) && (start < document.getLength ())); + + } + + public void checkAll () + { + + Document document = this.text.getDocument (); + + for (int i = 0; i < document.getLength ();) + { + + Element el = null; + + try + { + + el = ((AbstractDocument) document).getParagraphElement (i); + + } catch (Exception e) + { + + // Need to funnel this back somewhere! + + } + + this.checkElements (i); + + i = el.getEndOffset (); + + } + + } + + private void clearAllHighlights () + { + + this.text.removeAllHighlights (this.painter); + + } + + public void checkElement (Element el) + { + + this.text.removeHighlightsForElement (el, + this.painter); + + if (!this.enabled) + { + + return; + + } + + int start = el.getStartOffset (); + + int docLength = this.text.getDocument ().getLength (); + + int end = el.getEndOffset (); + + if (start == end) + { + + return; + + } + + TextIterator ti = new TextIterator (this.text.getText ().substring (start, + end - 1)); + + List words = ti.getWords (); + + for (Word w : words) + { + + if (w.isPunctuation ()) + { + + continue; + + } + + //String word = w.getText (); + + if (!this.isWordCorrect (w)) + { + + try + { + + int wordStart = w.getAllTextStartOffset () + start; + int wordEnd = w.getAllTextEndOffset () + start; + + this.text.addHighlight (wordStart, + wordEnd, + this.painter, + false); + + } catch (Exception e) + { + + } + + } + + } + /* + int wordStart = -1; + int wordEnd = -1; + + while ((docTok.hasMoreWords ()) && + (docTok.getCurrentWordPosition () <= end)) + { + + String word = docTok.nextWord (); + + wordStart = docTok.getCurrentWordPosition (); + + wordEnd = docTok.getCurrentWordEnd (); + + if (wordEnd > docLength) + { + + wordEnd = docLength - 1; + + } + + if (wordStart >= wordEnd) + { + + continue; + + } + + if (!this.isWordCorrect (word)) + { + + try + { + + this.text.addHighlight (wordStart, + wordEnd, + this.painter, + false); + + } catch (Exception e) + { + + } + + } + + } + */ + + } + + public boolean isEnabled () + { + + return this.enabled; + + } + + public void enable (boolean v) + { + + boolean turningOn = (!this.enabled && v); + + this.enabled = v; + + if (turningOn) + { + + this.checkAll (); + + } else + { + + this.clearAllHighlights (); + + } + + } + + public void insertUpdate (DocumentEvent ev) + { + + if (!this.enabled) + { + + return; + + } + + if (ev.getLength () == 1) + { + + this.lastCharacterOver = QSpellChecker.NULL_CHAR; + + } + + if (ev.getLength () == 1) + { + + String t = null; + + try + { + + t = ev.getDocument ().getText (ev.getOffset (), + ev.getLength ()); + + } catch (Exception e) { + + // Wtf... + return; + + } + + if (t.trim ().length () == 0) + { + + // Check the previous element. + Element element; + + try + { + + element = ((AbstractDocument) ev.getDocument ()).getParagraphElement (ev.getOffset ()); + + } catch (Exception ex) + { + + return; + + } + + this.checkElement (element); + + } + + } else { + + this.checkElements (ev.getOffset (), + ev.getLength ()); + + } + + } + + public void changedUpdate (DocumentEvent ev) + { + + } + + public void removeUpdate (DocumentEvent ev) + { + + if (!this.enabled) + { + + return; + + } + + if (ev.getOffset () == 0) + { + + return; + + } + + if (ev.getLength () == 1) + { + + this.lastCharacterOver = QSpellChecker.NULL_CHAR; + + } + + if (ev.getLength () == 1) + { + + // Check the previous char, if there is one then don't check, if it's whitespace then check. + if (ev.getOffset () > 0) + { + + String t = null; + + try + { + + t = ev.getDocument ().getText (ev.getOffset () - 1, + ev.getLength ()); + + } catch (Exception e) { + + // Wtf... + return; + + } + + // Check the previous element. + Element element; + + try + { + + element = ((AbstractDocument) ev.getDocument ()).getParagraphElement (ev.getOffset ()); + + } catch (Exception ex) + { + + return; + + } + + this.checkElement (element); + + return; + + } + + } else { + + this.checkElements (ev.getOffset (), + ev.getLength ()); + + } + + } + + public void caretUpdate (CaretEvent ev) + { + + if (!this.enabled) + { + + return; + + } + + if (this.lastCaret == -1) + { + + this.lastCaret = ev.getDot (); + + return; + + } + + Document document = this.text.getDocument (); + + try + { + + Element oldEl = ((AbstractDocument) document).getParagraphElement (this.lastCaret); + Element newEl = ((AbstractDocument) document).getParagraphElement (ev.getDot ()); + + if (oldEl != newEl) + { + + this.checkElements (this.lastCaret); + + } else + { + + boolean d = false; + + if ((Math.max (this.lastCaret, + ev.getDot ()) - Math.min (this.lastCaret, + ev.getDot ())) > 1) + { + + this.checkElement (newEl); + + } else + { + + if (this.lastCharacterOver != QSpellChecker.NULL_CHAR) + { + + String text = this.text.getText (); + + if ((text.length () == 0) || + (ev.getDot () > (text.length () - 1))) + { + + return; + + } + + if ((Character.isWhitespace (this.lastCharacterOver)) && + (Character.isWhitespace (text.charAt (ev.getDot ())))) + { + + d = true; + + } + + try + { + + if (ev.getDot () < this.lastCaret) + { + + if ((!Character.isWhitespace (this.lastCharacterOver)) && + (Character.isWhitespace (text.charAt (ev.getDot ())))) + { + + d = true; + + } + + } else + { + + if (Character.isWhitespace (this.lastCharacterOver)) + { + + d = true; + + } + + } + + } catch (Exception e) + { + + com.quollwriter.Environment.logError ("HERE: ", + e); + + } + + } + + } + + if (d) + { + + this.checkElement (newEl); + + } + + } + + } catch (Exception e) + { + + return; + + } + + this.lastCaret = ev.getDot (); + + String t = this.text.getText (); + + if ((this.lastCaret >= t.length ()) || + (this.lastCaret < 0)) + { + + return; + + } + + this.lastCharacterOver = this.text.getText ().charAt (this.lastCaret); + + } + +} diff --git a/src/com/quollwriter/ui/components/QStyledEditorKit.java b/src/main/java/com/quollwriter/ui/components/QStyledEditorKit.java similarity index 100% rename from src/com/quollwriter/ui/components/QStyledEditorKit.java rename to src/main/java/com/quollwriter/ui/components/QStyledEditorKit.java diff --git a/src/main/java/com/quollwriter/ui/components/QTextEditor.java b/src/main/java/com/quollwriter/ui/components/QTextEditor.java new file mode 100644 index 00000000..75d5c2af --- /dev/null +++ b/src/main/java/com/quollwriter/ui/components/QTextEditor.java @@ -0,0 +1,1672 @@ +package com.quollwriter.ui.components; + +import java.awt.*; +import java.awt.event.*; + +import java.awt.datatransfer.*; + +import java.io.*; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import java.util.LinkedHashSet; + +import javax.swing.*; +import javax.swing.event.*; +import javax.swing.text.*; +import javax.swing.undo.*; + +import com.quollwriter.StringWithMarkup; +import com.quollwriter.DictionaryProvider2; + +import com.quollwriter.text.*; + +import com.quollwriter.synonyms.SynonymProvider; + +import com.quollwriter.*; + +public class QTextEditor extends JTextPane implements TextStylable +{ + + public static final String ALIGN_LEFT = "Left"; + public static final String ALIGN_RIGHT = "Right"; + public static final String ALIGN_JUSTIFIED = "Justified"; + + public static final String PASTE_ACTION_NAME = "__paste"; + public static final String COPY_ACTION_NAME = "__copy"; + public static final String CUT_ACTION_NAME = "__cut"; + public static final String UNDO_ACTION_NAME = "__undo"; + public static final String REDO_ACTION_NAME = "__redo"; + public static final String BOLD_ACTION_NAME = "bold"; + public static final String ITALIC_ACTION_NAME = "italic"; + public static final String UNDERLINE_ACTION_NAME = "underline"; + public static final String PRINT_ACTION_NAME = "print"; + + public CompoundUndoManager undoManager = null; + public QSpellChecker spellChecker = null; + private boolean loading = false; + public SimpleAttributeSet styles = new SimpleAttributeSet (); + private DefaultStyledDocument doc = null; + public Style sectionBreakStyle = null; + private String sectionBreak = null; + private Set styleChangeListeners = new LinkedHashSet (); + private LineHighlighter lineHighlighter = null; + private boolean canCopy = true; + private boolean canFormat = true; + + public QTextEditor(DictionaryProvider2 prov, + boolean spellCheckerEnabled) + { + + this.setCaret (new QCaret ()); + this.getCaret ().setBlinkRate (500); + + this.undoManager = new CompoundUndoManager (this); + + // Adapted from: https://community.oracle.com/thread/2376090 + // When there is a long contiguous piece of text it will prevent the text from + // wrapping. This allows the wrapping to occur. However it does not prevent the + // word wrapping from going nuts in text after this. + // The bug only triggers when the text is wider than the view. + /* + final ViewFactory vf = new ViewFactory () + { + + @Override + public View create (Element elem) + { + + String kind = elem.getName(); + + if (kind != null) + { + + if (kind.equals (AbstractDocument.ContentElementName)) + { + + return new LabelView (elem) + { + + @Override + public float getMinimumSpan (int axis) + { + + if (axis == View.X_AXIS) + { + + return 0; + + } + + if (axis == View.Y_AXIS) + { + + return super.getMinimumSpan (axis); + + } + + throw new IllegalArgumentException ("Invalid axis: " + axis); + + } + + }; + + } else if (kind.equals(AbstractDocument.ParagraphElementName)) { + return new ParagraphView(elem); + } else if (kind.equals(AbstractDocument.SectionElementName)) { + return new BoxView(elem, View.Y_AXIS); + } else if (kind.equals(StyleConstants.ComponentElementName)) { + return new ComponentView(elem); + } else if (kind.equals(StyleConstants.IconElementName)) { + return new IconView(elem); + } + + } + + // default to text display + return new LabelView (elem); + + } + + }; +*/ + this.setEditorKit (new QStyledEditorKit ()); +/* + { + + @Override + public ViewFactory getViewFactory () + { + + return vf; + + } + + }); + */ + this.initDocument (); + + this.setMargin (new Insets (5, + 5, + 0, + 5)); + + final QTextEditor _this = this; + + this.undoManager.discardAllEdits (); + + // Get the files. + this.spellChecker = new QSpellChecker (this, + prov); + this.spellChecker.enable (spellCheckerEnabled); + + ActionMap am = this.getActionMap (); + + am.put (REDO_ACTION_NAME, + new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + if (_this.undoManager.canRedo ()) + { + + _this.undoManager.redo (); + + } + + } + + }); + + am.put (UNDO_ACTION_NAME, + new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + if (_this.undoManager.canUndo ()) + { + + _this.undoManager.undo (); + + } + + } + + }); + + am.put (PRINT_ACTION_NAME, + new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + try + { + + _this._print (); + + } catch (Exception e) + { + + // e.printStackTrace (); + + } + + } + + }); + + am.put (BOLD_ACTION_NAME, + new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + _this.toggleBold (); + + } + + }); + + am.put (ITALIC_ACTION_NAME, + new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + _this.toggleItalic (); + + } + + }); + + am.put (UNDERLINE_ACTION_NAME, + new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + _this.toggleUnderline (); + + } + + }); + + am.put (PASTE_ACTION_NAME, + new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + _this.paste (); + + } + + }); + + am.put (COPY_ACTION_NAME, + new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + _this.copy (); + + } + + }); + + am.put (CUT_ACTION_NAME, + new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + _this.cut (); + + } + + }); +/* + am.put (UNDO_ACTION_NAME, + this.getEditor ().getUndoManager ().getUndoAction ()); + + am.put (REDO_ACTION_NAME, + this.getEditor ().getUndoManager ().getRedoAction ()); + */ +/* + am.put ("redo", + new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + if (_this.undoManager.canRedo ()) + { + + _this.undoManager.redo (); + + } + + } + + }); + + am.put ("undo", + new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + if (_this.undoManager.canUndo ()) + { + + _this.undoManager.undo (); + + } + + } + + }); + + am.put ("print", + new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + try + { + + _this._print (); + + } catch (Exception e) + { + + // e.printStackTrace (); + + } + + } + + }); + + am.put ("bold", + new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + _this.toggleBold (); + + } + + }); + + am.put ("italic", + new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + _this.toggleItalic (); + + } + + }); + + am.put ("underline", + new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + _this.toggleUnderline (); + + } + + }); +*/ + InputMap im = this.getInputMap (JComponent.WHEN_IN_FOCUSED_WINDOW); + + im.put (KeyStroke.getKeyStroke (KeyEvent.VK_Z, + Event.CTRL_MASK), + UNDO_ACTION_NAME); + im.put (KeyStroke.getKeyStroke (KeyEvent.VK_Y, + Event.CTRL_MASK), + REDO_ACTION_NAME); + im.put (KeyStroke.getKeyStroke (KeyEvent.VK_P, + Event.CTRL_MASK), + PRINT_ACTION_NAME); + im.put (KeyStroke.getKeyStroke (KeyEvent.VK_B, + Event.CTRL_MASK), + BOLD_ACTION_NAME);//new StyledEditorKit.BoldAction ()); + im.put (KeyStroke.getKeyStroke (KeyEvent.VK_I, + Event.CTRL_MASK), + ITALIC_ACTION_NAME); + im.put (KeyStroke.getKeyStroke (KeyEvent.VK_U, + Event.CTRL_MASK), + UNDERLINE_ACTION_NAME); + + this.lineHighlighter = new LineHighlighter (Color.LIGHT_GRAY); + + } + + public void initDocument () + { + + this.doc = new DefaultStyledDocument (); + + this.doc.putProperty (DefaultEditorKit.EndOfLineStringProperty, + "\n"); + + this.sectionBreakStyle = this.doc.addStyle ("section-break", + null); + StyleConstants.setAlignment (this.sectionBreakStyle, + StyleConstants.ALIGN_CENTER); + + this.doc.addUndoableEditListener (this.undoManager); + + this.doc.setParagraphAttributes (0, + 0, + this.styles, + true); + this.doc.setCharacterAttributes (0, + 0, + this.styles, + true); + + this.setDocument (this.doc); + + } + + public void setCanFormat (boolean c) + { + + this.canFormat = c; + + } + + public boolean isCanFormat () + { + + return this.canFormat; + + } + + public void setCanCopy (boolean c) + { + + this.canCopy = c; + + } + + public boolean isCanCopy () + { + + return this.canCopy; + + } + + @Override + public void copy () + { + + if (!this.canCopy) + { + + return; + + } + + super.copy (); + + } + + @Override + public void paste () + { + + if (!this.canCopy) + { + + return; + + } + + Transferable trans = Toolkit.getDefaultToolkit().getSystemClipboard().getContents (null); + + if ((trans != null) + && + (trans.isDataFlavorSupported (DataFlavor.stringFlavor)) + ) + { + + try + { + + String s = (String) trans.getTransferData (DataFlavor.stringFlavor); + + s = com.quollwriter.text.TextUtilities.sanitizeText (s); + + TransferHandler transferHandler = this.getTransferHandler(); + transferHandler.importData (this, + new StringSelection (s)); + + } catch (Exception e) { + + super.paste (); + + } + + } + + } + + protected QTextEditor() + { + + + } + + public void setWritingLineColor (Color c) + { + + this.lineHighlighter.setPaint (c); + this.validate (); + this.repaint (); + + } + + public void setHighlightWritingLine (boolean v) + { + + if (v) + { + + this.lineHighlighter.install (this); + + } else { + + this.lineHighlighter.uninstall (); + + } + + } + + public SynonymProvider getSynonymProvider () + { + + if (this.spellChecker != null) + { + + return this.spellChecker.getSynonymProvider (); + + } + + return null; + + } + + public void setSynonymProvider (SynonymProvider sp) + { + + if (this.spellChecker != null) + { + + this.spellChecker.setSynonymProvider (sp); + + } + + } + + public boolean _print () + throws java.awt.print.PrinterException + { + + QTextEditor qt = new QTextEditor (null, + false); + + qt.setSectionBreak (this.sectionBreak); + + qt.setLineSpacing (this.getLineSpacing ()); + qt.setFontSize (this.getPrintFontSize (this.getFontSize ())); + qt.setFontFamily (this.getFontFamily ()); + qt.setAlignment (this.getAlignment ()); + qt.setFirstLineIndent (this.getFirstLineIndent ()); + qt.setMargin (null); + qt.setTextWithMarkup (this.getTextWithMarkup ()); + + int ppi = java.awt.Toolkit.getDefaultToolkit ().getScreenResolution (); + + // A4 - 17cm wide, 25.7cm high. + // 6.7" wide, 10.12" high + + float pageHeight = 10.12f; + float pageWidth = 8.5f; + + qt.setSize (new Dimension ((int) (pageWidth * ppi), + Integer.MAX_VALUE)); + + qt.setSize (new Dimension ((int) (pageWidth * ppi), + qt.getPreferredSize ().height)); + + return qt.print (); + + } + + public void setDictionaryProvider (DictionaryProvider2 dp) + { + + this.spellChecker.setDictionaryProvider (dp); + + this.checkSpelling (); + + } + + public void applyStyle (Object style, + int start, + int end) + throws Exception + { + + MutableAttributeSet attrs = new SimpleAttributeSet (); + attrs.addAttribute (style, + true); + + this.doc.setCharacterAttributes (start, + end - start, + attrs, + false); + + } + + public String getSelectedText () + { + + int start = this.getSelectionStart (); + + if (start < 0) + { + + return ""; + + } + + int end = this.getSelectionEnd (); + + if (end < 0) + { + + return ""; + + } + + return this.getText ().substring (start, + end); + + } + + public StringWithMarkup getTextWithMarkup () + { + + return new StringWithMarkup (this.getText (), + new Markup (this.getDocument ())); + + } + + public void addStyleChangeListener (StyleChangeListener l) + { + + this.styleChangeListeners.add (l); + + } + + public void removeStyleChangeListener (StyleChangeListener l) + { + + this.styleChangeListeners.remove (l); + + } + + protected void fireStyleChangeEvent (int start, + int end, + String styleType, + boolean on) + { + + StyleChangeEvent ev = new StyleChangeEvent (this, + start, + end, + styleType, + on); + + for (StyleChangeListener l : this.styleChangeListeners) + { + + l.styleChanged (ev); + + } + + } + + private void clearBoldItalicUnderline () + { + + SimpleAttributeSet attrs = new SimpleAttributeSet (); + + StyleConstants.setBold (attrs, + false); + StyleConstants.setItalic (attrs, + false); + StyleConstants.setUnderline (attrs, + false); + + StyledEditorKit k = (StyledEditorKit) this.getEditorKit (); + + MutableAttributeSet inAttrs = k.getInputAttributes (); + + inAttrs.addAttributes (attrs); + + } + + public void setStyle (MutableAttributeSet attrs, + TextRange range) + { + + if (range.start != range.end) + { + + this.doc.setCharacterAttributes (range.start, + range.end - range.start, + attrs, + false); + + } + + StyledEditorKit k = (StyledEditorKit) this.getEditorKit (); + + MutableAttributeSet inAttrs = k.getInputAttributes (); + + inAttrs.addAttributes (attrs); + + } + + public void toggleBold () + { + + if (!this.canFormat) + { + + return; + + } + + int start = this.getSelectionStart (); + + if (start < 0) + { + + start = this.getCaret ().getDot (); + + } + + if (this.getSelectionEnd () == start) + { + + if (start > 0) + { + + start--; + + } + + } + + AbstractDocument.AbstractElement el = (AbstractDocument.AbstractElement) this.doc.getCharacterElement (start); + + SimpleAttributeSet attr = new SimpleAttributeSet (); + + StyleConstants.setBold (attr, + !StyleConstants.isBold (el.getAttributes ())); + + TextRange tr = new TextRange (this); + + this.setStyle (attr, + tr); + + this.fireStyleChangeEvent (tr.start, + tr.end, + StyleChangeEvent.BOLD, + StyleConstants.isBold (attr)); + + } + + public void toggleItalic () + { + + if (!this.canFormat) + { + + return; + + } + + int start = this.getSelectionStart (); + + if (start < 0) + { + + start = this.getCaret ().getDot (); + + } + + if (this.getSelectionEnd () == start) + { + + if (start > 0) + { + + start--; + + } + + } + + AbstractDocument.AbstractElement el = (AbstractDocument.AbstractElement) this.doc.getCharacterElement (start); + + SimpleAttributeSet attr = new SimpleAttributeSet (); + + StyleConstants.setItalic (attr, + !StyleConstants.isItalic (el.getAttributes ())); + + TextRange tr = new TextRange (this); + + this.setStyle (attr, + tr); + + this.fireStyleChangeEvent (tr.start, + tr.end, + StyleChangeEvent.ITALIC, + StyleConstants.isItalic (attr)); + + } + + public void toggleUnderline () + { + + if (!this.canFormat) + { + + return; + + } + + int start = this.getSelectionStart (); + + if (start < 0) + { + + start = this.getCaret ().getDot (); + + } + + if (this.getSelectionEnd () == start) + { + + if (start > 0) + { + + start--; + + } + + } + + AbstractDocument.AbstractElement el = (AbstractDocument.AbstractElement) this.doc.getCharacterElement (start); + + SimpleAttributeSet attr = new SimpleAttributeSet (); + + StyleConstants.setUnderline (attr, + !StyleConstants.isUnderline (el.getAttributes ())); + + TextRange tr = new TextRange (this); + + this.setStyle (attr, + tr); + + this.fireStyleChangeEvent (tr.start, + tr.end, + StyleChangeEvent.UNDERLINE, + StyleConstants.isUnderline (attr)); + + } + + public void replaceText (String replace) + { + + if (this.getText ().length () == 0) + { + + this.setTextWithMarkup (new StringWithMarkup (replace)); + + return; + + } + + int caret = this.getCaret ().getDot (); + + this.startCompoundEdit (); + + this.select (0, + this.getText ().length ()); + + this.replaceSelection (replace); + + this.endCompoundEdit (); + + this.getCaret ().setDot (caret); + + + } + + public void replaceText (int start, + int end, + String replace) + { + + int caret = this.getCaret ().getDot (); + + this.startCompoundEdit (); + + this.select (start, + end); + + this.replaceSelection (replace); + + this.endCompoundEdit (); + + this.getCaret ().setDot (caret); + + } + + public void startCompoundEdit () + { + + this.undoManager.startCompoundEdit (); + + } + + public void endCompoundEdit () + { + + this.undoManager.endCompoundEdit (); + + } + + public CompoundUndoManager getUndoManager () + { + + return this.undoManager; + + } +/* + public TextProperties getTextProperties () + { + + return new TextProperties (this, + this.getFontFamily (), + this.getFontSize (), + this.getAlignmentAsString (), + this.getFirstLineIndent (), + this.getLineSpacing () + 1, + this.getTextColor (), + this.getBackgroundColor ()); + + } + */ + public String getAlignmentAsString () + { + + int v = this.getAlignment (); + + if (v == StyleConstants.ALIGN_LEFT) + { + + return QTextEditor.ALIGN_LEFT; + + } + + if (v == StyleConstants.ALIGN_RIGHT) + { + + return QTextEditor.ALIGN_RIGHT; + + } + + if (v == StyleConstants.ALIGN_JUSTIFIED) + { + + return QTextEditor.ALIGN_JUSTIFIED; + + } + + return QTextEditor.ALIGN_LEFT; + + } + + public int getAlignment () + { + + return StyleConstants.getAlignment (this.styles); + + } + + public void setAlignment (int v) + { + + StyleConstants.setAlignment (this.styles, + v); + + this.applyStyles (); + + } + + public boolean getFirstLineIndent () + { + + return StyleConstants.getFirstLineIndent (this.styles) != 0; + + } + + public void setFirstLineIndent (boolean v) + { + + float f = 0f; + + if (v) + { + + f = 30f; + + } + + StyleConstants.setFirstLineIndent (this.styles, + f); + + this.applyStyles (); + + } + + public void setAlignment (String v) + { + + int a = StyleConstants.ALIGN_LEFT; + + if (v.equalsIgnoreCase (QTextEditor.ALIGN_LEFT)) + { + + a = StyleConstants.ALIGN_LEFT; + + } + + if (v.equalsIgnoreCase (QTextEditor.ALIGN_RIGHT)) + { + + a = StyleConstants.ALIGN_RIGHT; + + } + + if (v.equalsIgnoreCase (QTextEditor.ALIGN_JUSTIFIED)) + { + + a = StyleConstants.ALIGN_JUSTIFIED; + + } + + this.setAlignment (a); + + } + + public Color getTextColor () + { + + return this.getFontColor (); + + } + + public Color getFontColor () + { + + return StyleConstants.getForeground (this.styles); + + } + + public void setTextColor (Color c) + { + + this.setFontColor (c); + + } + + public void setFontColor (Color c) + { + + // Change the caret color to match. + this.setCaretColor (c); + + StyleConstants.setForeground (this.styles, + c); + + this.applyStyles (); + + } + + /** + * Note: is here for compatibility, but will do nothing, parent components need to + * implement TextStyleable.setTextBorder with their own behaviour. + */ + @Override + public void setTextBorder (int v) + { + + // Do nothing. + + } + + public int getFontSize () + { + + return StyleConstants.getFontSize (this.styles); + + } + + public Font getFontForStyles () + { + + return new Font (this.getFontFamily (), + Font.PLAIN, + this.getFontSize ()); + + } + + public void setFontSize (int v) + { + + StyleConstants.setFontSize (this.styles, + v); + + this.applyStyles (); + + this.fireStyleChangeEvent (0, + this.doc.getEndPosition ().getOffset (), + StyleChangeEvent.FONT_SIZE, + false); + + } + + public String getFontFamily () + { + + return StyleConstants.getFontFamily (this.styles); + + } + + public void setFontFamily (String name) + { + + if (name == null) + { + + throw new IllegalArgumentException ("Font family name cannot be null"); + + } + + StyleConstants.setFontFamily (this.styles, + name); + + this.applyStyles (); + + this.fireStyleChangeEvent (0, + this.doc.getEndPosition ().getOffset (), + StyleChangeEvent.FONT_NAME, + false); + + } + + private void applyStyles () + { + + this.doc.setParagraphAttributes (0, + this.doc.getEndPosition ().getOffset (), + this.styles, + true); + + this.initSectionBreaks (this.getText ()); + + } + + public int getLineHeight () + { + + java.awt.image.BufferedImage bi = new java.awt.image.BufferedImage (1, 1, java.awt.image.BufferedImage.TYPE_INT_ARGB); + Graphics g = bi.getGraphics (); + + return (int) (g.getFontMetrics (new Font (this.getFontFamily (), Font.PLAIN, this.getFontSize ())).getHeight () * this.getLineSpacing ()); + + } + + public float getLineSpacing () + { + + return StyleConstants.getLineSpacing (this.styles) + 1; + + } + + public void setLineSpacing (float v) + { + + StyleConstants.setLineSpacing (this.styles, + v - 1); + + this.applyStyles (); + + } + + public void addWordToDictionary (String word) + { + + if (this.spellChecker != null) + { + + this.spellChecker.addWord (word); + + } + + } + + public void setSpellCheckEnabled (boolean v) + { + + if (this.spellChecker != null) + { + + this.spellChecker.enable (v); + + } + + } + + public boolean isSpellCheckEnabled () + { + + if (this.spellChecker != null) + { + + return this.spellChecker.isEnabled (); + + } + + return false; + + } + + public List getSpellCheckSuggestions (Word word) + { + + if (this.spellChecker == null) + { + + return new ArrayList (); + + } + + return this.spellChecker.getSuggestions (word); + + } + + public boolean isLoadingText () + { + + return this.loading; + + } + + public void setSectionBreak (String b) + { + + this.sectionBreak = b; + + } + + private void initSectionBreaks (String t) + { + + if (t == null) + { + + return; + + } + + if (this.sectionBreak != null) + { + + int ind = t.indexOf (this.sectionBreak); + + while (ind != -1) + { + + this.doc.setParagraphAttributes (ind, + 1, + this.sectionBreakStyle, + false); + + Style ls = this.doc.addStyle (null, + null); + StyleConstants.setAlignment (ls, + StyleConstants.ALIGN_LEFT); + + this.doc.setCharacterAttributes (ind + this.sectionBreak.length (), + 1, + ls, + false); + + ind = t.indexOf (this.sectionBreak, + ind + this.sectionBreak.length () + 1); + + } + + } + + } + + public void setText (String t) + { + + throw new UnsupportedOperationException ("Not supported, use setTextWithMarkup"); + + } + + public void removeHighlight (Object o) + { + + this.getHighlighter ().removeHighlight (o); + + } + + public Object addHighlight (int start, + int end, + Highlighter.HighlightPainter painter, + boolean removeHighlightOnActivity) + { + + final Highlighter h = this.getHighlighter (); + + try + { + + final Object o = h.addHighlight (start, + end, + ((painter != null) ? painter : javax.swing.text.DefaultHighlighter.DefaultPainter)); + + if (removeHighlightOnActivity) + { + + final QTextEditor _this = this; + + this.addKeyListener (new KeyAdapter () + { + + public void keyPressed (KeyEvent ev) + { + + _this.removeHighlight (o); + + _this.removeKeyListener (this); + + } + + }); + + this.addMouseListener (new MouseAdapter () + { + + public void mousePressed (MouseEvent ev) + { + + _this.removeHighlight (o); + + _this.removeMouseListener (this); + + } + + }); + + + } + + return o; + + } catch (Exception e) + { + + return null; + + } + + } + + public void removeAllHighlights (Highlighter.HighlightPainter painter) + { + + Highlighter h = this.getHighlighter (); + + Highlighter.Highlight[] highlights = h.getHighlights (); + + if (painter == null) + { + + painter = javax.swing.text.DefaultHighlighter.DefaultPainter; + + } + + for (int k = highlights.length; --k >= 0;) + { + + Highlighter.Highlight hh = highlights[k]; + + if (hh.getPainter () == painter) + { + + h.removeHighlight (hh); + + } + + } + + } + + public void removeHighlightsForElement (Element el, + Highlighter.HighlightPainter painter) + { + + int i = el.getStartOffset (); + int j = el.getEndOffset (); + + if (i == j) + { + + return; + + } + + if (painter == null) + { + + painter = javax.swing.text.DefaultHighlighter.DefaultPainter; + + } + + Highlighter h = this.getHighlighter (); + + Highlighter.Highlight[] highlights = h.getHighlights (); + + for (int k = highlights.length; --k >= 0;) + { + + Highlighter.Highlight hh = highlights[k]; + + int s = hh.getStartOffset (); + + int e = hh.getEndOffset (); + + if (((i <= s) && (s <= j)) || + ((i <= e) && (e <= j))) + { + + if (hh.getPainter () == painter) + { + + h.removeHighlight (hh); + + } + + } + + } + + } + + public void setTextWithMarkup (StringWithMarkup text) + { + + boolean enabled = false; + + this.undoManager.setRecordUndos (false); + + if (this.spellChecker != null) + { + + enabled = this.spellChecker.isEnabled (); + + this.spellChecker.enable (false); + + } + + String t = null; + Markup markup = null; + + if (text != null) + { + + t = text.getText (); + markup = text.getMarkup (); + + } + + if (t != null) + { + + t = Utils.replaceString (t, + String.valueOf ('\r'), + ""); + + } + + //this.styles = new SimpleAttributeSet (); + + this.clearBoldItalicUnderline (); + + super.setText (t); + + //this.applyStyles (); + + this.initSectionBreaks (t); + + if (markup != null) + { + + //Markup m = new Markup (markup); + + markup.apply (this); + + } + + this.undoManager.setRecordUndos (true); + + if (this.spellChecker != null) + { + + this.spellChecker.enable (enabled); + + } + + } + + public void checkSpelling () + { + + if (this.spellChecker != null) + { + + if (this.spellChecker.isEnabled ()) + { + + this.spellChecker.checkAll (); + + } + + } + + } + + public void appendText (String t) + throws BadLocationException + { + + this.doc.insertString (this.doc.getEndPosition ().getOffset () - 1, + t, + null); + + } + + public void insertText (int where, + String t) + throws BadLocationException + { + + this.doc.insertString (where, + t, + null); + + } + + public void removeText (int where, + int length) + throws BadLocationException + { + + this.doc.remove (where, + length); + + this.removeAllHighlights (null); + + } + + public void setBackgroundColor (Color c) + { + + this.setBackground (c); + + } + + public Color getBackgroundColor () + { + + return this.getBackground (); + + } + + public static int getPrintFontSize (int size) + { + + return Math.round ((float) size / ((float) java.awt.Toolkit.getDefaultToolkit ().getScreenResolution () / 72f)); + + } + + public boolean isPositionAtTextEnd (int p) + { + + int cl = this.getText ().length (); + + if (cl == 0) + { + + return p == cl; + + } + + return p >= cl; + + } + +} diff --git a/src/com/quollwriter/ui/components/Runner.java b/src/main/java/com/quollwriter/ui/components/Runner.java similarity index 100% rename from src/com/quollwriter/ui/components/Runner.java rename to src/main/java/com/quollwriter/ui/components/Runner.java diff --git a/src/com/quollwriter/ui/components/ScrollableBox.java b/src/main/java/com/quollwriter/ui/components/ScrollableBox.java similarity index 100% rename from src/com/quollwriter/ui/components/ScrollableBox.java rename to src/main/java/com/quollwriter/ui/components/ScrollableBox.java diff --git a/src/com/quollwriter/ui/components/ScrollablePanel.java b/src/main/java/com/quollwriter/ui/components/ScrollablePanel.java similarity index 100% rename from src/com/quollwriter/ui/components/ScrollablePanel.java rename to src/main/java/com/quollwriter/ui/components/ScrollablePanel.java diff --git a/src/com/quollwriter/ui/components/SelectedGradientPainter.java b/src/main/java/com/quollwriter/ui/components/SelectedGradientPainter.java similarity index 100% rename from src/com/quollwriter/ui/components/SelectedGradientPainter.java rename to src/main/java/com/quollwriter/ui/components/SelectedGradientPainter.java diff --git a/src/com/quollwriter/ui/components/SpellChecker.java b/src/main/java/com/quollwriter/ui/components/SpellChecker.java similarity index 100% rename from src/com/quollwriter/ui/components/SpellChecker.java rename to src/main/java/com/quollwriter/ui/components/SpellChecker.java diff --git a/src/com/quollwriter/ui/components/StyleChangeAdapter.java b/src/main/java/com/quollwriter/ui/components/StyleChangeAdapter.java similarity index 100% rename from src/com/quollwriter/ui/components/StyleChangeAdapter.java rename to src/main/java/com/quollwriter/ui/components/StyleChangeAdapter.java diff --git a/src/com/quollwriter/ui/components/StyleChangeEvent.java b/src/main/java/com/quollwriter/ui/components/StyleChangeEvent.java similarity index 100% rename from src/com/quollwriter/ui/components/StyleChangeEvent.java rename to src/main/java/com/quollwriter/ui/components/StyleChangeEvent.java diff --git a/src/com/quollwriter/ui/components/StyleChangeListener.java b/src/main/java/com/quollwriter/ui/components/StyleChangeListener.java similarity index 100% rename from src/com/quollwriter/ui/components/StyleChangeListener.java rename to src/main/java/com/quollwriter/ui/components/StyleChangeListener.java diff --git a/src/com/quollwriter/ui/components/TabHeader.java b/src/main/java/com/quollwriter/ui/components/TabHeader.java similarity index 100% rename from src/com/quollwriter/ui/components/TabHeader.java rename to src/main/java/com/quollwriter/ui/components/TabHeader.java diff --git a/src/com/quollwriter/ui/components/TableCellListener.java b/src/main/java/com/quollwriter/ui/components/TableCellListener.java similarity index 100% rename from src/com/quollwriter/ui/components/TableCellListener.java rename to src/main/java/com/quollwriter/ui/components/TableCellListener.java diff --git a/src/com/quollwriter/ui/components/TextProperties.java b/src/main/java/com/quollwriter/ui/components/TextProperties.java similarity index 100% rename from src/com/quollwriter/ui/components/TextProperties.java rename to src/main/java/com/quollwriter/ui/components/TextProperties.java diff --git a/src/com/quollwriter/ui/components/TextRange.java b/src/main/java/com/quollwriter/ui/components/TextRange.java similarity index 100% rename from src/com/quollwriter/ui/components/TextRange.java rename to src/main/java/com/quollwriter/ui/components/TextRange.java diff --git a/src/com/quollwriter/ui/components/TextStylable.java b/src/main/java/com/quollwriter/ui/components/TextStylable.java similarity index 100% rename from src/com/quollwriter/ui/components/TextStylable.java rename to src/main/java/com/quollwriter/ui/components/TextStylable.java diff --git a/src/com/quollwriter/ui/components/TextUnderlinePainter.java b/src/main/java/com/quollwriter/ui/components/TextUnderlinePainter.java similarity index 100% rename from src/com/quollwriter/ui/components/TextUnderlinePainter.java rename to src/main/java/com/quollwriter/ui/components/TextUnderlinePainter.java diff --git a/src/com/quollwriter/ui/components/UIUtils.java b/src/main/java/com/quollwriter/ui/components/UIUtils.java similarity index 100% rename from src/com/quollwriter/ui/components/UIUtils.java rename to src/main/java/com/quollwriter/ui/components/UIUtils.java diff --git a/src/com/quollwriter/ui/components/VerticalLayout.java b/src/main/java/com/quollwriter/ui/components/VerticalLayout.java similarity index 100% rename from src/com/quollwriter/ui/components/VerticalLayout.java rename to src/main/java/com/quollwriter/ui/components/VerticalLayout.java diff --git a/src/com/quollwriter/ui/components/WavyLinePainter.java b/src/main/java/com/quollwriter/ui/components/WavyLinePainter.java similarity index 100% rename from src/com/quollwriter/ui/components/WavyLinePainter.java rename to src/main/java/com/quollwriter/ui/components/WavyLinePainter.java diff --git a/src/com/quollwriter/ui/components/WindowStateAdapter.java b/src/main/java/com/quollwriter/ui/components/WindowStateAdapter.java similarity index 100% rename from src/com/quollwriter/ui/components/WindowStateAdapter.java rename to src/main/java/com/quollwriter/ui/components/WindowStateAdapter.java diff --git a/src/com/quollwriter/ui/events/DictionaryChangedEvent.java b/src/main/java/com/quollwriter/ui/events/DictionaryChangedEvent.java similarity index 100% rename from src/com/quollwriter/ui/events/DictionaryChangedEvent.java rename to src/main/java/com/quollwriter/ui/events/DictionaryChangedEvent.java diff --git a/src/com/quollwriter/ui/events/DictionaryChangedListener.java b/src/main/java/com/quollwriter/ui/events/DictionaryChangedListener.java similarity index 100% rename from src/com/quollwriter/ui/events/DictionaryChangedListener.java rename to src/main/java/com/quollwriter/ui/events/DictionaryChangedListener.java diff --git a/src/com/quollwriter/ui/events/ItemChangedEvent.java b/src/main/java/com/quollwriter/ui/events/ItemChangedEvent.java similarity index 100% rename from src/com/quollwriter/ui/events/ItemChangedEvent.java rename to src/main/java/com/quollwriter/ui/events/ItemChangedEvent.java diff --git a/src/com/quollwriter/ui/events/NameChangedAdapter.java b/src/main/java/com/quollwriter/ui/events/NameChangedAdapter.java similarity index 100% rename from src/com/quollwriter/ui/events/NameChangedAdapter.java rename to src/main/java/com/quollwriter/ui/events/NameChangedAdapter.java diff --git a/src/com/quollwriter/ui/events/NameChangedEvent.java b/src/main/java/com/quollwriter/ui/events/NameChangedEvent.java similarity index 100% rename from src/com/quollwriter/ui/events/NameChangedEvent.java rename to src/main/java/com/quollwriter/ui/events/NameChangedEvent.java diff --git a/src/com/quollwriter/ui/events/NameChangedListener.java b/src/main/java/com/quollwriter/ui/events/NameChangedListener.java similarity index 100% rename from src/com/quollwriter/ui/events/NameChangedListener.java rename to src/main/java/com/quollwriter/ui/events/NameChangedListener.java diff --git a/src/com/quollwriter/ui/events/TreeModelAdapter.java b/src/main/java/com/quollwriter/ui/events/TreeModelAdapter.java similarity index 100% rename from src/com/quollwriter/ui/events/TreeModelAdapter.java rename to src/main/java/com/quollwriter/ui/events/TreeModelAdapter.java diff --git a/src/com/quollwriter/ui/events/VetoableActionEvent.java b/src/main/java/com/quollwriter/ui/events/VetoableActionEvent.java similarity index 100% rename from src/com/quollwriter/ui/events/VetoableActionEvent.java rename to src/main/java/com/quollwriter/ui/events/VetoableActionEvent.java diff --git a/src/com/quollwriter/ui/events/WordCountTimerEvent.java b/src/main/java/com/quollwriter/ui/events/WordCountTimerEvent.java similarity index 100% rename from src/com/quollwriter/ui/events/WordCountTimerEvent.java rename to src/main/java/com/quollwriter/ui/events/WordCountTimerEvent.java diff --git a/src/com/quollwriter/ui/events/WordCountTimerListener.java b/src/main/java/com/quollwriter/ui/events/WordCountTimerListener.java similarity index 100% rename from src/com/quollwriter/ui/events/WordCountTimerListener.java rename to src/main/java/com/quollwriter/ui/events/WordCountTimerListener.java diff --git a/src/com/quollwriter/ui/forms/AnyFormItem.java b/src/main/java/com/quollwriter/ui/forms/AnyFormItem.java similarity index 100% rename from src/com/quollwriter/ui/forms/AnyFormItem.java rename to src/main/java/com/quollwriter/ui/forms/AnyFormItem.java diff --git a/src/com/quollwriter/ui/forms/CheckboxFormItem.java b/src/main/java/com/quollwriter/ui/forms/CheckboxFormItem.java similarity index 100% rename from src/com/quollwriter/ui/forms/CheckboxFormItem.java rename to src/main/java/com/quollwriter/ui/forms/CheckboxFormItem.java diff --git a/src/com/quollwriter/ui/forms/ComboBoxFormItem.java b/src/main/java/com/quollwriter/ui/forms/ComboBoxFormItem.java similarity index 100% rename from src/com/quollwriter/ui/forms/ComboBoxFormItem.java rename to src/main/java/com/quollwriter/ui/forms/ComboBoxFormItem.java diff --git a/src/com/quollwriter/ui/forms/DateFormItem.java b/src/main/java/com/quollwriter/ui/forms/DateFormItem.java similarity index 100% rename from src/com/quollwriter/ui/forms/DateFormItem.java rename to src/main/java/com/quollwriter/ui/forms/DateFormItem.java diff --git a/src/com/quollwriter/ui/forms/FileSelectorFormItem.java b/src/main/java/com/quollwriter/ui/forms/FileSelectorFormItem.java similarity index 100% rename from src/com/quollwriter/ui/forms/FileSelectorFormItem.java rename to src/main/java/com/quollwriter/ui/forms/FileSelectorFormItem.java diff --git a/src/com/quollwriter/ui/forms/Form.java b/src/main/java/com/quollwriter/ui/forms/Form.java similarity index 100% rename from src/com/quollwriter/ui/forms/Form.java rename to src/main/java/com/quollwriter/ui/forms/Form.java diff --git a/src/com/quollwriter/ui/forms/FormItem.java b/src/main/java/com/quollwriter/ui/forms/FormItem.java similarity index 100% rename from src/com/quollwriter/ui/forms/FormItem.java rename to src/main/java/com/quollwriter/ui/forms/FormItem.java diff --git a/src/com/quollwriter/ui/forms/ImageSelectorFormItem.java b/src/main/java/com/quollwriter/ui/forms/ImageSelectorFormItem.java similarity index 100% rename from src/com/quollwriter/ui/forms/ImageSelectorFormItem.java rename to src/main/java/com/quollwriter/ui/forms/ImageSelectorFormItem.java diff --git a/src/com/quollwriter/ui/forms/MultiLineTextFormItem.java b/src/main/java/com/quollwriter/ui/forms/MultiLineTextFormItem.java similarity index 100% rename from src/com/quollwriter/ui/forms/MultiLineTextFormItem.java rename to src/main/java/com/quollwriter/ui/forms/MultiLineTextFormItem.java diff --git a/src/com/quollwriter/ui/forms/SelectFormItem.java b/src/main/java/com/quollwriter/ui/forms/SelectFormItem.java similarity index 100% rename from src/com/quollwriter/ui/forms/SelectFormItem.java rename to src/main/java/com/quollwriter/ui/forms/SelectFormItem.java diff --git a/src/com/quollwriter/ui/forms/TextFormItem.java b/src/main/java/com/quollwriter/ui/forms/TextFormItem.java similarity index 100% rename from src/com/quollwriter/ui/forms/TextFormItem.java rename to src/main/java/com/quollwriter/ui/forms/TextFormItem.java diff --git a/src/main/java/com/quollwriter/ui/fx/AbstractChapterItemFormatter.java b/src/main/java/com/quollwriter/ui/fx/AbstractChapterItemFormatter.java new file mode 100644 index 00000000..16390874 --- /dev/null +++ b/src/main/java/com/quollwriter/ui/fx/AbstractChapterItemFormatter.java @@ -0,0 +1,241 @@ +package com.quollwriter.ui.fx; + +import java.util.*; +import java.util.function.*; + +import javafx.scene.Node; +import javafx.scene.layout.*; +import javafx.scene.control.*; + +import com.quollwriter.*; +import com.quollwriter.data.NamedObject; +import com.quollwriter.data.ChapterItem; +import com.quollwriter.data.IPropertyBinder; +import com.quollwriter.ui.fx.components.*; +import com.quollwriter.ui.fx.viewers.*; + +import static com.quollwriter.uistrings.UILanguageStringsManager.getUILanguageStringProperty; +import static com.quollwriter.LanguageStrings.*; + +public abstract class AbstractChapterItemFormatter implements ChapterItemFormatter +{ + + protected V viewer = null; + protected E item = null; + protected IPropertyBinder binder = null; + private LinkedToPanel linkedToPanel = null; + private Runnable popupShown = null; + private QuollButton editBut = null; + private QuollButton linkBut = null; + private QuollButton deleteBut = null; + private QuollButton saveBut = null; + private QuollButton cancelBut = null; + private boolean editable = true; + private Supplier> extraControls = null; + + public AbstractChapterItemFormatter (V viewer, + IPropertyBinder binder, + E item, + Runnable onNewPopupShown, + Supplier> extraControls) + { + + this (viewer, + binder, + item, + onNewPopupShown, + true, + extraControls); + + } + + public AbstractChapterItemFormatter (V viewer, + IPropertyBinder binder, + E item, + Runnable onNewPopupShown, + boolean editable, + Supplier> extraControls) + { + + this.viewer = viewer; + this.item = item; + this.binder = binder; + this.popupShown = onNewPopupShown; + this.editable = editable; + this.extraControls = extraControls; + + } + + public Node format () + { + + VBox v = new VBox (); + + VBox lv = new VBox (); + lv.getStyleClass ().add (StyleClassNames.LINKEDTO); + lv.managedProperty ().bind (lv.visibleProperty ()); + + this.binder.addSetChangeListener (this.item.getLinks (), + ev -> + { + + lv.setVisible (this.item.getLinks ().size () > 0); + + }); + + lv.setVisible (this.item.getLinks ().size () > 0); + + lv.getChildren ().add (QuollLabel.builder () + .label (linkedto,view,title) + .styleClassName (StyleClassNames.SUBTITLE) + .build ()); + + this.linkedToPanel = new LinkedToPanel (this.item, + this.binder, + this.viewer); + + lv.getChildren ().add (new ScrollPane (this.linkedToPanel)); + + this.editBut = QuollButton.builder () + .iconName (StyleClassNames.EDIT) + .tooltip (getUILanguageStringProperty (Arrays.asList (edititem,tooltip), + Environment.getObjectTypeName (this.item))) + .onAction (ev -> + { + + this.editItem (this.item); + /* + this.viewer.runCommand (ProjectViewer.CommandId.editobject, + this.item); +*/ + UIUtils.runLater (this.popupShown); + + }) + .build (); + this.editBut.managedProperty ().bind (this.editBut.visibleProperty ()); + + this.editBut.setVisible (this.editable); + + this.linkBut = QuollButton.builder () + .iconName (StyleClassNames.LINK) + .tooltip (getUILanguageStringProperty (Arrays.asList (linkitem,tooltip), + Environment.getObjectTypeName (this.item))) + .onAction (ev -> + { + + lv.setVisible (true); + + this.saveBut.setVisible (true); + this.cancelBut.setVisible (true); + this.editBut.setVisible (false); + this.linkBut.setVisible (false); + this.deleteBut.setVisible (false); + + this.linkedToPanel.showEdit (); + + }) + .build (); + this.linkBut.managedProperty ().bind (this.linkBut.visibleProperty ()); + this.linkBut.setVisible (this.editable); + + this.deleteBut = QuollButton.builder () + .iconName (StyleClassNames.DELETE) + .tooltip (getUILanguageStringProperty (Arrays.asList (deleteitem,tooltip), + Environment.getObjectTypeName (this.item))) + .onAction (ev -> + { + + this.deleteItem (this.item); + +/* + this.viewer.showDeleteChapterItemPopup (this.item, + this.viewer.getEditorForChapter (this.item.getChapter ()).getNodeForChapterItem (this.item)); +*/ + UIUtils.runLater (this.popupShown); + + }) + .build (); + this.deleteBut.managedProperty ().bind (this.deleteBut.visibleProperty ()); + this.deleteBut.setVisible (this.editable); + + this.saveBut = QuollButton.builder () + .iconName (StyleClassNames.SAVE) + .tooltip (chapteritems,links,save,buttons,confirm,tooltip) + .onAction (ev -> + { + + this.item.setLinks (this.linkedToPanel.getSelected ()); + + try + { + + this.saveItem (this.item); + /* + this.viewer.saveObject (this.item, + true); + */ + this.saveBut.setVisible (false); + this.cancelBut.setVisible (false); + this.editBut.setVisible (true); + this.linkBut.setVisible (true); + this.deleteBut.setVisible (true); + this.linkedToPanel.showView (); + lv.setVisible (this.item.getLinks ().size () > 0); + + } catch (Exception e) { + + Environment.logError ("Unable to save item: " + + this.item, + e); + + ComponentUtils.showErrorMessage (this.viewer, + getUILanguageStringProperty (chapteritems,links,save,actionerror)); + + } + + }) + .build (); + this.saveBut.managedProperty ().bind (this.saveBut.visibleProperty ()); + this.saveBut.setVisible (false); + + this.cancelBut = QuollButton.builder () + .iconName (StyleClassNames.CANCEL) + .tooltip (chapteritems,links,save,buttons,confirm,tooltip) + .onAction (ev -> + { + + this.saveBut.setVisible (false); + this.cancelBut.setVisible (false); + this.editBut.setVisible (true); + this.linkBut.setVisible (true); + this.deleteBut.setVisible (true); + this.linkedToPanel.showView (); + lv.setVisible (this.item.getLinks ().size () > 0); + + }) + .build (); + this.cancelBut.managedProperty ().bind (this.cancelBut.visibleProperty ()); + this.cancelBut.setVisible (false); + + //ToolBar t = new ToolBar (); + HBox t = new HBox (); + t.getStyleClass ().addAll (StyleClassNames.BUTTONS, StyleClassNames.TOOLBAR); + + if (this.extraControls != null) + { + + t.getChildren ().addAll (this.extraControls.get ()); + + } + + t.getChildren ().addAll (this.editBut, this.linkBut, this.deleteBut, this.saveBut, this.cancelBut); + + v.getChildren ().addAll (this.getContent (), lv, t); + + return v; + + } + + public abstract Node getContent (); + +} diff --git a/src/main/java/com/quollwriter/ui/fx/AbstractProjectItemFormatter.java b/src/main/java/com/quollwriter/ui/fx/AbstractProjectItemFormatter.java new file mode 100644 index 00000000..9f65e203 --- /dev/null +++ b/src/main/java/com/quollwriter/ui/fx/AbstractProjectItemFormatter.java @@ -0,0 +1,80 @@ +package com.quollwriter.ui.fx; + +import java.util.*; +import java.util.function.*; + +import javafx.beans.property.*; +import javafx.scene.Node; +import javafx.scene.control.*; +import javafx.scene.layout.*; + +import com.quollwriter.*; +import com.quollwriter.data.*; +import com.quollwriter.ui.fx.components.*; +import com.quollwriter.ui.fx.viewers.*; + +public abstract class AbstractProjectItemFormatter extends AbstractChapterItemFormatter +{ + + public AbstractProjectItemFormatter (ProjectViewer viewer, + IPropertyBinder binder, + E item, + Runnable onNewPopupShown, + Supplier> extraControls) + { + + this (viewer, + binder, + item, + onNewPopupShown, + true, + extraControls); + + } + + public AbstractProjectItemFormatter (ProjectViewer viewer, + IPropertyBinder binder, + E item, + Runnable onNewPopupShown, + boolean editable, + Supplier> extraControls) + { + + super (viewer, + binder, + item, + onNewPopupShown, + editable, + extraControls); + + } + + @Override + public void saveItem (E item) + throws GeneralException + { + + viewer.saveObject (item, + false); + + } + + @Override + public void deleteItem (E item) + { + + viewer.showDeleteChapterItemPopup (item, + viewer.getEditorForChapter (item.getChapter ()).getNodeForChapterItem (item)); + + } + + @Override + public void editItem (E item) + { + + this.viewer.runCommand (ProjectViewer.CommandId.editobject, + item); + + } + +} diff --git a/src/main/java/com/quollwriter/ui/fx/AssetFindResultsBox.java b/src/main/java/com/quollwriter/ui/fx/AssetFindResultsBox.java new file mode 100644 index 00000000..6c454f25 --- /dev/null +++ b/src/main/java/com/quollwriter/ui/fx/AssetFindResultsBox.java @@ -0,0 +1,164 @@ +package com.quollwriter.ui.fx; + +import java.util.*; +import java.util.function.*; + +import javafx.beans.property.*; +import javafx.scene.*; +import javafx.scene.control.*; +import javafx.scene.input.*; +import javafx.scene.image.*; +import javafx.scene.layout.*; + +import com.quollwriter.*; +import com.quollwriter.data.*; +import com.quollwriter.ui.fx.components.*; +import com.quollwriter.ui.fx.viewers.*; + +import static com.quollwriter.uistrings.UILanguageStringsManager.getUILanguageStringProperty; +import com.quollwriter.uistrings.UILanguageStringsManager; +import static com.quollwriter.LanguageStrings.*; + +public class AssetFindResultsBox extends FindResultsBox +{ + + private Set objs = null; + private QuollTreeView tree = null; + private AccordionItem acc = null; + private UserConfigurableObjectType type = null; + private IPropertyBinder binder = null; + + public AssetFindResultsBox (UserConfigurableObjectType type, + AbstractProjectViewer viewer, + Set objs) + { + + super (viewer, + null); + + this.objs = objs; + this.type = type; + this.binder = new PropertyBinder (); + + } + + @Override + public void dispose () + { + + this.binder.dispose (); + + } + + public QuollTreeView getTree () + { + + if (this.tree == null) + { + + this.tree = this.createTree (); + + } + + return this.tree; + + } + + @Override + public Node getContent () + { + + if (this.tree == null) + { + + this.tree = this.getTree (); + + } + + StringProperty tProp = new SimpleStringProperty (); + tProp.bind (UILanguageStringsManager.createStringBinding (() -> + { + + return String.format ("%1$s (%2$s)", + this.type.getObjectTypeNamePlural (), + Environment.formatNumber (this.objs.size ())); + + })); + + this.acc = AccordionItem.builder () + .title (tProp) + .styleClassName (StyleClassNames.ASSET) + .openContent (this.tree) + .build (); + UIUtils.setBackgroundImage (this.acc.getHeader ().getIcon (), + this.type.icon16x16Property (), + this.binder); + + //this.acc.getHeader ().getIcon ().imageProperty ().bind (this.type.icon16x16Property ()); + + return this.acc; + + } + + private QuollTreeView createTree () + { + + Function, Node> cellProvider = (treeItem) -> + { + + NamedObject n = treeItem.getValue (); + + if (n instanceof Project) + { + + return new Label (); + + } + + QuollLabel l = QuollLabel.builder () + .styleClassName (n.getObjectType ()) + .label (n.getName ()) + .build (); + + l.addEventHandler (MouseEvent.MOUSE_RELEASED, + ev -> + { + + if (ev.isPopupTrigger ()) + { + + return; + + } + + this.viewer.viewObject (n); + + }); + + return l; + + }; + + // Create the model. + TreeItem root = new TreeItem<> (); + root.setValue (this.viewer.getProject ()); + + for (Asset o : this.objs) + { + + TreeItem ci = new TreeItem<> (); + ci.setValue (o); + root.getChildren ().add (ci); + + } + + QuollTreeView tree = new QuollTreeView<> (); + tree.setShowRoot (false); + tree.setCellProvider (cellProvider); + tree.setRoot (root); + + return tree; + + } + +} diff --git a/src/main/java/com/quollwriter/ui/fx/BackgroundObject.java b/src/main/java/com/quollwriter/ui/fx/BackgroundObject.java new file mode 100644 index 00000000..b3ae5171 --- /dev/null +++ b/src/main/java/com/quollwriter/ui/fx/BackgroundObject.java @@ -0,0 +1,363 @@ +package com.quollwriter.ui.fx; + +import java.io.*; +import java.nio.file.*; + +import javafx.scene.image.*; +import javafx.scene.layout.*; +import javafx.scene.paint.*; +import javafx.beans.property.*; + +import com.quollwriter.*; + +public class BackgroundObject +{ + + public static final String BG_IMAGE_PREFIX = "bg:"; + + private Color color = null; + private Background bg = null; + private Path userPath = null; + private String bgImage = null; + private ObjectProperty bgProp = null; + + public BackgroundObject () + { + + this.bgProp = new SimpleObjectProperty<> (); + + } + + public BackgroundObject (String id) + throws Exception + { + + this (); + + if (id == null) + { + + return; + + } + + this.update (BackgroundObject.createBackgroundObjectForId (id)); + + } + + public Object getBackgroundObject () + { + + if (this.userPath != null) + { + + return this.userPath; + + } + + if (this.color != null) + { + + return this.color; + + } + + if (this.bgImage != null) + { + + return this.bgImage; + + } + + return this.bgImage; + + } + + public Background getBackground () + { + + return this.bg; + + } + + public String getAsString () + { + + if (this.userPath != null) + { + + return this.userPath.toString (); + + } + + if (this.color != null) + { + + return UIUtils.colorToHex (this.color); + + } + + if (this.bgImage != null) + { + + return BG_IMAGE_PREFIX + this.bgImage; + + } + + return null; + + } + + public ObjectProperty backgroundProperty () + { + + return this.bgProp; + + } + + public Path getUserPath () + { + + return this.userPath; + + } + + public boolean isUserPath () + { + + return this.userPath != null; + + } + + public boolean isImage () + { + + if ((this.bgImage != null) + || + (this.userPath != null) + ) + { + + return true; + + } + + return false; + + } + + public void update (Object o) + throws Exception + { + + if (o == null) + { + + this.bgImage = null; + this.userPath = null; + this.color = null; + this.bg = null; + this.bgProp.setValue (null); + return; + + } + + if (o instanceof Color) + { + + this.updateForColor ((Color) o); + return; + + } + + if (o instanceof String) + { + + this.updateForBuiltInImage ((String) o); + return; + + } + + if (o instanceof Path) + { + + this.updateForUserPath ((Path) o); + return; + + } + + throw new IllegalArgumentException ("Unsupported object type: " + o.getClass ().getName ()); + + } + + public void updateForUserPath (Path p) + throws IOException + { + + this.color = null; + this.bgImage = null; + + if ((Files.notExists (p)) + || + (Files.isDirectory (p)) + ) + { + + this.userPath = null; + this.bg = null; + this.bgProp.setValue (null); + return; + + } + + this.userPath = p; + this.bg = new Background (new BackgroundImage (new Image (Files.newInputStream (p)), + BackgroundRepeat.NO_REPEAT, + BackgroundRepeat.NO_REPEAT, + null, + new BackgroundSize (100, 100, true, true, true, true))); + //null)); + + this.bgProp.setValue (this.bg); + + } + + public void updateForBuiltInImage (String id) + { + + if (id.startsWith (BG_IMAGE_PREFIX)) + { + + id = id.substring (BG_IMAGE_PREFIX.length ()); + + // Legacy per v3 + if (id.startsWith ("1-")) + { + + id = "_" + id; + + } + + } + + this.userPath = null; + this.color = null; + + String name = Constants.BACKGROUND_IMGS_DIR + id; + + InputStream s = Utils.getResourceStream (name); + + if (s == null) + { + + this.bgImage = null; + this.bg = null; + this.bgProp.setValue (null); + return; + + } + + Image im = new Image (s); + this.bgImage = id; + + // These shouldn't be stretched. + if (id.startsWith ("_1-")) + { + + this.bg = new Background (new BackgroundImage (im, + BackgroundRepeat.NO_REPEAT, + BackgroundRepeat.NO_REPEAT, + null, + new BackgroundSize (100, 100, true, true, true, true))); + + } else { + + this.bg = new Background (new BackgroundImage (im, + BackgroundRepeat.REPEAT, + BackgroundRepeat.REPEAT, + null, + BackgroundSize.DEFAULT)); + //new BackgroundSize (100, 100, true, true, true, true))); + + } + + this.bgProp.setValue (this.bg); + + } + + public void updateForColor (Color c) + { + + this.userPath = null; + this.bgImage = null; + this.color = c; + this.bg = new Background (new BackgroundFill (c, null, null)); + + this.bgProp.setValue (this.bg); + + } + + public static Object createBackgroundObjectForId (String id) + { + + if (id == null) + { + + return null; + + } + + if (id.startsWith ("#")) + { + + Color col = UIUtils.hexToColor (id); + + return col; + + } + + if (id.startsWith (BG_IMAGE_PREFIX)) + { + + id = id.substring (BG_IMAGE_PREFIX.length ()); + + Image im = Environment.getBackgroundImage (id, -1, -1); + + if (im != null) + { + + return id; + + } + + } + + if (id.equals ("file:")) + { + + return null; + + } + + if (id.startsWith ("file:")) + { + + id = id.substring ("file:".length ()); +/* + StringBuffer _id = new StringBuffer (id); + + _id = _id.replace (0, + "file:C:\\".length (), + "file:\\\\:C:\\"); + + id = _id.toString (); +*/ + } + + Path path = Paths.get (id); + + return path; + + } + +} diff --git a/src/main/java/com/quollwriter/ui/fx/Buildable.java b/src/main/java/com/quollwriter/ui/fx/Buildable.java new file mode 100644 index 00000000..34b81ab0 --- /dev/null +++ b/src/main/java/com/quollwriter/ui/fx/Buildable.java @@ -0,0 +1,13 @@ +package com.quollwriter.ui.fx; + +public interface Buildable, E> +{ + + static , E> T builder () + { + + throw new IllegalStateException (); + + } + +} diff --git a/src/main/java/com/quollwriter/ui/fx/ChapterFindResultsBox.java b/src/main/java/com/quollwriter/ui/fx/ChapterFindResultsBox.java new file mode 100644 index 00000000..7bac27b2 --- /dev/null +++ b/src/main/java/com/quollwriter/ui/fx/ChapterFindResultsBox.java @@ -0,0 +1,347 @@ +package com.quollwriter.ui.fx; + +import java.util.*; +import java.util.function.*; +import java.util.stream.*; + +import javafx.scene.*; +import javafx.beans.property.*; +import javafx.scene.control.*; +import javafx.scene.input.*; +import javafx.event.*; + +import com.quollwriter.*; +import com.quollwriter.data.*; +import com.quollwriter.ui.fx.panels.*; +import com.quollwriter.ui.fx.viewers.*; +import com.quollwriter.ui.fx.components.*; +import com.quollwriter.ui.fx.sidebars.*; + +import com.quollwriter.text.*; + +import static com.quollwriter.uistrings.UILanguageStringsManager.getUILanguageStringProperty; +import com.quollwriter.uistrings.UILanguageStringsManager; +import static com.quollwriter.LanguageStrings.*; + +public class ChapterFindResultsBox extends FindResultsBox +{ + + private Map> snippets = null; + private Set highlightIds = new HashSet<> (); + private TextEditor highlightedEditor = null; + private Chapter highlightedChapter = null; + private QuollTreeView tree = null; + private AccordionItem acc = null; + private EventHandler mouseList = null; + private EventHandler keyList = null; + + public ChapterFindResultsBox (Map> snippets, + AbstractProjectViewer viewer) + { + + super (viewer, + null); + + this.snippets = snippets; + + this.mouseList = ev -> + { + + this.clearHighlight (); + + }; + + this.keyList = ev -> + { + + this.clearHighlight (); + + }; + + } + + @Override + public void dispose () + { + + this.clearHighlight (); + + } + + public QuollTreeView getTree () + { + + if (this.tree == null) + { + + this.tree = this.createTree (); + + } + + return this.tree; + + } + + @Override + public Node getContent () + { + + if (this.tree == null) + { + + this.tree = this.getTree (); + + } + + StringProperty tProp = new SimpleStringProperty (); + tProp.bind (UILanguageStringsManager.createStringBinding (() -> + { + + return String.format ("%1$s (%2$s)", + getUILanguageStringProperty (objectnames,plural,Chapter.OBJECT_TYPE).getValue (), + Environment.formatNumber (this.snippets.size ())); + + })); + + this.acc = AccordionItem.builder () + .title (tProp) + .styleClassName (Chapter.OBJECT_TYPE) + .openContent (this.tree) + .build (); + + return this.acc; + + } + + private QuollTreeView createTree () + { + + Function, Node> cellProvider = (treeItem) -> + { + + Object n = treeItem.getValue (); + + if (n instanceof Project) + { + + return new Label (); + + } + + if (n instanceof Chapter) + { + + Chapter c = (Chapter) n; + + QuollLabel l = QuollLabel.builder () + .styleClassName (c.getObjectType ()) + .build (); + + l.textProperty ().bind (UILanguageStringsManager.createStringBinding (() -> + { + + String t = "%1$s (%2$s)"; + + return String.format (t, + c.getName (), + treeItem.getChildren ().size ()); + + }, + treeItem.getChildren (), + c.nameProperty ())); + + l.addEventHandler (MouseEvent.MOUSE_RELEASED, + ev -> + { + + if (ev.isPopupTrigger ()) + { + + return; + + } + + this.tree.toggleOpen (treeItem); + + }); + + return l; + + } + + if (n instanceof SentenceMatches) + { + + SentenceMatches s = (SentenceMatches) n; + + String value = s.getSentence ().getText (); + + QuollLabel l = QuollLabel.builder () + .styleClassName (StyleClassNames.SNIPPET) + .label (new SimpleStringProperty (value)) + .build (); + + l.addEventHandler (MouseEvent.MOUSE_PRESSED, + ev -> + { + + if (ev.isPopupTrigger ()) + { + + return; + + } + + TreeItem parent = treeItem.getParent (); + + this.showSnippet ((Chapter) parent.getValue (), + s); + + }); + + return l; + + } + + throw new IllegalStateException ("How did we get here?"); + + }; + + // Create the model. + TreeItem root = new TreeItem<> (); + root.setValue (this.viewer.getProject ()); + + for (Chapter c : this.snippets.keySet ()) + { + + TreeItem ci = new TreeItem<> (); + ci.setValue (c); + root.getChildren ().add (ci); + + List segs = this.snippets.get (c); + + Collections.sort (segs, + (o1, o2) -> + { + + return o1.getSentence ().getAllTextStartOffset () - o2.getSentence ().getAllTextStartOffset (); + + }); + + for (SentenceMatches s : segs) + { + + TreeItem ii = new TreeItem<> (); + ii.setValue (s); + ci.getChildren ().add (ii); + + } + + } + + QuollTreeView tree = new QuollTreeView<> (); + tree.setShowRoot (false); + tree.getStyleClass ().add (StyleClassNames.CHAPTER); + tree.setCellProvider (cellProvider); + tree.setRoot (root); + + if (UserProperties.getAsBoolean (Constants.SHOW_EACH_CHAPTER_FIND_RESULT_PROPERTY_NAME)) + { + + tree.expandAll (); + + } + + return tree; + + } + + public void clearHighlight () + { + + if (this.highlightedEditor != null) + { + + this.highlightedEditor.removeEventHandler (KeyEvent.KEY_RELEASED, + this.keyList); + + this.highlightedEditor.removeEventHandler (MouseEvent.MOUSE_RELEASED, + this.mouseList); + + if (this.viewer.getEditorForChapter (this.highlightedChapter) != null) + { + + this.highlightIds.stream () + .forEach (i -> this.highlightedEditor.removeHighlight (i)); + + } + this.highlightIds.clear (); + + this.highlightedChapter = null; + this.highlightedEditor = null; + + } + + } + + public void showSnippet (final Chapter c, + final SentenceMatches s) + { + + this.clearHighlight (); + + this.viewer.viewObject (c, + () -> + { + + ChapterEditorPanelContent p = this.viewer.getEditorForChapter (c); + + try + { + + int si = s.getSentence ().getAllTextStartOffset (); + + p.scrollToTextPosition (si, + () -> + { + + this.highlightIds.clear (); + + int ml = s.getMatch ().length (); + + for (Integer i : s.getIndices ()) + { + + IndexRange r = new IndexRange (s.getSentence ().getWord (i).getAllTextStartOffset (), + s.getSentence ().getWord (i).getAllTextEndOffset ()); + + this.highlightIds.add (p.getEditor ().addHighlight (r, + UserProperties.getFindHighlightColor ())); + + } + + this.highlightedChapter = c; + this.highlightedEditor = p.getEditor (); + + this.highlightedEditor.addEventHandler (KeyEvent.KEY_RELEASED, + this.keyList); + + this.highlightedEditor.addEventHandler (MouseEvent.MOUSE_RELEASED, + this.mouseList); + + }); + + } catch (Exception e) { + + Environment.logError ("Unable to scroll to: " + s.getSentence ().getAllTextStartOffset (), + e); + + return; + + } + + }); + + } + +} diff --git a/src/main/java/com/quollwriter/ui/fx/ChapterItemFormatter.java b/src/main/java/com/quollwriter/ui/fx/ChapterItemFormatter.java new file mode 100644 index 00000000..29b15765 --- /dev/null +++ b/src/main/java/com/quollwriter/ui/fx/ChapterItemFormatter.java @@ -0,0 +1,19 @@ +package com.quollwriter.ui.fx; + +import javafx.beans.property.*; +import javafx.scene.Node; + +import com.quollwriter.data.*; +import com.quollwriter.*; + +public interface ChapterItemFormatter +{ + + String getStyleClassName (); + StringProperty getPopupTitle (); + Node format (); + void deleteItem (E i); + void editItem (E i); + void saveItem (E i) throws GeneralException; + +} diff --git a/src/main/java/com/quollwriter/ui/fx/ChapterProblemResultsBox.java b/src/main/java/com/quollwriter/ui/fx/ChapterProblemResultsBox.java new file mode 100644 index 00000000..6c4e8738 --- /dev/null +++ b/src/main/java/com/quollwriter/ui/fx/ChapterProblemResultsBox.java @@ -0,0 +1,528 @@ +package com.quollwriter.ui.fx; + +import java.util.*; +import java.util.function.*; +import java.util.stream.*; + +import javafx.scene.*; +import javafx.beans.property.*; +import javafx.scene.control.*; +import javafx.scene.input.*; + +import com.quollwriter.*; +import com.quollwriter.data.*; +import com.quollwriter.ui.fx.panels.*; +import com.quollwriter.ui.fx.viewers.*; +import com.quollwriter.ui.fx.components.*; +import com.quollwriter.ui.fx.sidebars.*; + +import com.quollwriter.text.*; + +import static com.quollwriter.uistrings.UILanguageStringsManager.getUILanguageStringProperty; +import com.quollwriter.uistrings.UILanguageStringsManager; +import static com.quollwriter.LanguageStrings.*; + +public class ChapterProblemResultsBox extends FindResultsBox +{ + + private Map> problems = null; + private TextEditor.Highlight highlightId = null; + private TextEditor.Highlight lineHighlightId = null; + private TextEditor highlightedEditor = null; + private QuollTreeView tree = null; + + public ChapterProblemResultsBox (ProjectViewer viewer, + Map> problems) + { + + super (viewer, + null); + + this.problems = problems; + + } + + @Override + public void dispose () + { + + this.clearHighlight (); + + } + + public QuollTreeView getTree () + { + + if (this.tree == null) + { + + this.tree = this.createTree (); + + } + + return this.tree; + + } + + @Override + public Node getContent () + { + + if (this.tree == null) + { + + this.tree = this.getTree (); + + } + + return this.tree; + + } + + private void saveIgnores (Set ignore, + Chapter c) + { + + c.getProblemFinderIgnores ().addAll (ignore); + + try + { + + this.viewer.saveProblemFinderIgnores (c); + + //this.sidebar.find (); + + this.viewer.fireProjectEvent (ProjectEvent.Type.problemfinder, + ProjectEvent.Action.ignore); + + } catch (Exception e) { + + Environment.logError ("Unable to save problem finder ignores for chapter: " + + c, + e); + + ComponentUtils.showErrorMessage (this.viewer, + getUILanguageStringProperty (project,LanguageStrings.sidebar,problemfinder,LanguageStrings.ignore,actionerror)); + //"Unable to save ignore."); + + } + + } + + private QuollTreeView createTree () + { + + final ChapterProblemResultsBox _this = this; + + Function, Node> cellProvider = (treeItem) -> + { + + Object n = treeItem.getValue (); + + if (n instanceof Project) + { + + return new Label (); + + } + + if (n instanceof Chapter) + { + + Chapter c = (Chapter) n; + + QuollLabel l = QuollLabel.builder () + .styleClassName (c.getObjectType ()) + .build (); + + l.textProperty ().bind (UILanguageStringsManager.createStringBinding (() -> + { + + String t = "%1$s (%2$s)"; + + return String.format (t, + c.getName (), + treeItem.getChildren ().size ()); + + }, + treeItem.getChildren (), + c.nameProperty ())); + + List mprefix = Arrays.asList (project,LanguageStrings.sidebar,problemfinder,results,treepopupmenu,items); + + ContextMenu cm = new ContextMenu (); + + cm.getItems ().add (QuollMenuItem.builder () + .iconName (StyleClassNames.IGNORE) + .label (getUILanguageStringProperty (Utils.newList (mprefix, ignoreall))) + .onAction (ev -> + { + + Set issues = treeItem.getChildren ().stream () + .map (ti -> (Issue) ti.getValue ()) + .collect (Collectors.toSet ()); + + this.saveIgnores (issues, + c); + + this.tree.removeObject (treeItem); + + }) + .build ()); + + l.setContextMenu (cm); + + l.addEventHandler (MouseEvent.MOUSE_RELEASED, + ev -> + { + + if (ev.isPopupTrigger ()) + { + + return; + + } + + this.tree.toggleOpen (treeItem); + + }); + + return l; + + } + + if (n instanceof Issue) + { + + Issue i = (Issue) n; + + TextBlock b = i.getTextBlock (); + + String value = null; + + if (b instanceof Paragraph) + { + + value = ((Paragraph) b).getFirstSentence ().getText (); + + } else { + + value = b.getText (); + + } + + QuollLabel l = QuollLabel.builder () + .styleClassName (StyleClassNames.ISSUE) + .label (new SimpleStringProperty (value)) + //.tooltip (new SimpleStringProperty (i.getDescription ())) + .build (); + + Tooltip t = new Tooltip (); + t.setGraphic (QuollTextView.builder () + .text (i.getDescription ()) + .build ()); + + l.setTooltip (t); + + List mprefix = Arrays.asList (project,LanguageStrings.sidebar,problemfinder,results,treepopupmenu,items); + + ContextMenu cm = new ContextMenu (); + + cm.getItems ().add (QuollMenuItem.builder () + .iconName (StyleClassNames.IGNORE) + .label (getUILanguageStringProperty (Utils.newList (mprefix, ignore))) + .onAction (ev -> + { + + Chapter c = i.getChapter (); + + Set issues = new HashSet<> (); + + issues.add (i); + + this.tree.removeObject (treeItem.getValue ()); + + this.clearHighlight (); + + this.saveIgnores (issues, + c); + + }) + .build ()); + + l.setContextMenu (cm); + + l.addEventHandler (MouseEvent.MOUSE_PRESSED, + ev -> + { + + if (ev.isPopupTrigger ()) + { + + return; + + } + + this.showChapterIssue (i); + + }); + + return l; + + } + + throw new IllegalStateException ("How did we get here?"); + + }; + + // Create the model. + TreeItem root = new TreeItem<> (); + root.setValue (this.viewer.getProject ()); + + for (Chapter c : this.problems.keySet ()) + { + + TreeItem ci = new TreeItem<> (); + ci.setValue (c); + root.getChildren ().add (ci); + + Set issues = this.problems.get (c); + +// Set ignores = c.getProblemFinderIgnores (); + for (Issue iss : issues) + { +/* + if (ignores.contains (iss)) + { + + continue; + + } +*/ + TreeItem ii = new TreeItem<> (); + ii.setValue (iss); + ci.getChildren ().add (ii); + + } + + } + + QuollTreeView tree = new QuollTreeView<> (); + tree.setShowRoot (false); + tree.getStyleClass ().add (StyleClassNames.PROBLEMFINDER); + tree.setCellProvider (cellProvider); + tree.setRoot (root); + + if (UserProperties.getAsBoolean (Constants.SHOW_EACH_CHAPTER_FIND_RESULT_PROPERTY_NAME)) + { + + tree.expandAll (); + + } + + return tree; + + } + + public void clearHighlight () + { + + if (this.highlightedEditor != null) + { + + this.highlightedEditor.removeHighlight (this.highlightId); + this.highlightedEditor.removeHighlight (this.lineHighlightId); + + } + + } + + public void showChapterIssue (Issue i) + { + + this.clearHighlight (); + + this.viewer.editChapter (i.getChapter (), + () -> + { + + ChapterEditorPanelContent p = this.viewer.getEditorForChapter (i.getChapter ()); + + p.scrollToTextPosition (i.getStartIssuePosition (), + () -> + { + + TextBlock textBlock = i.getTextBlock (); + + final TextEditor ed = p.getEditor (); + + int end = textBlock.getAllTextEndOffset () + 1; + + if (textBlock instanceof Sentence) + { + + end = ((Sentence) textBlock).getLastWord ().getAllTextEndOffset (); + + } + + this.lineHighlightId = ed.addHighlight (new IndexRange (textBlock.getAllTextStartOffset (), + textBlock.getAllTextEndOffset ()), + UserProperties.getProblemFinderBlockHighlightColor ()); + + this.highlightId = ed.addHighlight (new IndexRange (i.getStartIssuePosition (), + i.getEndIssuePosition ()), + UserProperties.getProblemFinderIssueHighlightColor ()); + + this.highlightedEditor = ed; + + }); + + }); + + } +/* + private class PopupPreviewListener extends MouseEventHandler + { + + private HideablePopup popup = null; + private Issue lastObject = null; + private ChapterProblemResultsBox results = null; + + public PopupPreviewListener (ChapterProblemResultsBox results) + { + + this.results = results; + + } + + @Override + public void handlePress (MouseEvent ev) + { + + if (this.popup != null) + { + + this.popup.hidePopup (); + + } + + } + + @Override + public void mouseMoved (MouseEvent ev) + { + + final PopupPreviewListener _this = this; + + // Edit the chapter. + TreePath tp = this.results.tree.getPathForLocation (ev.getX (), + ev.getY ()); + + if (tp == null) + { + + return; + + } + + Object d = ((DefaultMutableTreeNode) tp.getLastPathComponent ()).getUserObject (); + + if (!(d instanceof Issue)) + { + + return; + + } + + if (this.popup != null) + { + + this.popup.hidePopup (); + + } + + if ((this.lastObject != null) + && + (d != this.lastObject) + ) + { + + // Hide the popup. + this.popup.hidePopup (); + + } + + final Issue issue = (Issue) d; + + this.lastObject = issue; + + Point po = this.results.viewer.convertPoint (this.results.getTree (), + new Point (ev.getX () + 10, + this.results.getTree ().getPathBounds (tp).y + this.results.getTree ().getPathBounds (tp).height - 5)); + + this.popup = new HideablePopup (this.results.getViewer ()) + { + + @Override + public JComponent getContent () + { + + JEditorPane desc = UIUtils.createHelpTextPane (issue.getDescription (), + null); + + FormLayout fl = new FormLayout ("380px", + "p"); + + PanelBuilder pb = new PanelBuilder (fl); + + CellConstraints cc = new CellConstraints (); + + pb.add (desc, cc.xy (1, 1)); + + desc.setAlignmentX (Component.LEFT_ALIGNMENT); + + JPanel p = pb.getPanel (); + p.setOpaque (true); + p.setBackground (UIUtils.getComponentColor ()); + + return p; + + } + }; + + // Show the first line of the description. + this.popup.show (1000, + 250, + po, + new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + _this.lastObject = null; + + } + + }); + + } + + @Override + public void mouseExited (MouseEvent ev) + { + + this.lastObject = null; + + if (this.popup != null) + { + + this.popup.hidePopup (); + + } + + } + + } +*/ +} diff --git a/src/main/java/com/quollwriter/ui/fx/Command.java b/src/main/java/com/quollwriter/ui/fx/Command.java new file mode 100644 index 00000000..2f4b5c76 --- /dev/null +++ b/src/main/java/com/quollwriter/ui/fx/Command.java @@ -0,0 +1,97 @@ +package com.quollwriter.ui.fx; + +import java.util.*; + +public class Command +{ + + private Runnable action = null; + private List ids = null; + + protected Command (String... commandIds) + { + + if ((commandIds == null) + || + (commandIds.length == 0) + ) + { + + throw new IllegalArgumentException ("At least 1 command id must be provided."); + + } + + this.ids = Arrays.asList (commandIds); + + } + + public Command (Runnable action, + String... commandIds) + { + + if (action == null) + { + + throw new IllegalArgumentException ("Action must be provided."); + + } + + if ((commandIds == null) + || + (commandIds.length == 0) + ) + { + + throw new IllegalArgumentException ("At least 1 command id must be provided."); + + } + + this.action = action; + + this.ids = Arrays.asList (commandIds); + + } + + public void run () + { + + UIUtils.runLater (this.action); + + } + + public void run (Runnable doAfter) + { + + UIUtils.runLater (() -> + { + + this.action.run (); + + if (doAfter != null) + { + + UIUtils.runLater (doAfter); + + } + + }); + + } + + public List commandIds () + { + + return this.ids; + + } + + public static Command create (Runnable action, + String... commandIds) + { + + return new Command (action, + commandIds); + + } + +} diff --git a/src/main/java/com/quollwriter/ui/fx/CommandWithArgs.java b/src/main/java/com/quollwriter/ui/fx/CommandWithArgs.java new file mode 100644 index 00000000..c475acce --- /dev/null +++ b/src/main/java/com/quollwriter/ui/fx/CommandWithArgs.java @@ -0,0 +1,73 @@ +package com.quollwriter.ui.fx; + +import java.util.*; + +public class CommandWithArgs extends Command +{ + + private Action f = null; + + public CommandWithArgs (Action f, + String... ids) + { + + super (ids); + this.f = f; + + } + + @Override + public void run (Runnable doAfter) + { + + this.run (doAfter, + (E) null); + + } + + @Override + public void run () + { + + this.run ((Runnable) null); + + } + + public void run (E... objs) + { + + this.run (null, + objs); + + } + + public void run (Runnable doAfter, + E... objs) + { + + UIUtils.runLater (() -> + { + + this.f.apply (objs); + + if (doAfter != null) + { + + UIUtils.runLater (doAfter); + + } + + }); + + + } + + @FunctionalInterface + public interface Action + { + + void apply (E... objs); + + } + +} diff --git a/src/main/java/com/quollwriter/ui/fx/DebugConsole.java b/src/main/java/com/quollwriter/ui/fx/DebugConsole.java new file mode 100644 index 00000000..0c0ac237 --- /dev/null +++ b/src/main/java/com/quollwriter/ui/fx/DebugConsole.java @@ -0,0 +1,20 @@ +package com.quollwriter.ui.fx; + +import javafx.scene.*; +import javafx.scene.layout.*; + +import com.quollwriter.ui.fx.viewers.*; + +public class DebugConsole extends Region +{ + + private AbstractViewer viewer = null; + + public DebugConsole (AbstractViewer viewer) + { + + this.viewer = viewer; + + } + +} diff --git a/src/main/java/com/quollwriter/ui/fx/DefaultQuollWriterUpdater.java b/src/main/java/com/quollwriter/ui/fx/DefaultQuollWriterUpdater.java new file mode 100644 index 00000000..5ce1b569 --- /dev/null +++ b/src/main/java/com/quollwriter/ui/fx/DefaultQuollWriterUpdater.java @@ -0,0 +1,643 @@ +package com.quollwriter.ui.fx; + +import java.io.*; + +import java.net.*; + +import java.security.*; + +import java.util.*; +import java.util.concurrent.*; +import java.util.zip.*; + +import javafx.beans.property.*; +import javafx.scene.control.*; +import javafx.scene.layout.*; + +//import com.gentlyweb.properties.*; + +import com.quollwriter.*; + +import com.quollwriter.data.*; +import com.quollwriter.data.comparators.*; +import com.quollwriter.ui.fx.*; +import com.quollwriter.ui.fx.components.*; +import com.quollwriter.ui.fx.viewers.*; + +import static com.quollwriter.LanguageStrings.*; +import static com.quollwriter.uistrings.UILanguageStringsManager.getUILanguageStringProperty; + +public class DefaultQuollWriterUpdater implements QuollWriterUpdater +{ + + private AbstractViewer viewer = null; + private ProgressBar progressBar = null; + private boolean stop = false; + private Version version = null; + private long size = 0; + private String url = null; + private byte[] digest = null; + private boolean beta = false; + private Notification downloadNotification = null; + private QuollTextView help = null; + private Button cancel = null; + private ScheduledFuture watch = null; + private String fileExt = null; + + public DefaultQuollWriterUpdater () + { + + } + + public URL getUpgradeURL (Version version) + throws Exception + { + + String parms = "?version=" + version.getVersion () + "&platform=" + Environment.getOSPlatform (); + + return Environment.getSupportUrl (Constants.GET_UPGRADE_FILE_PAGE_PROPERTY_NAME, + parms); + + } + + private URL getNewsAndVersionCheckURL () + throws Exception + { + + Map parms = new HashMap<> (); + + if (UserProperties.getAsBoolean (Constants.OPTIN_TO_BETA_VERSIONS_PROPERTY_NAME)) + { + + parms.put ("beta", + "true"); + + } + + String lastVersionCheckTime = UserProperties.get (Constants.LAST_VERSION_CHECK_TIME_PROPERTY_NAME); + + if (lastVersionCheckTime != null) + { + + parms.put ("since", + lastVersionCheckTime); + + } + + parms.put ("platform", + Environment.getOSPlatform ()); + parms.put ("currVersion", + Environment.getQuollWriterVersion ().getVersion ()); + + return Environment.getSupportUrl (Constants.GET_LATEST_VERSION_PAGE_PROPERTY_NAME, + Utils.encodeParms (parms)); + + } + + private void doDownload () + { + + final List prefix = Arrays.asList (upgrade,download); + + final DefaultQuollWriterUpdater _this = this; +/* + this.progressBar = ControllableProgressBar.builder () + //.allowStop (true) + //.stopTooltip (getUILanguageStringProperty (buttons,cancel)) + .build (); +*/ + this.progressBar = new ProgressBar (0); + + int ind = 0; + + VBox b = new VBox (); + this.help = QuollTextView.builder () + .text (getUILanguageStringProperty (Utils.newList (prefix,start), + version)) + .inViewer (this.viewer) + .build (); + b.getChildren ().addAll (this.help, this.progressBar); +/* + this.progressBar.stateProperty ().addListener ((pr, oldv, newv) -> + { + + this.stop = true; + this.downloadNotification.removeNotification (); + + }); +*/ + this.downloadNotification = this.viewer.addNotification (b, + StyleClassNames.DOWNLOAD, + -1); + + this.downloadNotification.setOnRemove (() -> + { + + this.stop = true; + + }); + + File tf = null; + + try + { + + tf = File.createTempFile ("QuollWriter-install-" + _this.version.getVersion () + ".", + this.fileExt); + + //tf.deleteOnExit (); + + } catch (Exception e) + { + + Environment.logError ("Unable to create temp file for: " + + this.version, + e); + + this.showError (getUILanguageStringProperty (Utils.newList (prefix,errors,cantcreatetemporaryfile))); + //"Unable to create the temporary file for the download."); + + return; + + } + + final File outFile = tf; + + this.watch = Environment.schedule (() -> + { + + if (this.stop) + { + + this.watch.cancel (true); + + } + + int length = (int) outFile.length (); + + double v = (double) length / (double) _this.size; + + //double perc = v * 90f; + + UIUtils.runLater (() -> + { + + this.help.setText (getUILanguageStringProperty (Utils.newList (prefix,inprogress), + this.version.getVersion (), + Environment.formatNumber (length), + Environment.formatNumber (size))); + + this.setProgress (v); + + }); + + }, + 750, + 750); + + Environment.scheduleImmediately (() -> + { + + try + { + + URL u = new URL (this.url); + //this.getUpgradeURL (this.version); + + HttpURLConnection conn = (HttpURLConnection) u.openConnection (); + + conn.setDoInput (true); + conn.setDoOutput (true); + + conn.connect (); + + int p = 0; + + BufferedOutputStream out = new BufferedOutputStream (new FileOutputStream (outFile)); + + BufferedInputStream in = new BufferedInputStream (conn.getInputStream ()); + + byte[] buf = new byte[65536]; + + int bRead = -1; + + while ((bRead = in.read (buf)) != -1) + { + + if (this.stop) + { + + in.close (); + out.flush (); + out.close (); + + return; + + } + + out.write (buf, + 0, + bRead); + + } + + in.close (); + out.flush (); + out.close (); + + this.setProgress (90); + + watch.cancel (true); + + if (this.stop) + { + + return; + + } + + UIUtils.runLater (() -> + { + + this.help.setText (getUILanguageStringProperty (upgrade,checkingfile)); + + }); + + // Calculate a hash code. + MessageDigest md = MessageDigest.getInstance ("SHA-256"); + + DigestInputStream dis = new DigestInputStream (new BufferedInputStream (new FileInputStream (outFile)), + md); + + buf = new byte[65536]; + + bRead = -1; + + String ll = outFile.length () + ""; + + ll = ll.substring (ll.length () - 1); + + int v = 0; + + try + { + + v = Integer.parseInt (ll); + + } catch (Exception e) + { + } + + boolean odd = ((v % 2) == 0); + + while ((bRead = dis.read (buf)) != -1) + { + + if (odd) + { + + md.update (ll.getBytes ()); + + } else + { + + md.update (_this.version.getVersion ().getBytes ()); + + } + + } + + dis.close (); + + byte[] ddigest = md.digest (); + + if (_this.stop) + { + + return; + + } + + this.setProgress (95); + + // Digest calculated from download file is not the same as gained from the server. + StringProperty digestNotEqualError = getUILanguageStringProperty (Utils.newList (prefix,errors,digestinvalid)); + //"Digest calculated from download file is not the same as gained from the server."; + + // Compare the digest with that gained from the server. + if (!Arrays.equals (ddigest, + this.digest)) + { + + throw new GeneralException (digestNotEqualError.getValue ()); + + } + + UIUtils.runLater (() -> + { + + this.help.setText (getUILanguageStringProperty (Utils.newList (prefix,complete))); + //"Download of upgrade file complete..."); + + //this.cancel.setVisible (false); + this.downloadNotification.removeNotification (); + + this.setProgress (100); + + QuollButton nb = QuollButton.builder () + .label (upgrade,restart,buttons,exitnow) + .build (); + + QuollButton lb = QuollButton.builder () + .label (upgrade,restart,buttons,exitlater) + .build (); + + QuollPopup qp = QuollPopup.messageBuilder () + .title (getUILanguageStringProperty (upgrade,restart,title)) + .message (getUILanguageStringProperty (Arrays.asList (upgrade,restart,text), + this.version)) + .button (nb) + .button (lb) + .build (); + + nb.setOnAction (ev -> + { + + qp.close (); + + this.closeDown (); + + }); + + lb.setOnAction (ev -> + { + + qp.close (); + + }); + + }); + + Environment.addDoOnShutdown (() -> + { + + try + { + + List args = new ArrayList<> (); + + if (Environment.OsCheck.getOperatingSystemType () == Environment.OsCheck.OSType.MacOS) + { + + args.add ("open"); + + } + + if (Environment.OsCheck.getOperatingSystemType () == Environment.OsCheck.OSType.Linux) + { + + args.add ("xdg-open"); + + } + + args.add (outFile.getPath ()); + + ProcessBuilder pb = new ProcessBuilder (args); + pb.start (); + + // TODO Check that the JVM is exiting... + + } catch (Exception e) { + + Environment.logError ("Unable to run upgrade file: " + + outFile.getPath (), + e); + + } + + }); + + } catch (Exception e) + { + + Environment.logError ("Unable to download the upgrade file", + e); + + this.showError (getUILanguageStringProperty (Utils.newList (prefix,errors,unabletodownload))); + //"Unable to download the upgrade file."); + + } + + }); + + } + + public void doUpdate (AbstractViewer viewer) + { + + this.viewer = viewer; + + try + { + + URL u = this.getNewsAndVersionCheckURL (); + + HttpURLConnection conn = (HttpURLConnection) u.openConnection (); + + conn.setDoInput (true); + conn.setDoOutput (true); + + conn.connect (); + + BufferedInputStream bin = new BufferedInputStream (conn.getInputStream ()); + + ByteArrayOutputStream bout = new ByteArrayOutputStream (); + + Utils.streamTo (bin, + bout, + 8192); + + UserProperties.set (Constants.LAST_VERSION_CHECK_TIME_PROPERTY_NAME, + String.valueOf (System.currentTimeMillis ())); + + String info = new String (bout.toByteArray (), + "utf-8"); + + // Should be json. + Map data = (Map) JSONDecoder.decode (info); + + Map version = (Map) data.get ("version"); + + if (version != null) + { + + this.version = new Version ((String) version.get ("version")); + + this.url = (String) version.get ("url"); + + this.fileExt = this.url.substring (this.url.lastIndexOf (".")); + + this.size = ((Number) version.get ("size")).longValue (); + + this.digest = com.quollwriter.Base64.decode ((String) version.get ("digest")); + + if (Environment.getQuollWriterVersion ().isNewer (this.version)) + { + + UIUtils.runLater (() -> + { + + QuollButton dl = QuollButton.builder () + .label (getUILanguageStringProperty (upgrade,newversionavailable,buttons,download)) + .buttonType (ButtonBar.ButtonData.APPLY) + .build (); + + QuollButton later = QuollButton.builder () + .label (getUILanguageStringProperty (upgrade,newversionavailable,buttons,LanguageStrings.later)) + .buttonType (ButtonBar.ButtonData.CANCEL_CLOSE) + .build (); + + QuollButtonBar bb = QuollButtonBar.builder () + .button (dl) + .button (later) + .build (); + + VBox v = new VBox (); + v.getChildren ().add (QuollTextView.builder () + .text (getUILanguageStringProperty (Arrays.asList (upgrade,newversionavailable,text), + this.version.getVersion ().replace (".", + "-"))) + .build ()); + + v.getChildren ().add (bb); + + Notification n = this.viewer.addNotification (v, + StyleClassNames.DOWNLOAD, + 90); + + later.setOnAction (ev -> + { + + n.removeNotification (); + + }); + + dl.setOnAction (ev -> + { + + this.doDownload (); + n.removeNotification (); + + }); + + }); + + } + + } + + } catch (Exception e) + { + + Environment.logError ("Unable to perform update check", + e); + + } + + } + + private void showError (StringProperty m) + { + + UIUtils.runLater (() -> + { + + ComponentUtils.showErrorMessage (this.viewer, + m); + + this.downloadNotification.removeNotification (); + + }); + + } + + private void showGeneralError () + { + + this.showError (getUILanguageStringProperty (Arrays.asList (upgrade,download,errors,general), + //"Unable to download/install the new version. Click here to download the latest version from the Quoll Writer website", + UserProperties.get (Constants.QUOLLWRITER_DOWNLOADS_URL_PROPERTY_NAME))); + + this.downloadNotification.removeNotification (); + + } + + public void setProgress (double p) + { + + UIUtils.runLater (() -> + { + + this.progressBar.setProgress (p); + + }); + + } + + private void closeDown () + { + + final DefaultQuollWriterUpdater _this = this; + + Environment.getOpenViewers ().stream () + .forEach (pv -> pv.close (null)); + + // TODO Environment.doForOpenViewers -> close () +/* +TODO + Map open = Environment.getOpenProjects (); + + // Get the first, close it. + if (open.size () > 0) + { + + AbstractProjectViewer pv = open.values ().iterator ().next (); + + pv.setState (java.awt.Frame.NORMAL); + pv.toFront (); + + pv.close (false, + new ActionListener () + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + _this.closeDown (); + + } + + }); + + return; + + } else { + + if (Environment.getAllProjectsViewer () != null) + { + + Environment.getAllProjectsViewer ().close (null); + + } else { + + Environment.closeDown (); + + } + + } +*/ + + } + +} diff --git a/src/main/java/com/quollwriter/ui/fx/EditUserConfigurableTypeFieldPanel.java b/src/main/java/com/quollwriter/ui/fx/EditUserConfigurableTypeFieldPanel.java new file mode 100644 index 00000000..f0c328db --- /dev/null +++ b/src/main/java/com/quollwriter/ui/fx/EditUserConfigurableTypeFieldPanel.java @@ -0,0 +1,135 @@ +package com.quollwriter.ui.fx; + +import java.util.*; +import java.util.function.*; + +import javafx.beans.property.*; +import javafx.util.*; +import javafx.collections.*; +import javafx.scene.control.*; +import javafx.scene.layout.*; + +import com.quollwriter.*; +import com.quollwriter.data.*; +import com.quollwriter.ui.fx.userobjects.*; +import com.quollwriter.ui.fx.components.*; + +import static com.quollwriter.uistrings.UILanguageStringsManager.getUILanguageStringProperty; +import static com.quollwriter.LanguageStrings.*; + +public class EditUserConfigurableTypeFieldPanel extends VBox +{ + + private QuollTextField nameField = null; + + public EditUserConfigurableTypeFieldPanel (UserConfigurableObjectTypeField field) + { + + List prefix = Arrays.asList (userobjects,fields,LanguageStrings.edit); + +/* + Header h = Header.builder () + .title (getUILanguageStringProperty (userobjects,fields,LanguageStrings.edit,title)) + .build (); + + this.config.getChildren ().add (h); +*/ + UserConfigurableObjectTypeFieldConfigHandler handler = field.getConfigHandler2 (); + + this.nameField = QuollTextField.builder () + .styleClassName (StyleClassNames.NAME) + .text (field.getFormName ()) + .build (); + + Form.Builder fb = Form.builder () + .layoutType (Form.LayoutType.stacked) + .item (getUILanguageStringProperty (Utils.newList (prefix,labels,LanguageStrings.name)), + nameField); + + Set nitems = handler.getExtraFormItems (); + + if ((nitems != null) + && + (nitems.size () > 0) + ) + { + + fb.items (nitems); + + } + + Form f = fb.confirmButton (getUILanguageStringProperty (buttons,save)) + .cancelButton (getUILanguageStringProperty (buttons,cancel)) + .build (); + f.setOnConfirm (ev -> + { + + ev.consume (); + Set errs = new LinkedHashSet<> (); + + if (nameField.getText ().trim ().equals ("")) + { + + errs.add (getUILanguageStringProperty (Utils.newList (prefix,LanguageStrings.errors,LanguageStrings.name,novalue))); + + } + + // Check for the name being the same as another field. + String formName = nameField.getText ().trim (); + String lformName = formName.toLowerCase (); + + for (UserConfigurableObjectTypeField uf : field.getUserConfigurableObjectType ().getConfigurableFields ()) + { + + if ((!uf.equals (field)) + && + (uf.getFormName ().equalsIgnoreCase (lformName)) + ) + { + + errs.add (getUILanguageStringProperty (Utils.newList (prefix,LanguageStrings.errors,LanguageStrings.name,valueexists), + uf.getFormName ())); + + } + + } + + Set errs2 = handler.getExtraFormItemErrors (field.getUserConfigurableObjectType ()); + + if (errs2 != null) + { + + errs.addAll (errs2); + + } + + if (errs.size () > 0) + { + + f.showErrors (errs); + return; + + } + + field.setFormName (formName); + + handler.updateFromExtraFormItems (); + + this.fireEvent (new Form.FormEvent (f, Form.FormEvent.CONFIRM_EVENT)); + + }); + + + this.getChildren ().add (f); + + } + + @Override + public void requestFocus () + { + + this.nameField.requestFocus (); + + } + +} diff --git a/src/main/java/com/quollwriter/ui/fx/FadeApp.java b/src/main/java/com/quollwriter/ui/fx/FadeApp.java new file mode 100644 index 00000000..7cec1e9b --- /dev/null +++ b/src/main/java/com/quollwriter/ui/fx/FadeApp.java @@ -0,0 +1,151 @@ +package com.quollwriter.ui.fx; + +import javafx.animation.FadeTransition; +import javafx.application.Application; +import javafx.beans.property.ReadOnlyObjectProperty; +import javafx.collections.*; +import javafx.concurrent.*; +import javafx.geometry.*; +import javafx.scene.Scene; +import javafx.scene.control.*; +import javafx.scene.effect.DropShadow; +import javafx.scene.image.*; +import javafx.scene.layout.*; +import javafx.scene.paint.Color; +import javafx.stage.*; +import javafx.util.Duration; + +/** + * Example of displaying a splash page for a standalone JavaFX application + */ +public class FadeApp extends Application { + public static final String APPLICATION_ICON = + "http://cdn1.iconfinder.com/data/icons/Copenhagen/PNG/32/people.png"; + public static final String SPLASH_IMAGE = + "http://fxexperience.com/wp-content/uploads/2010/06/logo.png"; + + private Pane splashLayout; + private ProgressBar loadProgress; + private Label progressText; + private Stage mainStage; + private static final int SPLASH_WIDTH = 676; + private static final int SPLASH_HEIGHT = 227; + + public static void main(String[] args) throws Exception { + launch(args); + } + + @Override + public void init() { + ImageView splash = new ImageView(new Image( + SPLASH_IMAGE + )); + loadProgress = new ProgressBar(); + loadProgress.setPrefWidth(SPLASH_WIDTH - 20); + progressText = new Label("Will find friends for peanuts . . ."); + splashLayout = new VBox(); + splashLayout.getChildren().addAll(splash, loadProgress, progressText); + progressText.setAlignment(Pos.CENTER); + splashLayout.setStyle( + "-fx-padding: 5; " + + "-fx-background-color: cornsilk; " + + "-fx-border-width:5; " + + "-fx-border-color: " + + "linear-gradient(" + + "to bottom, " + + "chocolate, " + + "derive(chocolate, 50%)" + + ");" + ); + splashLayout.setEffect(new DropShadow()); + } + + @Override + public void start(final Stage initStage) throws Exception { + final Task> friendTask = new Task>() { + @Override + protected ObservableList call() throws InterruptedException { + ObservableList foundFriends = + FXCollections.observableArrayList(); + ObservableList availableFriends = + FXCollections.observableArrayList( + "Fili", "Kili", "Oin", "Gloin", "Thorin", + "Dwalin", "Balin", "Bifur", "Bofur", + "Bombur", "Dori", "Nori", "Ori" + ); + + updateMessage("Finding friends . . ."); + for (int i = 0; i < availableFriends.size(); i++) { + Thread.sleep(400); + updateProgress(i + 1, availableFriends.size()); + String nextFriend = availableFriends.get(i); + foundFriends.add(nextFriend); + updateMessage("Finding friends . . . found " + nextFriend); + } + Thread.sleep(400); + updateMessage("All friends found."); + + return foundFriends; + } + }; + + showSplash( + initStage, + friendTask, + () -> showMainStage(friendTask.valueProperty()) + ); + new Thread(friendTask).start(); + } + + private void showMainStage( + ReadOnlyObjectProperty> friends + ) { + mainStage = new Stage(StageStyle.DECORATED); + mainStage.setTitle("My Friends"); + mainStage.getIcons().add(new Image( + APPLICATION_ICON + )); + + final ListView peopleView = new ListView<>(); + peopleView.itemsProperty().bind(friends); + + mainStage.setScene(new Scene(peopleView)); + mainStage.show(); + } + + private void showSplash( + final Stage initStage, + Task task, + InitCompletionHandler initCompletionHandler + ) { + progressText.textProperty().bind(task.messageProperty()); + loadProgress.progressProperty().bind(task.progressProperty()); + task.stateProperty().addListener((observableValue, oldState, newState) -> { + if (newState == Worker.State.SUCCEEDED) { + loadProgress.progressProperty().unbind(); + loadProgress.setProgress(1); + initStage.toFront(); + FadeTransition fadeSplash = new FadeTransition(Duration.seconds(1.2), splashLayout); + fadeSplash.setFromValue(1.0); + //fadeSplash.setToValue(0.0); + //fadeSplash.setOnFinished(actionEvent -> initStage.hide()); + //fadeSplash.play(); + + initCompletionHandler.complete(); + } // todo add code to gracefully handle other task states. + }); + + Scene splashScene = new Scene(splashLayout, Color.TRANSPARENT); + final Rectangle2D bounds = Screen.getPrimary().getBounds(); + initStage.setScene(splashScene); + initStage.setX(bounds.getMinX() + bounds.getWidth() / 2 - SPLASH_WIDTH / 2); + initStage.setY(bounds.getMinY() + bounds.getHeight() / 2 - SPLASH_HEIGHT / 2); + initStage.initStyle(StageStyle.TRANSPARENT); + initStage.setAlwaysOnTop(true); + initStage.show(); + } + + public interface InitCompletionHandler { + void complete(); + } +} diff --git a/src/main/java/com/quollwriter/ui/fx/FindResultsBox.java b/src/main/java/com/quollwriter/ui/fx/FindResultsBox.java new file mode 100644 index 00000000..757380eb --- /dev/null +++ b/src/main/java/com/quollwriter/ui/fx/FindResultsBox.java @@ -0,0 +1,36 @@ +package com.quollwriter.ui.fx; + +import javafx.scene.*; + +import com.quollwriter.ui.fx.viewers.*; +import com.quollwriter.ui.fx.components.*; +import com.quollwriter.data.*; + +public abstract class FindResultsBox implements IPropertyBinder +{ + + protected E viewer = null; + private IPropertyBinder binder = null; + + public FindResultsBox (E pv, + IPropertyBinder binder) + { + + this.viewer = pv; + this.binder = binder; + + } + + public abstract void dispose (); + + public abstract Node getContent (); + + @Override + public IPropertyBinder getBinder () + { + + return this.binder; + + } + +} diff --git a/src/main/java/com/quollwriter/ui/fx/FullScreenPropertiesPanel.java b/src/main/java/com/quollwriter/ui/fx/FullScreenPropertiesPanel.java new file mode 100644 index 00000000..df854aee --- /dev/null +++ b/src/main/java/com/quollwriter/ui/fx/FullScreenPropertiesPanel.java @@ -0,0 +1,321 @@ +package com.quollwriter.ui.fx; + +import java.util.*; + +import javafx.beans.value.*; +import javafx.scene.*; +import javafx.geometry.*; +import javafx.scene.layout.*; +import javafx.beans.property.*; +import javafx.scene.control.*; +import javafx.scene.input.*; + +import com.quollwriter.*; +import com.quollwriter.data.IPropertyBinder; +import com.quollwriter.ui.fx.viewers.*; +import com.quollwriter.ui.fx.components.*; + +import static com.quollwriter.uistrings.UILanguageStringsManager.getUILanguageStringProperty; +import static com.quollwriter.LanguageStrings.*; + +public class FullScreenPropertiesPanel extends VBox +{ + + private BackgroundPane bgsel = null; + private Pane bgsize = null; + private Slider bgopacity = null; + private QuollCheckBox bgshowwctime = null; + private IPropertyBinder binder = null; + private boolean ignoreChanges = false; + + public FullScreenPropertiesPanel (AbstractProjectViewer viewer, + IPropertyBinder binder) + { + + this.getStyleClass ().add (StyleClassNames.FULLSCREEN); + + Form.Builder fb = Form.builder (); + + this.bgsel = new BackgroundPane (viewer); + + try + { + + this.bgsel.setBackgroundObject (UserProperties.getFullScreenBackground ()); + + } catch (Exception e) { + + Environment.logError ("Unable to set full screen background to: " + + UserProperties.getFullScreenBackground (), + e); + + } + + this.bgsel.setOnMouseClicked (ev -> + { + + if (ev.getButton () != MouseButton.PRIMARY) + { + + return; + + } + + this.bgsel.showBackgroundSelector (); + + }); + + this.bgsel.getBackgroundObject ().backgroundProperty ().addListener ((pr, oldv, newv) -> + { + + try + { + + this.ignoreChanges = true; + + UserProperties.setFullScreenBackground (this.bgsel.getBackgroundObject ().getBackgroundObject ()); + + } finally { + + this.ignoreChanges = false; + + } + + }); + + binder.addChangeListener (UserProperties.fullScreenBackgroundProperty (), + (pr, oldv, newv) -> + { + + if (this.ignoreChanges) + { + + return; + + } + + try + { + + this.bgsel.setBackgroundObject (newv); + + } catch (Exception e) { + + Environment.logError ("Unable to set full screen background to: " + + newv, + e); + + } + + }); + + fb.item (getUILanguageStringProperty (project,sidebar,fullscreenproperties,selectbackground,text), + this.bgsel); + + fb.item (QuollHyperlink.builder () + .label (getUILanguageStringProperty (project,sidebar,fullscreenproperties,bgimagewebsites,text)) + .styleClassName (StyleClassNames.SELECTBG) + .onAction (ev -> + { + + // Open the url. + UIUtils.openURL (viewer, + Constants.QUOLLWRITER_PROTOCOL + ":resources.html#bgimages"); + + }) + .build ()); + + this.bgopacity = new Slider (0, 1, UserProperties.getFullScreenOpacity ()); + UIUtils.setTooltip (this.bgopacity, + getUILanguageStringProperty (project,sidebar,fullscreenproperties,LanguageStrings.bgopacity,tooltip)); + this.bgopacity.valueProperty ().addListener ((pr, oldv, newv) -> + { + + try + { + + this.ignoreChanges = true; + + UserProperties.setFullScreenOpacity (newv.doubleValue ()); + + } finally { + + + this.ignoreChanges = false; + + } + + }); + + binder.addChangeListener (UserProperties.fullScreenOpacityProperty (), + (pr, oldv, newv) -> + { + + if (this.ignoreChanges) + { + + return; + + } + + this.bgopacity.setValue (newv.doubleValue ()); + + }); + + fb.item (getUILanguageStringProperty (project,sidebar,fullscreenproperties,LanguageStrings.bgopacity,text), + this.bgopacity); + + int border = 2; + + this.bgsize = new Pane (); + this.bgsize.getStyleClass ().add (StyleClassNames.INNER); + Pane bgsizeWrapper = new Pane (); + bgsizeWrapper.getChildren ().add (this.bgsize); + bgsizeWrapper.getStyleClass ().add (StyleClassNames.BACKGROUNDSIZEBOX); + UIUtils.setTooltip (this.bgsize, + getUILanguageStringProperty (project,sidebar,fullscreenproperties,areasize,tooltip)); + + ChangeListener resizeRelocate = (pr, oldv, newv) -> + { + + double w = bgsizeWrapper.getWidth (); + double h = bgsizeWrapper.getHeight (); + + double xbw = UserProperties.getFullScreenXBorderWidth (); + double ybw = UserProperties.getFullScreenYBorderWidth (); + + double cx = w * xbw; + double cy = h * ybw; + + this.bgsize.setPrefSize ((double) Math.round (w - (2 * w * xbw) - (2 * border)), + (double) Math.round (h - (2 * h * ybw) - (2 * border))); + this.bgsize.relocate (Math.round (cx), Math.round (cy)); + + }; + + binder.addChangeListener (UserProperties.fullScreenXBorderWidthProperty (), + resizeRelocate); + binder.addChangeListener (UserProperties.fullScreenYBorderWidthProperty (), + resizeRelocate); + + this.sceneProperty ().addListener ((pr, oldv, newv) -> + { + + if ((oldv == null) + && + (newv != null) + ) + { + + javafx.application.Platform.runLater (() -> + //UIUtils.runLater (() -> + { + + resizeRelocate.changed (UserProperties.fullScreenXBorderWidthProperty (), + 0, + 0); + + }); + + } + + }); + + fb.item (getUILanguageStringProperty (project,sidebar,fullscreenproperties,areasize,text), + bgsizeWrapper); + + DragResizer mdr = DragResizer.makeResizable (this.bgsize, + border, + Side.TOP, + Side.BOTTOM, + Side.LEFT, + Side.RIGHT); + + mdr.setOnDraggingLeft (() -> + { + + if (mdr.getDragZone () == Side.RIGHT) + { + + UserProperties.incrementFullScreenXBorderWidth (); + + } + + if (mdr.getDragZone () == Side.LEFT) + { + + UserProperties.decrementFullScreenXBorderWidth (); + + } + + }); + + mdr.setOnDraggingRight (() -> + { + + if (mdr.getDragZone () == Side.RIGHT) + { + + UserProperties.decrementFullScreenXBorderWidth (); + + } + + if (mdr.getDragZone () == Side.LEFT) + { + + UserProperties.incrementFullScreenXBorderWidth (); + + } + + }); + + mdr.setOnDraggingUp (() -> + { + + if (mdr.getDragZone () == Side.TOP) + { + + UserProperties.decrementFullScreenYBorderWidth (); + + } + + if (mdr.getDragZone () == Side.BOTTOM) + { + + UserProperties.incrementFullScreenYBorderWidth (); + + } + + }); + + mdr.setOnDraggingDown (() -> + { + + if (mdr.getDragZone () == Side.TOP) + { + + UserProperties.incrementFullScreenYBorderWidth (); + + } + + if (mdr.getDragZone () == Side.BOTTOM) + { + + UserProperties.decrementFullScreenYBorderWidth (); + + } + + }); + + this.bgshowwctime = QuollCheckBox.builder () + .label (project,sidebar,fullscreenproperties,showtimewordcount,text) + .userProperty (Constants.FULL_SCREEN_SHOW_TIME_WORD_COUNT_PROPERTY_NAME) + .build (); + + fb.item (this.bgshowwctime); + + this.getChildren ().add (fb.build ()); + + } + +} diff --git a/src/main/java/com/quollwriter/ui/fx/FullScreenTextProperties.java b/src/main/java/com/quollwriter/ui/fx/FullScreenTextProperties.java new file mode 100644 index 00000000..b44d4b93 --- /dev/null +++ b/src/main/java/com/quollwriter/ui/fx/FullScreenTextProperties.java @@ -0,0 +1,349 @@ +package com.quollwriter.ui.fx; + +import javafx.scene.paint.*; + +import com.gentlyweb.properties.*; + +import com.quollwriter.*; +import com.quollwriter.data.*; + +public class FullScreenTextProperties extends TextProperties implements UserPropertySetter +{ + + private boolean allowSet = true; + + public FullScreenTextProperties () + { + + boolean v = Environment.isNightModeEnabled (); + + String fontColor = null; + String bgColor = null; + String lineColor = null; + + if (v) + { + + fontColor = UserProperties.get (Constants.FULL_SCREEN_EDITOR_FONT_COLOR_NIGHT_MODE_PROPERTY_NAME); + + if (fontColor == null) + { + + fontColor = UserProperties.get (Constants.EDITOR_FONT_COLOR_NIGHT_MODE_PROPERTY_NAME); + + } + + bgColor = UserProperties.get (Constants.FULL_SCREEN_EDITOR_BGCOLOR_NIGHT_MODE_PROPERTY_NAME); + + if (bgColor == null) + { + + bgColor = UserProperties.get (Constants.EDITOR_BGCOLOR_NIGHT_MODE_PROPERTY_NAME); + + } + + lineColor = UserProperties.get (Constants.FULL_SCREEN_EDITOR_WRITING_LINE_COLOR_NIGHT_MODE_PROPERTY_NAME); + + if (lineColor == null) + { + + lineColor = UserProperties.get (Constants.EDITOR_WRITING_LINE_COLOR_NIGHT_MODE_PROPERTY_NAME); + + } + + } + + if (fontColor == null) + { + + fontColor = UserProperties.get (Constants.FULL_SCREEN_EDITOR_FONT_COLOR_PROPERTY_NAME, + Constants.EDITOR_FONT_COLOR_PROPERTY_NAME); + + } + + if (bgColor == null) + { + + bgColor = UserProperties.get (Constants.FULL_SCREEN_EDITOR_BGCOLOR_PROPERTY_NAME, + Constants.EDITOR_BGCOLOR_PROPERTY_NAME); + + } + + if (lineColor == null) + { + + lineColor = UserProperties.get (Constants.FULL_SCREEN_EDITOR_WRITING_LINE_COLOR_PROPERTY_NAME, + Constants.EDITOR_WRITING_LINE_COLOR_PROPERTY_NAME); + + } + + this.initInternal (UserProperties.get (Constants.FULL_SCREEN_EDITOR_FONT_PROPERTY_NAME, + Constants.EDITOR_FONT_PROPERTY_NAME), + UserProperties.getAsInt (Constants.FULL_SCREEN_EDITOR_FONT_SIZE_PROPERTY_NAME, + Constants.EDITOR_FONT_SIZE_PROPERTY_NAME), + UserProperties.get (Constants.FULL_SCREEN_EDITOR_ALIGNMENT_PROPERTY_NAME, + Constants.EDITOR_ALIGNMENT_PROPERTY_NAME), + UserProperties.getAsBoolean (Constants.FULL_SCREEN_EDITOR_INDENT_FIRST_LINE_PROPERTY_NAME, + Constants.EDITOR_INDENT_FIRST_LINE_PROPERTY_NAME), + UserProperties.getAsFloat (Constants.FULL_SCREEN_EDITOR_LINE_SPACING_PROPERTY_NAME, + Constants.EDITOR_LINE_SPACING_PROPERTY_NAME), + UserProperties.getAsFloat (Constants.FULL_SCREEN_EDITOR_PARAGRAPH_SPACING_PROPERTY_NAME, + Constants.EDITOR_PARAGRAPH_SPACING_PROPERTY_NAME), + UIUtils.hexToColor (fontColor), + UIUtils.hexToColor (bgColor), + UIUtils.hexToColor (lineColor), + UserProperties.getAsBoolean (Constants.FULL_SCREEN_EDITOR_HIGHLIGHT_WRITING_LINE_PROPERTY_NAME, + Constants.EDITOR_HIGHLIGHT_WRITING_LINE_PROPERTY_NAME), + UserProperties.getAsInt (Constants.FULL_SCREEN_EDITOR_TEXT_BORDER_PROPERTY_NAME, + Constants.EDITOR_TEXT_BORDER_PROPERTY_NAME) + ); + + Environment.nightModeProperty ().addListener ((pr, oldv, newv) -> + { + + String c = UserProperties.get (newv ? Constants.FULL_SCREEN_EDITOR_FONT_COLOR_NIGHT_MODE_PROPERTY_NAME : Constants.FULL_SCREEN_EDITOR_FONT_COLOR_PROPERTY_NAME); + + if (c == null) + { + + c = UserProperties.get (Constants.FULL_SCREEN_EDITOR_FONT_COLOR_PROPERTY_NAME, + Constants.EDITOR_FONT_COLOR_PROPERTY_NAME); + + } + + this.setTextColor (UIUtils.hexToColor (c)); + + c = UserProperties.get (newv ? Constants.FULL_SCREEN_EDITOR_BGCOLOR_NIGHT_MODE_PROPERTY_NAME : Constants.FULL_SCREEN_EDITOR_BGCOLOR_PROPERTY_NAME); + + if (c == null) + { + + c = UserProperties.get (Constants.FULL_SCREEN_EDITOR_BGCOLOR_PROPERTY_NAME, + Constants.EDITOR_BGCOLOR_PROPERTY_NAME); + + } + + this.setBackgroundColor (UIUtils.hexToColor (c)); + + c = UserProperties.get (newv ? Constants.FULL_SCREEN_EDITOR_WRITING_LINE_COLOR_NIGHT_MODE_PROPERTY_NAME : Constants.FULL_SCREEN_EDITOR_WRITING_LINE_COLOR_PROPERTY_NAME); + + if (c == null) + { + + c = UserProperties.get (Constants.FULL_SCREEN_EDITOR_WRITING_LINE_COLOR_PROPERTY_NAME, + Constants.EDITOR_WRITING_LINE_COLOR_PROPERTY_NAME); + + } + + this.setWritingLineColor (UIUtils.hexToColor (c)); + + }); + + } + + public FullScreenTextProperties (TextProperties props) + { + + this.initInternal (props); + + } + + @Override + public void stopSetting () + { + + this.allowSet = false; + + } + + @Override + public void startSetting () + { + + this.allowSet = true; + + } + + public void setBackgroundColor (Color c) + { + + super.setBackgroundColor (c); +/* + if (c.equals (this.getTextColor ())) + { + + if (c.equals (Color.BLACK)) + { + + // Set the background to white. + this.setTextColor (Color.WHITE); + + } + + if (c.equals (Color.WHITE)) + { + + // Set the background to black. + this.setTextColor (Color.BLACK); + + } + + } +*/ + this.setProperty (new StringProperty (Environment.isNightModeEnabled () ? Constants.FULL_SCREEN_EDITOR_BGCOLOR_NIGHT_MODE_PROPERTY_NAME : Constants.FULL_SCREEN_EDITOR_BGCOLOR_PROPERTY_NAME, + UIUtils.colorToHex (this.getBackgroundColor ()))); + + } + + public void setTextColor (Color c) + { + + super.setTextColor (c); +/* + if (c.equals (this.getBackgroundColor ())) + { + + if (c.equals (Color.BLACK)) + { + + this.setBackgroundColor (Color.WHITE); + + } + + if (c.equals (Color.WHITE)) + { + + // Set the background to black. + this.setBackgroundColor (Color.BLACK); + + } + + } +*/ + this.setProperty (new StringProperty (Environment.isNightModeEnabled () ? Constants.FULL_SCREEN_EDITOR_FONT_COLOR_NIGHT_MODE_PROPERTY_NAME : Constants.FULL_SCREEN_EDITOR_FONT_COLOR_PROPERTY_NAME, + UIUtils.colorToHex (this.getTextColor ()))); + + } + + public void setWritingLineColor (Color c) + { + + super.setWritingLineColor (c); + + this.setProperty (new StringProperty (Environment.isNightModeEnabled () ? Constants.FULL_SCREEN_EDITOR_WRITING_LINE_COLOR_NIGHT_MODE_PROPERTY_NAME : Constants.FULL_SCREEN_EDITOR_WRITING_LINE_COLOR_PROPERTY_NAME, + UIUtils.colorToHex (this.getWritingLineColor ()))); + + } + + public void setHighlightWritingLine (boolean v) + { + + super.setHighlightWritingLine (v); + + this.setProperty (new BooleanProperty (Constants.FULL_SCREEN_EDITOR_HIGHLIGHT_WRITING_LINE_PROPERTY_NAME, + v)); + + } + + public void setLineSpacing (float v) + { + + super.setLineSpacing (v); + + this.setProperty (new FloatProperty (Constants.FULL_SCREEN_EDITOR_LINE_SPACING_PROPERTY_NAME, + this.getLineSpacing ())); + + } + + public void setParagraphSpacing (float v) + { + + super.setParagraphSpacing (v); + + this.setProperty (new FloatProperty (Constants.FULL_SCREEN_EDITOR_PARAGRAPH_SPACING_PROPERTY_NAME, + this.getLineSpacing ())); + + } + + public void setFirstLineIndent (boolean v) + { + + super.setFirstLineIndent (v); + + this.setProperty (new BooleanProperty (Constants.FULL_SCREEN_EDITOR_INDENT_FIRST_LINE_PROPERTY_NAME, + this.getFirstLineIndent ())); + + } + + public void setAlignment (String v) + { + + super.setAlignment (v); + + this.setProperty (new StringProperty (Constants.FULL_SCREEN_EDITOR_ALIGNMENT_PROPERTY_NAME, + this.getAlignment ())); + + } + + public void setFontSize (int v) + { + + super.setFontSize (v); + + this.setProperty (new IntegerProperty (Constants.FULL_SCREEN_EDITOR_FONT_SIZE_PROPERTY_NAME, + this.getFontSize ())); + + } + + public void setTextBorder (int v) + { + + super.setTextBorder (v); + + this.setProperty (new IntegerProperty (Constants.FULL_SCREEN_EDITOR_TEXT_BORDER_PROPERTY_NAME, + this.getTextBorder ())); + + } + + public void setFontFamily (String f) + { + + super.setFontFamily (f); + + this.setProperty (new StringProperty (Constants.FULL_SCREEN_EDITOR_FONT_PROPERTY_NAME, + this.getFontFamily ())); + + } + + private void setProperty (AbstractProperty prop) + { + + if (!this.allowSet) + { + + return; + + } + + UserProperties.set (prop.getID (), + prop); + + } +/* + public void resetToDefaults () + { + + this.setBackgroundColor (UIUtils.hexToColor (UserProperties.get (Constants.DEFAULT_EDITOR_BGCOLOR_PROPERTY_NAME))); + this.setTextColor (UIUtils.hexToColor (UserProperties.get (Constants.DEFAULT_EDITOR_FONT_COLOR_PROPERTY_NAME))); + this.setTextBorder (UserProperties.getAsInt (Constants.DEFAULT_EDITOR_TEXT_BORDER_PROPERTY_NAME)); + this.setFontFamily (UserProperties.get (Constants.DEFAULT_EDITOR_FONT_PROPERTY_NAME)); + this.setFontSize (UserProperties.getAsInt (Constants.DEFAULT_EDITOR_FONT_SIZE_PROPERTY_NAME)); + this.setAlignment (Environment.getDefaultTextAlignment ()); + this.setFirstLineIndent (UserProperties.getAsBoolean (Constants.DEFAULT_EDITOR_INDENT_FIRST_LINE_PROPERTY_NAME)); + this.setLineSpacing (UserProperties.getAsFloat (Constants.DEFAULT_EDITOR_LINE_SPACING_PROPERTY_NAME)); + this.setWritingLineColor (UIUtils.hexToColor (UserProperties.get (Constants.DEFAULT_EDITOR_WRITING_LINE_COLOR_PROPERTY_NAME))); + this.setHighlightWritingLine (UserProperties.getAsBoolean (Constants.DEFAULT_EDITOR_HIGHLIGHT_WRITING_LINE_PROPERTY_NAME)); + + } +*/ +} diff --git a/src/main/java/com/quollwriter/ui/fx/IBuilder.java b/src/main/java/com/quollwriter/ui/fx/IBuilder.java new file mode 100644 index 00000000..2a0e0c0a --- /dev/null +++ b/src/main/java/com/quollwriter/ui/fx/IBuilder.java @@ -0,0 +1,16 @@ +package com.quollwriter.ui.fx; + +public /*abstract class*/ interface IBuilder, E> +{ + + public T _this (); + + public E build () + throws Exception; +/* + protected abstract T _this (); + + public abstract E build () + throws Exception; +*/ +} diff --git a/src/main/java/com/quollwriter/ui/fx/LanguageStringsIdBox.java b/src/main/java/com/quollwriter/ui/fx/LanguageStringsIdBox.java new file mode 100644 index 00000000..1cf4499a --- /dev/null +++ b/src/main/java/com/quollwriter/ui/fx/LanguageStringsIdBox.java @@ -0,0 +1,1070 @@ +package com.quollwriter.ui.fx; + +import java.util.concurrent.*; + +import java.util.*; +import java.util.stream.*; + +import javafx.scene.control.*; +import javafx.beans.property.*; +import javafx.scene.input.*; +import javafx.scene.layout.*; + +import com.quollwriter.*; +import com.quollwriter.uistrings.*; +import com.quollwriter.ui.fx.components.*; +import com.quollwriter.ui.fx.viewers.*; +import com.quollwriter.ui.fx.panels.*; +import com.quollwriter.text.*; + +public abstract class LanguageStringsIdBox extends VBox implements org.fxmisc.flowless.Cell> +{ + + protected LanguageStringsIdsPanel panel = null; + protected E baseValue = null; + protected E stringsValue = null; + private Id id = null; + private Form form = null; + + public LanguageStringsIdBox (final E baseValue, + final E stringsValue, + final LanguageStringsIdsPanel panel) + { + + final LanguageStringsIdBox _this = this; + + this.panel = panel; + this.baseValue = baseValue; + this.stringsValue = stringsValue; + + this.id = new Id (0, + BaseStrings.toId (this.baseValue.getId ()), + false); + + } + + public E getBaseValue () + { + + return this.baseValue; + + } + + @Override + public boolean isReusable () + { + + return false; + + } + + @Override + public void updateItem (Value v) + { + + + + } + + @Override + public LanguageStringsIdBox getNode () + { + + //this.init (); + + return this; + + } + + public void init () + { + + final String fid = BaseStrings.toId (this.baseValue.getId ()); + + final LanguageStringsIdBox _this = this; + + Set items = new LinkedHashSet<> (); + items.add (QuollMenuItem.builder () + .label (new SimpleStringProperty ("Find all references")) + .iconName (StyleClassNames.FIND) + .onAction (ev -> + { + + _this.panel.getEditor ().showFind (BaseStrings.toId (_this.baseValue.getId ())); + + }) + .build ()); + + items.add (QuollMenuItem.builder () + .label (new SimpleStringProperty ("Report error about this Id")) + .iconName (StyleClassNames.BUG) + .onAction (ev -> + { + + this.getEditor ().showReportProblemForId (BaseStrings.toId (this.baseValue.getId ())); + + }) + .build ()); + + items.add (QuollMenuItem.builder () + .label (new SimpleStringProperty ("Copy Id")) + .iconName (StyleClassNames.COPY) + .onAction (ev -> + { + + final Clipboard clipboard = Clipboard.getSystemClipboard(); + final ClipboardContent content = new ClipboardContent(); + content.putString (BaseStrings.ID_REF_START + BaseStrings.toId (this.baseValue.getId ()) + BaseStrings.ID_REF_END); + clipboard.setContent (content); + + }) + .build ()); + + Header h = Header.builder () + .title (new SimpleStringProperty (BaseStrings.toId (this.baseValue.getId ()))) + .contextMenu (items) + .build (); + + this.getStyleClass ().add (this.getStyleClassName ()); + + this.getChildren ().add (h); + + String comment = this.baseValue.getComment (); + + String scount = ""; + + int sc = this.getSCount (); + + if (sc > 0) + { + + StringBuilder c = new StringBuilder (); + + for (int i = 0; i < sc; i++) + { + + if (c.length () > 0) + { + + c.append (", "); + + } + + c.append ("%" + (i + 1) + "$s"); + + } + + } + + if (comment == null) + { + + comment = ""; + + } + + if (scount.length () > 0) + { + + scount = String.format ("Requires values: %1$s to be present in your value.", + scount); + + if (comment.length () > 0) + { + + comment += "\n"; + + } + + comment += scount; + + } + + Form.Builder fb = Form.builder () + .description (new SimpleStringProperty (comment)); + + for (Form.Item i : this.getFormItems ()) + { + + fb.item (i); + + } + + this.form = fb.build (); + + this.getChildren ().add (this.form); + + this.showErrors (false); + + } + + private int getSCount () + { + + if (this.baseValue instanceof TextValue) + { + + return ((TextValue) this.baseValue).getSCount (); + + } + + return -1; + + } + + public void updatePreviews () + { + + this.panel.getEditor ().updatePreviews (); + + } + + public void updateSideBar (Node n) + { + + this.panel.getEditor ().updateSideBar (this.panel.getParentNode ()); + + } + + public AbstractLanguageStringsEditor getEditor () + { + + return this.panel.getEditor (); + + } + + public abstract String getStyleClassName (); + + public abstract T getUserValue (); + + public abstract Set getFormItems (); + + public abstract void saveValue () + throws GeneralException; + +/* + public void saveValue () + throws GeneralException + { + + String uv = this.getUserValue (); + + if (uv != null) + { + + if (this.stringsValue != null) + { + + this.stringsValue.setRawText (uv); + + } else { + + this.stringsValue = this.editor.userStrings.insertTextValue (this.baseValue.getId ()); + + //this.stringsValue.setSCount (this.baseValue.getSCount ()); + this.stringsValue.setRawText (uv); + + } + + } else { + + this.editor.userStrings.removeNode (this.baseValue.getId ()); + + } + + } +*/ +/* + public Id getIdAtOffset (int offset) + { + + return BaseStrings.getId (this.userValue.getEditor ().getText (), + offset); + + } +*/ +/* + public Id getIdAtCaret () + { + + return this.getIdAtOffset (this.userValue.getEditor ().getCaretPosition ()); + + } +*/ + public Id getForId () + { + + return this.id; + + } + + public boolean hasUserValue () + { + + return this.getUserValue () != null; + + } + +/* + public String getUserValue () + { + + StringWithMarkup sm = this.userValue.getTextWithMarkup (); + + if (sm != null) + { + + if (!sm.hasText ()) + { + + return null; + + } + + return sm.getMarkedUpText (); + + } + + return null; + + } +*/ +/* + public void useEnglishValue () + { + + this.userValue.updateText (this.baseValue.getRawText ()); + this.showPreview (); + this.validate (); + this.repaint (); + + } +*/ + + public abstract boolean hasErrors (); + + public abstract boolean showErrors (boolean requireUserValue); + + public boolean showErrors (Set errs) + { + + if ((errs == null) + || + (errs.size () == 0) + ) + { + + this.form.hideError (); + + return false; + + } + + this.form.showErrors (new LinkedHashSet<> (errs.stream () + .map (e -> new SimpleStringProperty (e)) + .collect (Collectors.toList ()))); + + this.updateSideBar (this.baseValue); + + return true; + + } + + public abstract void showPreview (); + /* + public void showPreview () + { + + if (this.showErrors (false)) + { + + return; + + } + + String s = this.getUserValue (); + + if (s == null) + { + + if (this.preview != null) + { + + this.preview.setText (""); + + } + + this.previewWrapper.setVisible (false); + this.previewLabel.setVisible (false); + + this.editor.updateSideBar (this.baseValue); + + return; + + } + + if (this.preview == null) + { + + this.preview = UIUtils.createHelpTextPane ("", + this.editor); + this.preview.setBorder (UIUtils.createPadding (6, 0, 0, 0)); + this.preview.setFocusable (false); + + this.previewWrapper.add (this.preview); + + } + + String t = this.editor.getPreviewText (s); + + this.previewLabel.setVisible (true); + this.preview.setText (t); + this.previewWrapper.setVisible (true); + + this.editor.updateSideBar (this.baseValue); + + this.validate (); + this.repaint (); + + } +*/ +/* + private void fillMatch () + { + + QTextEditor editor = this.userValue.getEditor (); + + int c = editor.getCaretPosition (); + + Id id = BaseStrings.getId (editor.getText (), + c); + + if (id == null) + { + + return; + + } + + String m = this.selections.getSelectedValue (); + + //m = id.getNewFullId (m); + + Id.Part part = id.getPart (c); + + if (part != null) + { + + editor.replaceText (part.start, part.end, m); + editor.setCaretPosition (part.start + m.length ()); + + } else { + + // Is the previous character a . if so append. + if ((editor.getText ().substring (c - 1, c).equals (".")) + || + (c == id.getEnd ()) + ) + { + + editor.replaceText (c, c, m); + editor.setCaretPosition (c + m.length ()); + + } else { + + part = id.getLastPart (); + + editor.replaceText (part.start, part.start + part.end, m); + editor.setCaretPosition (part.start + m.length ()); + + } + + } + + c = editor.getCaretPosition (); + + id = this.getIdAtCaret (); + + // We may be inserting into the middle of an id, check to see if it's valid. + + // Check to see if the id maps to a string. + if (this.editor.baseStrings.getString (id.getId ()) != null) + { + + if (id.isPartial ()) + { + + editor.replaceText (id.getEnd (), id.getEnd (), "}"); + editor.setCaretPosition (c + 1); + + } + + this.hideSelector (); + + return; + + } + + // Check to see if there are more matches further down the tree. + String nid = id.getId () + "."; + + Set matches = this.editor.baseStrings.getIdMatches (nid); + + if (matches.size () > 0) + { + + c = editor.getCaretPosition (); + + editor.replaceText (c, c, "."); + editor.setCaretPosition (c + 1); + + try + { + + this.showSelectionPopup (matches, + editor.modelToView (id.getPart (c).start).getLocation ()); + + } catch (Exception e) { + + e.printStackTrace (); + + } + + return; + + } else { + + c = editor.getCaretPosition (); + + editor.replaceText (c, c, "}"); + editor.setCaretPosition (c + 1); + + this.hideSelector (); + + return; + + } + + } +*/ +/* + private String updateSelectedMatch (int incr) + { + + int i = this.selections.getSelectedIndex (); + + i += incr; + + int s = this.selections.getModel ().getSize (); + + if (i < 0) + { + + i = s + i; + + } + + if (i > s - 1) + { + + i -= s; + + } + + this.selections.setSelectedIndex (i); + + return this.selections.getSelectedValue (); + + } +*/ +/* + public boolean isSelectorVisible () + { + + if (this.selector != null) + { + + return this.selector.isVisible (); + + } + + return false; + + } +*/ +/* + public void hideSelector () + { + + if (this.selector != null) + { + + this.selector.setVisible (false); + + } + + this.userValue.getEditor ().setFocusTraversalKeysEnabled (true); + + } +*/ +/* + public void showSelectionPopup (Set matches, + Point point) + { + + if (this.selector == null) + { + + this.selector = new Box (BoxLayout.Y_AXIS); + + this.selector.setOpaque (true); + this.selector.setBackground (UIUtils.getComponentColor ()); + this.selector.setBorder (UIUtils.createLineBorder ()); + + } + + if ((matches == null) + || + (matches.size () == 0) + ) + { + + this.hideSelector (); + + return; + + } + + this.userValue.getEditor ().setFocusTraversalKeysEnabled (false); + + this.selector.removeAll (); + + DefaultListModel m = new DefaultListModel<> (); + + for (String o : matches) + { + + m.addElement (o); + + } + + this.selections = new JList (); + final JList l = this.selections; + l.setModel (m); + l.setLayoutOrientation (JList.VERTICAL); + l.setVisibleRowCount (0); + l.setOpaque (true); + l.setBackground (UIUtils.getComponentColor ()); + l.setMaximumSize (new Dimension (Short.MAX_VALUE, + Short.MAX_VALUE)); + UIUtils.setAsButton (l); + + l.setCellRenderer (new DefaultListCellRenderer () + { + + public Component getListCellRendererComponent (JList list, + Object value, + int index, + boolean isSelected, + boolean cellHasFocus) + { + + String obj = (String) value; + + JLabel l = (JLabel) super.getListCellRendererComponent (list, + value, + index, + isSelected, + cellHasFocus); + + l.setText (obj);//.getName ()); + + l.setFont (l.getFont ().deriveFont (UIUtils.getScaledFontSize (10)).deriveFont (Font.PLAIN)); + l.setBorder (UIUtils.createBottomLineWithPadding (5, 5, 5, 5)); + l.setPreferredSize (new Dimension (l.getPreferredSize ().width, 29)); + + return l; + + } + + }); + + l.setSelectedIndex (0); + + int rowHeight = 30; + + l.setAlignmentX (JComponent.LEFT_ALIGNMENT); + + JScrollPane sp = new JScrollPane (l); + + sp.setHorizontalScrollBarPolicy (ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); + sp.getVerticalScrollBar ().setUnitIncrement (rowHeight); + sp.setAlignmentX (JComponent.LEFT_ALIGNMENT); + sp.setOpaque (false); + sp.setBorder (null); + + this.selector.add (sp); + + l.addListSelectionListener (new ListSelectionListener () + { + + @Override + public void valueChanged (ListSelectionEvent ev) + { + + } + + }); + + this.selector.setPreferredSize (new Dimension (300, + rowHeight * (matches.size () > 10 ? 10 : matches.size ()))); + + this.editor.showPopupAt (this.selector, + SwingUtilities.convertPoint (this.userValue, + point, + this.editor), + false); + + } +*/ +/* + public class Id + { + + private int _start = -1; + private String fullId = null; + private boolean hasClosingBrace = false; + private java.util.List parts = new ArrayList<> (); + public boolean hasErrors = false; + + public Id (String text, + int offset) + { + + if (text.length () < 3) + { + + return; + + } + + String idstart = LanguageStrings.ID_REF_START; + + int ind = text.lastIndexOf (idstart, offset); + + if (ind > -1) + { + + ind += idstart.length (); + this._start = ind; + + int idendind = text.indexOf (LanguageStrings.ID_REF_END, ind); + + if (idendind > -1) + { + + if (idendind < offset) + { + + return; + + } + + // We have an end, see if it's on the same line. + int leind = text.indexOf ("\n", ind); + + if (leind < 0) + { + + leind = text.length (); + + } + + if (idendind < leind) + { + + this.hasClosingBrace = true; + this.fullId = text.substring (ind, leind - 1); + + } + + } else { +System.out.println ("ELSE"); + StringBuilder b = new StringBuilder (); + + for (int i = ind; i < text.length (); i++) + { + + char c = text.charAt (i); + + if (Character.isWhitespace (c)) + { + + break; + + } + + b.append (c); + + } + + this.fullId = b.toString (); + + } +System.out.println ("ID: " + this.fullId); + if (this.fullId.equals ("")) + { + + this.fullId = null; + + } + + int start = ind; + + java.util.List parts = Utils.splitString (this.fullId, + "."); + + int cind = start; + + Part prevp = null; + + for (int i = 0; i < parts.size (); i++) + { + + if (i > 0) + { + + cind++; + + } + + String ps = parts.get (i); + + if (ps.trim ().length () != ps.length ()) + { + + this.hasErrors = true; + + } + + Part p = new Part (this, + cind, + ps, + prevp); + + prevp = p; + cind += ps.length (); + + this.parts.add (p); + + } + + } + + } + + public int getEnd () + { + + if (this.parts.size () == 0) + { + + return this._start; + + } + + return this.parts.get (this.parts.size () - 1).end; + + } + + public Part getPart (int offset) + { + + for (int i = 0; i < this.parts.size (); i++) + { + + Part p = this.parts.get (i); + + if ((offset >= p.start) + && + (offset <= p.end) + ) + { + + return p; + + } + + } + + return null; + + } + + public String getFullId () + { + + return this.fullId; + + } + + public boolean isIdValid (LanguageStrings baseStrings) + { + + if (this.fullId == null) + { + + return false; + + } + + return baseStrings.isIdValid (this.fullId); + + } + + public boolean hasErrors () + { + + return this.hasErrors; + + } + + public String getNewFullId (String suffix) + { + + if (this.fullId.endsWith (".")) + { + + return this.fullId + suffix; + + } + + String pref = this.getIdPrefix (); + + if (pref == null) + { + + return suffix; + + } + + return pref + "." + suffix; + + } + + public String getIdPrefix () + { + + StringBuilder b = new StringBuilder (); + + for (int i = 0; i < this.parts.size () - 1; i++) + { + + if (i > 0) + { + + b.append ("."); + + } + + b.append (this.parts.get (i).part); + + } + + if (b.length () == 0) + { + + return null; + + } + + return b.toString (); + + } + + public Part getLastPart () + { + + if (this.parts.size () == 0) + { + + return null; + + } + + return this.parts.get (this.parts.size () - 1); + + } + + public Set getPartMatches (int offset, + LanguageStrings baseStrings) + { + + Part p = this.getPart (offset); + + if (p != null) + { + + return baseStrings.getIdMatches (p.getFullId ()); + + } + + return this.getMatches (baseStrings); + + } + + public Set getMatches (LanguageStrings baseStrings) + { + + return baseStrings.getIdMatches (this.fullId); + + } + + public class Part + { + + public int start = -1; + public int end = -1; + public String part = null; + public Id parent = null; + public Part previous = null; + + public Part (Id parent, + int start, + String part, + Part prev) + { + + this.start = start; + this.end = this.start + part.length (); + this.parent = parent; + this.part = part; + this.previous = prev; + + } + + public String getFullId () + { + + StringBuilder b = new StringBuilder (this.part); + + Part prev = this.previous; + + while (prev != null) + { + + b.insert (0, prev.part + "."); + prev = prev.previous; + + } + + return b.toString (); + + } + + } + + } +*/ + +} diff --git a/src/main/java/com/quollwriter/ui/fx/LanguageStringsImageIdBox.java b/src/main/java/com/quollwriter/ui/fx/LanguageStringsImageIdBox.java new file mode 100644 index 00000000..9b06406d --- /dev/null +++ b/src/main/java/com/quollwriter/ui/fx/LanguageStringsImageIdBox.java @@ -0,0 +1,196 @@ +package com.quollwriter.ui.fx; + +import java.util.concurrent.*; +import java.awt.event.*; + +import java.io.*; +import java.util.*; +import java.nio.file.*; + +import javafx.beans.property.*; + +import com.quollwriter.*; +import com.quollwriter.uistrings.*; +import com.quollwriter.ui.fx.components.*; +import com.quollwriter.ui.fx.panels.*; +import com.quollwriter.text.*; + +public class LanguageStringsImageIdBox extends LanguageStringsIdBox +{ + + //private AbstractLanguageStringsEditor editor = null; + private ImageSelector userValue = null; + //private ImageValue baseValue = null; + //private ImageValue stringsValue = null; + + //private JTextPane errors = null; + //private Box errorsWrapper = null; + //private JLabel errorsLabel = null; + + public LanguageStringsImageIdBox (final ImageValue baseValue, + final ImageValue stringsValue, + final LanguageStringsIdsPanel panel) + { + + super (baseValue, + stringsValue, + panel); + + } + + @Override + public String getStyleClassName () + { + + return StyleClassNames.IMAGE; + + } + + public Set getFormItems () + { + + Set items = new LinkedHashSet<> (); + + items.add (new Form.Item (QuollHyperlink.builder () + .label ("View English Image Online") + .onAction (ev -> + { + + UIUtils.openURL (this.panel.getEditor (), + Environment.getQuollWriterWebsite () + this.baseValue.getUrl ()); + + }) + .build ())); + + this.userValue = ImageSelector.builder () + .withViewer (this.panel.getEditor ()) + .file ((this.stringsValue != null ? this.stringsValue.getImageFile () : null)) + .build (); + this.userValue.imagePathProperty ().addListener ((pr, oldv, newv) -> + { + + this.updateSideBar (this.baseValue); + + }); + + items.add (new Form.Item (new SimpleStringProperty ("Your Image"), + this.userValue)); + + return items; + + } + + public void saveValue () + throws GeneralException + { + + Path uv = this.getUserValue (); + + if (uv != null) + { + + if (this.stringsValue == null) + { + + this.stringsValue = this.getEditor ().getUserStrings ().insertImageValue (this.baseValue.getId ()); + + } + + this.stringsValue.setImageFile (uv); + + } else { + + this.getEditor ().getUserStrings ().removeNode (this.baseValue.getId ()); + + } + + } + + @Override + public Path getUserValue () + { + + return this.userValue.getImagePath (); + + } + + @Override + public boolean hasErrors () + { + + Path s = this.getUserValue (); + + if (s == null) + { + + return false; + + } + + return false; + + + } + + public boolean showErrors (boolean requireUserValue) + { + + Path s = this.getUserValue (); + + if ((s == null) + && + (!requireUserValue) + ) + { + + return false; + + } + + Set errs = null; + + if (s == null) + { + + errs = new LinkedHashSet<> (); + + errs.add ("Cannot show a preview, no value provided."); + + } else { + + } + + Node root = this.baseValue.getRoot (); + + this.updateSideBar (this.baseValue); + + return false; + + } + + public void showPreview () + { + + if (this.showErrors (false)) + { + + return; + + } + + Path s = this.getUserValue (); + + if (s == null) + { + + this.updateSideBar (this.baseValue); + + return; + + } + + this.updateSideBar (this.baseValue); + + } + +} diff --git a/src/main/java/com/quollwriter/ui/fx/LanguageStringsResultsBox.java b/src/main/java/com/quollwriter/ui/fx/LanguageStringsResultsBox.java new file mode 100644 index 00000000..4a78e159 --- /dev/null +++ b/src/main/java/com/quollwriter/ui/fx/LanguageStringsResultsBox.java @@ -0,0 +1,172 @@ +package com.quollwriter.ui.fx; + +import java.util.*; +import java.util.function.*; + +import javafx.beans.property.*; +import javafx.scene.control.*; + +import com.quollwriter.*; +import com.quollwriter.uistrings.*; +import com.quollwriter.ui.fx.viewers.*; +import com.quollwriter.ui.fx.components.*; + +public class LanguageStringsResultsBox extends FindResultsBox +{ + + private QuollTreeView tree = null; + private Map>> matches = new HashMap<> (); + + public LanguageStringsResultsBox (AbstractLanguageStringsEditor viewer, + Map>> matches) + { + + super (viewer, + null); + + this.matches = matches; + + } + + @Override + public void dispose () + { + + } + + public QuollTreeView getTree () + { + + if (this.tree == null) + { + + this.tree = this.createTree (); + + } + + return this.tree; + + } + + @Override + public javafx.scene.Node getContent () + { + + if (this.tree == null) + { + + this.tree = this.getTree (); + + } + + return this.tree; + + } + + private QuollTreeView createTree () + { + + TreeItem root = new TreeItem<> (); + root.setValue (new Node ("root", null)); + + Function, javafx.scene.Node> cellProvider = (treeItem) -> + { + + Node n = treeItem.getValue (); + + boolean parent = treeItem.getParent () == root; + + int c = treeItem.getChildren ().size (); + + String title = (n.getTitle () != null ? n.getTitle () : BaseStrings.toId (n.getId ())); + + if (parent) + { + + String name = String.format ("%s (%s)", + title, + Environment.formatNumber (c)); + + QuollLabel l = QuollLabel.builder () + .label (new SimpleStringProperty (name)) + .styleClassName (this.viewer.getBaseStrings ().getSection (n.getSection ()).icon) + .build (); + + l.getStyleClass ().add ("section"); + + l.setOnMousePressed (ev -> + { + + this.viewer.showIds (new Id (BaseStrings.toId (n.getId ()))); + + }); + + return l; + + } else { + + String name = String.format ("%s", + title, + Environment.formatNumber (c)); + + QuollLabel l = QuollLabel.builder () + .label (new SimpleStringProperty (name)) + .build (); + + l.setOnMousePressed (ev -> + { + + this.viewer.showId (new Id (BaseStrings.toId (n.getId ()))); + + }); + + return l; + + } + + }; + + // Create the model. + + for (Section s : this.matches.keySet ()) + { + + Map> items = this.matches.get (s); + + for (Node n : items.keySet ()) + { + + TreeItem ci = new TreeItem<> (); + ci.setValue (n); + root.getChildren ().add (ci); + + List vals = items.get (n); + + for (Value v : vals) + { + + TreeItem ii = new TreeItem<> (); + ii.setValue (v); + ci.getChildren ().add (ii); + + } + + } + + } + + QuollTreeView tree = new QuollTreeView<> (); + tree.setShowRoot (false); + tree.getStyleClass ().add (StyleClassNames.LANGUAGESTRINGS); + tree.setCellProvider (cellProvider); + tree.setRoot (root); + + UIUtils.addStyleSheet (tree, + Constants.COMPONENT_STYLESHEET_TYPE, + "languagestringsresultsbox"); + + return tree; + + } + +} diff --git a/src/main/java/com/quollwriter/ui/fx/LanguageStringsTextIdBox.java b/src/main/java/com/quollwriter/ui/fx/LanguageStringsTextIdBox.java new file mode 100644 index 00000000..2572d4ac --- /dev/null +++ b/src/main/java/com/quollwriter/ui/fx/LanguageStringsTextIdBox.java @@ -0,0 +1,1204 @@ +package com.quollwriter.ui.fx; + +import java.util.concurrent.*; + +import java.util.*; + +import org.reactfx.*; +import org.reactfx.util.*; +import org.fxmisc.wellbehaved.event.*; + +import javafx.collections.*; +import javafx.geometry.*; +import javafx.beans.property.*; +import javafx.scene.layout.*; +import javafx.scene.input.*; +import javafx.scene.control.*; + +import com.quollwriter.*; +import com.quollwriter.uistrings.*; +import com.quollwriter.ui.fx.components.*; +import com.quollwriter.ui.fx.panels.*; +import com.quollwriter.ui.fx.popups.*; +import com.quollwriter.text.*; +import com.quollwriter.ui.events.*; + +public class LanguageStringsTextIdBox extends LanguageStringsIdBox +{ + + private String popupId = null; + + private QuollTextArea userValue = null; + //privte TextArea userValue = null; + + private QuollTextView preview = null; + private VBox previewWrapper = null; + + private DictionaryProvider2 dictProv = null; + + private ScheduledFuture errorCheck = null; + + private ObservableList matches = null; + + private ShowObjectSelectPopup matchesView = null; + + public LanguageStringsTextIdBox (final TextValue baseValue, + final TextValue stringsValue, + final LanguageStringsIdsPanel panel) + { + + super (baseValue, + stringsValue, + panel); + + this.matches = FXCollections.observableList (new ArrayList<> ()); + + this.popupId = BaseStrings.toId (this.baseValue.getId ()) + "stringsmatch"; + + LanguageStringsTextIdBox _this = this; + try + { + + this.dictProv = new DictionaryProvider2 () + { + + @Override + public void addDictionaryChangedListener (DictionaryChangedListener l) + { + + } + + @Override + public void removeDictionaryChangedListener (DictionaryChangedListener l) + { + + } + + @Override + public void removeWord (String word) + { + + } + + @Override + public void addWord (String word) + { + + } + + @Override + public com.quollwriter.ui.fx.SpellChecker getSpellChecker () + { + + return new com.quollwriter.ui.fx.SpellChecker () + { + + @Override + public boolean isCorrect (Word word) + { +//if(true){return true;} + if (_this.panel.getEditor ().getBaseStrings ().isIdValid (word.getText ())) + { + + return true; + + } + + com.quollwriter.ui.fx.SpellChecker sp = _this.panel.getEditor ().getSpellChecker (); + + if (sp != null) + { + + return sp.isCorrect (word); + + } else { + + return true; + + } + + } + + @Override + public boolean isIgnored (Word word) + { + + return false; + + } + + @Override + public java.util.List getSuggestions (Word word) + { + + com.quollwriter.ui.fx.SpellChecker sp = _this.panel.getEditor ().getSpellChecker (); + + if (sp != null) + { + + return sp.getSuggestions (word); + + } else { + + return null; + + } + + } + + }; + + } + + }; + + } catch (Exception e) { + + Environment.logError ("Unable to create user dictionary", + e); + + } + + } + + @Override + public void requestFocus () + { + + this.userValue.requestFocus (); + + } + + @Override + public String getStyleClassName () + { + + return StyleClassNames.STRING; + + } + + @Override + public Set getFormItems () + { + + LanguageStringsTextIdBox _this = this; + + Set items = new LinkedHashSet<> (); + + items.add (new Form.Item (new SimpleStringProperty ("English"), + QuollTextView.builder () + .text (this.baseValue.getRawText ()) + .formatter (s -> + { + + s = Utils.replaceString (s, + "<", + "<"); + return s; + + }) + .build ())); + + this.previewWrapper = new VBox (); + previewWrapper.getStyleClass ().add (StyleClassNames.PREVIEW); + previewWrapper.managedProperty ().bind (previewWrapper.visibleProperty ()); + previewWrapper.setVisible (false); + + this.preview = QuollTextView.builder () + .inViewer (this.panel.getEditor ()) + .build (); + this.preview.setFocusTraversable (false); + + this.previewWrapper.getChildren ().add (QuollLabel.builder () + .label (new SimpleStringProperty ("Preview")) + .build ()); + this.previewWrapper.getChildren ().add (this.preview); + this.userValue = QuollTextArea.builder () + .text ((this.stringsValue != null ? this.stringsValue.getRawText () : null)) + .contextMenu (() -> + { + + Set its = new LinkedHashSet<> (); + + final Id id = this.getIdAtOffset (this.userValue.getTextEditor ().getTextPositionForCurrentMousePosition ()); + + if (id != null) + { + + its.add (QuollMenuItem.builder () + .iconName (StyleClassNames.VIEW) + .label (new SimpleStringProperty ("Go to Id definition")) + .onAction (ev -> + { + + this.getEditor ().showId (id); + + }) + .build ()); + + } + + its.add (QuollMenuItem.builder () + .iconName (StyleClassNames.COPY) + .label (new SimpleStringProperty ("Use the English value")) + .onAction (ev -> + { + + this.useEnglishValue (); + + }) + .build ()); + + return its; + + }) + .dictionaryProvider (this.dictProv) + .spellCheckEnabled (true) + .formattingEnabled (false) + .autoGrabFocus (false) + .withViewer (this.panel.getEditor ()) + .build (); + + // TODO Mouse motion - _this.userValue.setToolTipText (_this.getEditor ().getString (id.getId ())); + + // TODO _this.updatePreviews (); + //_this.showPreview (); + +/* +TODO ? + final Action defSelect = this.userValue.getEditor ().getActionMap ().get (DefaultEditorKit.selectWordAction); + + this.userValue.getEditor ().getActionMap ().put (DefaultEditorKit.selectWordAction, + new TextAction (DefaultEditorKit.selectWordAction) + { + + @Override + public void actionPerformed (ActionEvent ev) + { + + int c = _this.userValue.getEditor ().getCaretPosition (); + + Id id = _this.getIdAtCaret (); + + if (id != null) + { + + _this.userValue.getEditor ().setSelectionStart (id.getPart (c).start); + _this.userValue.getEditor ().setSelectionEnd (id.getPart (c).end); + + } else { + + defSelect.actionPerformed (ev); + + } + + } + + }); +*/ + + this.userValue.getTextEditor ().caretPositionProperty ().addListener ((pr, oldv, newv) -> + { + + if ((newv > 0) + && + (this.userValue.getTextEditor ().isFocused ()) + ) + { + + this.showMatches (false); + + } + + }); + + Nodes.addInputMap (this.userValue.getTextEditor (), + InputMap.process (EventPattern.keyPressed (KeyCode.P, KeyCombination.SHORTCUT_DOWN), + ev -> + { + + this.showPreview (); + + return InputHandler.Result.CONSUME; + + })); + + Nodes.addInputMap (this.userValue.getTextEditor (), + InputMap.process (EventPattern.keyPressed (), + ev -> + { + + if ((ev.getCode () == KeyCode.DELETE) + || + (ev.getCode () == KeyCode.BACK_SPACE) + ) + { + + UIUtils.forceRunLater (() -> + { + + this.showMatches (false); + + }); + + return InputHandler.Result.PROCEED; + + } + + if ((ev.getCode () == KeyCode.CLOSE_BRACKET) + && + (ev.isShiftDown ()) + ) + { + + this.hideSelector (); + + return InputHandler.Result.CONSUME; + + } + + if (ev.getCode () == KeyCode.ENTER) + { + + if (this.isSelectorVisible ()) + { + + ev.consume (); + + this.matchesView.getSelectionModel ().select (this.matchesView.getFocusModel ().getFocusedIndex ()); + + //this.fillMatch (); + + return InputHandler.Result.CONSUME; + + } + + } + + if (ev.getCode () == KeyCode.UP) + { + + if (this.isSelectorVisible ()) + { + + ev.consume (); + + this.updateSelectedMatch (-1); + + return InputHandler.Result.CONSUME; + + } + + } + + if (ev.getCode () == KeyCode.DOWN) + { + + if (this.isSelectorVisible ()) + { + + ev.consume (); + + this.updateSelectedMatch (1); + + return InputHandler.Result.CONSUME; + + } + + } + + if (ev.getCode () == KeyCode.ESCAPE) + { + + ev.consume (); + + this.hideSelector (); + + return InputHandler.Result.CONSUME; + + } + + if ((ev.getCode () == KeyCode.ENTER) + || + (ev.getCode () == KeyCode.UP) + || + (ev.getCode () == KeyCode.DOWN) + ) + { + + if (this.isSelectorVisible ()) + { + + ev.consume (); + + return InputHandler.Result.CONSUME; + + } + + } + + if (ev.getCode () == KeyCode.TAB) + { + + if (this.isSelectorVisible ()) + { + + this.matchesView.getSelectionModel ().select (this.matchesView.getFocusModel ().getFocusedIndex ()); + + return InputHandler.Result.CONSUME; + + //this.fillMatch (); + + } else { + + if (this.showMatches (false)) + { + + return InputHandler.Result.CONSUME; + + } + + } + + if (ev.isShiftDown ()) + { + + panel.moveToPreviousBox (this.baseValue); + + } else { + + panel.moveToNextBox (this.baseValue); + + } + + return InputHandler.Result.CONSUME; + + } + + UIUtils.forceRunLater (() -> + { + + this.showMatches (false); + + }); + + return InputHandler.Result.PROCEED; + + })); + + items.add (new Form.Item (new SimpleStringProperty ("Your Value"), + this.userValue)); + + items.add (new Form.Item (this.previewWrapper)); + + this.userValue.getTextEditor ().focusedProperty ().addListener ((pr, oldv, newv) -> + { + + this.hideSelector (); + + if (!newv) + { + + if (this.isSelectorVisible ()) + { + + return; + + } + + UIUtils.runLater (() -> + { + + if (this.showErrors (false)) + { + + return; + + } + + this.showPreview (); + + this.updateSideBar (this.baseValue); + + }); + + } + + }); + + this.userValue.getTextEditor ().plainTextChanges ().subscribe (ev -> + { + + this.showPreview (); +/* + if (this.errorCheck != null) + { + + this.errorCheck.cancel (true); + + } + + this.errorCheck = this.panel.getEditor ().schedule (() -> + { + + UIUtils.runLater (() -> + { + + this.showErrors (false); + + }); + + }, + 750, + -1); +*/ + }); + + UIUtils.forceRunLater (() -> + { + + this.showPreview (); + + }); + + return items; + + } + + private boolean showMatches (boolean fillOnSingleMatch) + { + + int c = this.userValue.getTextEditor ().getCaretPosition (); + + String t = this.userValue.getTextEditor ().getText (); + Id id = BaseStrings.getId (t, c); + + if (id == null) + { + + this.hideSelector (); + return false; + + } + + Set matches = id.getPartMatches (c, + this.panel.getEditor ().getBaseStrings ().getStrings ()); + + if ((matches == null) + || + (matches.size () == 0) + ) + { + + this.hideSelector (); + + } + + if (matches.size () == 1) + { + + Id.Part p = id.getPart (c); + + if (p == null) + { + + p = id.getLastPart (); + + } + + if (p.part.equals (matches.iterator ().next ())) + { + + if (fillOnSingleMatch) + { + + this.fillMatch (); + + this.hideSelector (); + return true; + + } + + } + + } + + try + { + + int ind = c; + + Id.Part pa = id.getPart (c); + + if (pa != null) + { + + ind = pa.start; + + } + + Bounds b = this.userValue.getTextEditor ().getBoundsForPosition (ind); + + if (b == null) + { + + return false; + + } + + b = this.userValue.getTextEditor ().screenToLocal (b); + //b = this.userValue.getTextEditor ().localToScene (b); + + this.showSelectionPopup (matches, + b.getMinX (), + b.getMaxY () - this.userValue.getTextEditor ().getLayoutBounds ().getHeight ()); + + return true; + + } catch (Exception e) { + + Environment.logError ("Unable to show selection popup", + e); + + return false; + + } + + } + + @Override + public void showPreview () + { + + String s = this.getUserValue (); + + if (s == null) + { + + this.previewWrapper.setVisible (false); + + return; + + } + + this.previewWrapper.setVisible (true); + + String t = this.getEditor ().getPreviewText (s); + + t = Utils.replaceString (t, + "[", + "["); + + t = Utils.replaceString (t, + "]", + "]"); + + this.preview.setText (new SimpleStringProperty (t)); + + } + + public void saveValue () + throws GeneralException + { + + String uv = this.getUserValue (); + + if (uv != null) + { + + if (this.stringsValue != null) + { + + this.stringsValue.setRawText (uv); + + } else { + + this.stringsValue = this.getEditor ().getUserStrings ().insertTextValue (this.baseValue.getId ()); + + //this.stringsValue.setSCount (this.baseValue.getSCount ()); + this.stringsValue.setRawText (uv); + + } + + } else { + + this.getEditor ().getUserStrings ().removeNode (this.baseValue.getId ()); + + } + + } + + public Id getIdAtPoint (Point2D p) + { + + try + { + + return BaseStrings.getId (this.userValue.getTextEditor ().getText (), + this.userValue.getTextEditor ().getTextPositionForMousePosition (p.getX (), + p.getY ())); + + } catch (Exception e) { + + // Can ignore. + + } + + return null; + + } + + public Id getIdAtOffset (int offset) + { + + return BaseStrings.getId (this.userValue.getTextEditor ().getText (), + offset); + + } + + public Id getIdAtCaret () + { + + return this.getIdAtOffset (this.userValue.getTextEditor ().getCaretPosition ()); + + } + + @Override + public String getUserValue () + { + + if (this.userValue.getTextEditor ().isReadyForUse ()) + { + + StringWithMarkup sm = this.userValue.getTextEditor ().getTextWithMarkup (); + + if (sm != null) + { + + if (!sm.hasText ()) + { + + return null; + + } + + return sm.getMarkedUpText (); + + } + + } else { + + if (this.stringsValue != null) + { + + return this.stringsValue.getRawText (); + + } + + } + + return null; + + } + + public void useEnglishValue () + { + + this.userValue.getTextEditor ().setText (new StringWithMarkup (this.baseValue.getRawText ())); + + } + + public int getErrorCount () + { + + String s = this.getUserValue (); + + if (s == null) + { + + return 0; + + } + + return BaseStrings.getErrors (s, + BaseStrings.toId (this.baseValue.getId ()), + this.baseValue.getSCount (), + this.getEditor ()).size (); + + } + + public boolean hasErrors () + { + + return this.getErrorCount () > 0; + + + } + + public boolean showErrors (boolean requireUserValue) + { + + String s = this.getUserValue (); + + if ((s == null) + && + (!requireUserValue) + ) + { + + return false; + + } + + Set errs = null; + + if (s == null) + { + + errs = new LinkedHashSet<> (); + + errs.add ("Cannot show a preview, no value provided."); + + } else { + + errs = BaseStrings.getErrors (s, + BaseStrings.toId (this.baseValue.getId ()), + this.baseValue.getSCount (), + this.getEditor ()); + + } + + return this.showErrors (errs); + + } + + private void fillMatch () + { + + String m = this.matchesView.getFocusModel ().getFocusedItem (); + + if (m == null) + { + + m = this.matches.get (0); + + } + + this.fillMatch (m); + + } + + private void fillMatch (String m) + { + + TextEditor editor = this.userValue.getTextEditor (); + + int c = editor.getCaretPosition (); + + Id id = BaseStrings.getId (editor.getText (), + c); + + if (id == null) + { + + return; + + } + + Id.Part part = id.getPart (c); + + if (part != null) + { + + editor.replaceText (part.start, part.end, m); + editor.setCaretPosition (part.start + m.length ()); + + } else { + + // Is the previous character a . if so append. + if ((editor.getText ().substring (c - 1, c).equals (".")) + || + (c == id.getEnd ()) + ) + { + + editor.replaceText (c, c, m); + editor.setCaretPosition (c + m.length ()); + + } else { + + part = id.getLastPart (); + + editor.replaceText (part.start, part.start + part.end, m); + editor.setCaretPosition (part.start + m.length ()); + + } + + } + + c = editor.getCaretPosition (); + + id = this.getIdAtCaret (); + + // We may be inserting into the middle of an id, check to see if it's valid. +/* + if (id.hasErrors ()) + { + + this.hideSelector (); + + // Update the view to "spell check" the ids. + return; + + } +*/ + // Check to see if the id maps to a string. + if (this.getEditor ().getBaseStrings ().getString (id.getId ()) != null) + { + + if (id.isPartial ()) + { + + editor.replaceText (id.getEnd (), id.getEnd (), "}"); + editor.setCaretPosition (c + 1); + + } + + this.hideSelector (); + + return; + + } + + // Check to see if there are more matches further down the tree. + String nid = id.getId () + "."; + + Set matches = this.getEditor ().getBaseStrings ().getIdMatches (nid); + + if (matches.size () > 0) + { + + c = editor.getCaretPosition (); + + editor.replaceText (c, c, "."); + editor.setCaretPosition (c + 1); + + try + { + + Bounds b = this.userValue.getTextEditor ().getBoundsForPosition (editor.getCaretPosition ()); + + b = this.userValue.getTextEditor ().screenToLocal (b); + //b = this.userValue.getTextEditor ().localToScene (b); + + this.showSelectionPopup (matches, + b.getMinX (), + b.getMaxY () - this.userValue.getTextEditor ().getLayoutBounds ().getHeight ()); + + } catch (Exception e) { + + e.printStackTrace (); + + } + + return; + + } else { + + c = editor.getCaretPosition (); + + editor.replaceText (c, c, "}"); + editor.setCaretPosition (c + 1); + + this.hideSelector (); + + return; + + } + + } + + private String updateSelectedMatch (int incr) + { + + int i = this.matchesView.getFocusModel ().getFocusedIndex (); + + i += incr; + + int s = this.matches.size (); + + if (i < 0) + { + + i = s + i; + + } + + if (i > s - 1) + { + + i -= s; + + } + + this.matchesView.getFocusModel ().focus (i); + + return this.matchesView.getFocusModel ().getFocusedItem (); + + } + + public boolean isSelectorVisible () + { + + return this.panel.getEditor ().getPopupById (this.popupId) != null; + + } + + public void hideSelector () + { + + QuollPopup qp = this.panel.getEditor ().getPopupById (this.popupId); + + if (qp != null) + { + + qp.close (); + + } + + this.userValue.getTextEditor ().setFocusTraversable (true); + + if (this.matchesView != null) + { + + //this.matchesView.getFocusModel ().focus (-1); + + } + + } + + public void showSelectionPopup (Set matches, + Bounds b) + { + + this.showSelectionPopup (matches, + b.getMinX (), + b.getMinY ()); + + } + + public void showSelectionPopup (Set matches, + Point2D point) + { + + this.showSelectionPopup (matches, + point.getX (), + point.getY ()); + + } + + public void showSelectionPopup (Set matches, + double x, + double y) + { + + if ((matches == null) + || + (matches.size () == 0) + ) + { + + QuollPopup qp = this.panel.getEditor ().getPopupById (this.popupId); + + if (qp != null) + { + + qp.close (); + + } + + return; + + } + + this.matches.clear (); + this.matches.addAll (matches); + + this.userValue.getTextEditor ().setFocusTraversable (false); + + QuollPopup qp = this.panel.getEditor ().getPopupById (this.popupId); + + if (qp == null) + { + + this.matchesView = ShowObjectSelectPopup.builder () + .withViewer (this.panel.getEditor ()) + .styleClassName (StyleClassNames.STRING) + .title ((StringProperty) null) + .styleSheet (StyleClassNames.OBJECTSELECT, "languagestringmatches") + .popupId (this.popupId) + .objects (this.matches) + .withClose (false) + .visibleCount (7) + .allowNavigationByKeys (true) + .cellProvider ((obj, popupContent) -> + { + + QuollLabel l = QuollLabel.builder () + .label (obj) + .build (); + + l.setOnMousePressed (ev -> + { + + if (ev.getButton () != MouseButton.PRIMARY) + { + + return; + + } + + this.fillMatch (obj); + + }); + + return l; + + }) + .build (); + + qp = this.matchesView.createPopup (); + + this.matchesView.getSelectionModel ().selectedItemProperty ().addListener ((pr, oldv, newv) -> + { + + if (newv != null) + { + + this.fillMatch (); + + } + + }); + + } + + QuollPopup _qp = qp; + + UIUtils.forceRunLater (() -> + { + + this.matchesView.getFocusModel ().focus (-1); + this.matchesView.getFocusModel ().focus (0); + + }); + + this.panel.getEditor ().showPopup (_qp, + this.userValue.getTextEditor (), + x, + y, + null); + + } + +} diff --git a/src/main/java/com/quollwriter/ui/fx/NamedObjectContent.java b/src/main/java/com/quollwriter/ui/fx/NamedObjectContent.java new file mode 100644 index 00000000..ae457d41 --- /dev/null +++ b/src/main/java/com/quollwriter/ui/fx/NamedObjectContent.java @@ -0,0 +1,34 @@ +package com.quollwriter.ui.fx; + +import javafx.scene.layout.*; + +import com.quollwriter.data.*; +import com.quollwriter.ui.fx.*; +import com.quollwriter.ui.fx.viewers.*; + +/** + A base class for content that is used to display named object content and thus by definition is also suitable for a viewer. + */ +public abstract class NamedObjectContent extends ViewerContent +{ + + protected O object = null; + + public NamedObjectContent (E viewer, + O object) + { + + super (viewer); + + this.object = object; + + } + + public O getObject () + { + + return this.object; + + } + +} diff --git a/src/main/java/com/quollwriter/ui/fx/NamedObjectFindResultsBox.java b/src/main/java/com/quollwriter/ui/fx/NamedObjectFindResultsBox.java new file mode 100644 index 00000000..20064ef2 --- /dev/null +++ b/src/main/java/com/quollwriter/ui/fx/NamedObjectFindResultsBox.java @@ -0,0 +1,159 @@ +package com.quollwriter.ui.fx; + +import java.util.*; +import java.util.function.*; + +import javafx.beans.property.*; +import javafx.scene.*; +import javafx.scene.control.*; +import javafx.scene.input.*; + +import com.quollwriter.*; +import com.quollwriter.data.*; +import com.quollwriter.ui.fx.components.*; +import com.quollwriter.ui.fx.viewers.*; + +import static com.quollwriter.uistrings.UILanguageStringsManager.getUILanguageStringProperty; +import com.quollwriter.uistrings.UILanguageStringsManager; +import static com.quollwriter.LanguageStrings.*; + +public class NamedObjectFindResultsBox extends FindResultsBox +{ + + private Set objs = null; + private QuollTreeView tree = null; + private AccordionItem acc = null; + private String styleClassName = null; + private StringProperty title = null; + + public NamedObjectFindResultsBox (StringProperty title, + String styleClassName, + AbstractProjectViewer viewer, + Set objs) + { + + super (viewer, + null); + + this.objs = objs; + this.styleClassName = styleClassName; + this.title = title; + + } + + @Override + public void dispose () + { + + } + + public QuollTreeView getTree () + { + + if (this.tree == null) + { + + this.tree = this.createTree (); + + } + + return this.tree; + + } + + @Override + public Node getContent () + { + + if (this.tree == null) + { + + this.tree = this.getTree (); + + } + + StringProperty tProp = new SimpleStringProperty (); + tProp.bind (UILanguageStringsManager.createStringBinding (() -> + { + + return String.format ("%1$s (%2$s)", + this.title.getValue (), + //getUILanguageStringProperty (objectnames,plural,this.objType).getValue (), + Environment.formatNumber (this.objs.size ())); + + }, + this.title)); + + this.acc = AccordionItem.builder () + .title (tProp) + .styleClassName (this.styleClassName) + .openContent (this.tree) + .build (); + + return this.acc; + + } + + private QuollTreeView createTree () + { + + Function, Node> cellProvider = (treeItem) -> + { + + NamedObject n = treeItem.getValue (); + + if (n instanceof Project) + { + + return new Label (); + + } + + QuollLabel l = QuollLabel.builder () + .styleClassName (n.getObjectType ()) + .label (n.getName ()) + .build (); + + l.addEventHandler (MouseEvent.MOUSE_RELEASED, + ev -> + { + + if (ev.isPopupTrigger ()) + { + + return; + + } + + this.viewer.viewObject (n); + + }); + + return l; + + }; + + // Create the model. + TreeItem root = new TreeItem<> (); + root.setValue (this.viewer.getProject ()); + + for (NamedObject o : this.objs) + { + + TreeItem ci = new TreeItem<> (); + ci.setValue (o); + root.getChildren ().add (ci); + + } + + QuollTreeView tree = new QuollTreeView<> (); + tree.setShowRoot (false); + tree.getStyleClass ().add (this.styleClassName); + tree.setCellProvider (cellProvider); + tree.setRoot (root); + + return tree; + + } + +} diff --git a/src/main/java/com/quollwriter/ui/fx/NewProjectPanel.java b/src/main/java/com/quollwriter/ui/fx/NewProjectPanel.java new file mode 100644 index 00000000..62e61937 --- /dev/null +++ b/src/main/java/com/quollwriter/ui/fx/NewProjectPanel.java @@ -0,0 +1,353 @@ +package com.quollwriter.ui.fx; + +import java.io.*; +import java.nio.file.*; + +import java.util.*; +import java.util.function.*; + +import javafx.beans.property.*; +import javafx.scene.input.*; +import javafx.event.*; +import javafx.scene.layout.*; + +import com.quollwriter.*; +import com.quollwriter.data.*; +import com.quollwriter.ui.fx.components.*; +import com.quollwriter.ui.fx.viewers.*; + +import static com.quollwriter.uistrings.UILanguageStringsManager.getUILanguageStringProperty; +import static com.quollwriter.LanguageStrings.*; + +public class NewProjectPanel extends VBox +{ + + private QuollTextField name = null; + private QuollFileField saveDir = null; + private QuollPasswordField passwords = null; + private QuollCheckBox encrypt = null; + private Project project = null; + private Form form = null; + private AbstractViewer viewer = null; + private Consumer onProjectCreated = null; + + public NewProjectPanel (AbstractViewer viewer, + StringProperty desc, + boolean showButtons, + boolean createOnReturn) + { + + final NewProjectPanel _this = this; + + this.viewer = viewer; + this.getStyleClass ().add (StyleClassNames.NEWPROJECT); + + this.setFillWidth (true); + + this.name = QuollTextField.builder () + .styleClassName (StyleClassNames.NAME) + .build (); + + Path defDir = Environment.getDefaultSaveProjectDirPath (); + + this.saveDir = QuollFileField.builder () + .styleClassName (StyleClassNames.SAVE) + .initialFile (defDir) + .limitTo (QuollFileField.Type.directory) + .chooserTitle (newprojectpanel,find,title) + .withViewer (viewer) + .build (); + + this.encrypt = QuollCheckBox.builder () + .selected (false) + .label (getUILanguageStringProperty (Arrays.asList (newprojectpanel,labels,LanguageStrings.encrypt))) + .build (); + + this.passwords = QuollPasswordField.builder () + .build (); + + Runnable r = () -> + { + + _this.createProject (); + + }; + + if (createOnReturn) + { + + UIUtils.addDoOnReturnPressed (this.name, + r); + UIUtils.addDoOnReturnPressed (this.passwords.getPasswordField1 (), + r); + UIUtils.addDoOnReturnPressed (this.passwords.getPasswordField2 (), + r); + + } + + this.form = Form.builder () + .description (desc) + .item (getUILanguageStringProperty (Arrays.asList (newprojectpanel,labels,LanguageStrings.name)), + this.name) + .item (getUILanguageStringProperty (Arrays.asList (newprojectpanel,labels,savein)), + this.saveDir) + .item (this.encrypt) + .item (this.passwords) + .confirmButton (showButtons ? getUILanguageStringProperty (Arrays.asList (newprojectpanel,buttons,create)) : null) + .cancelButton (showButtons ? getUILanguageStringProperty (Arrays.asList (newprojectpanel,buttons,cancel)) : null) + .build (); + + this.form.setOnConfirm (ev -> + { + + if (createOnReturn) + { + + r.run (); + + } + + }); + + this.passwords.managedProperty ().bind (this.passwords.visibleProperty ()); + this.passwords.setVisible (false); + this.encrypt.selectedProperty ().addListener ((v, oldv, newv) -> + { + + _this.passwords.setVisible (newv); + + }); + + this.getChildren ().add (this.form); + + } + + public void setOnProjectCreated (Consumer f) + { + + this.onProjectCreated = f; + //this.form.setOnConfirm (ev); + + } + + public void setOnCancel (EventHandler ev) + { + + this.form.setOnCancel (ev); + + } + + public void setProject (Project p) + { + + this.project = p; + + } + + public boolean createProject () + { + + if (!this.checkForm ()) + { + + return false; + + } + + Project proj = this.project; + + if (proj == null) + { + + proj = new Project (this.getName ()); + + } else { + + proj.setName (this.getName ()); + + } + + AbstractProjectViewer pj = null; + + try + { + + pj = AbstractProjectViewer.createProjectViewerForType (proj); + + pj.createViewer (); + + } catch (Exception e) + { + + Environment.logError ("Unable to create new project: " + + proj, + e); + + ComponentUtils.showErrorMessage (this.viewer, + getUILanguageStringProperty (newprojectpanel,actionerror)); + //"Unable to create new project: " + proj.getName ()); + + return false; + + } + + try + { + + proj.setFilePassword (this.getPassword ()); + + pj.newProject (this.getSaveDirectory (), + proj); + + } catch (Exception e) + { + + Environment.logError ("Unable to create new project: " + + proj, + e); + + // Close the viewer, don't care about changes since there won't be any. + pj.close (false, + null); + + ComponentUtils.showErrorMessage (this.viewer, + getUILanguageStringProperty (newprojectpanel,actionerror)); + //"Unable to create new project: " + proj.getName ()); + + return false; + + } + + this.fireEvent (new ActionEvent ()); + + if (this.onProjectCreated != null) + { + + Project _proj = proj; + + UIUtils.runLater (() -> + { + + this.onProjectCreated.accept (_proj); + + }); + + } + + return true; + + } + + public boolean checkForm () + { + + List prefix = Arrays.asList (newprojectpanel,errors); + + this.form.hideError (); + + String n = this.name.getText ().trim (); + + if (n.equals ("")) + { + + this.form.showError (getUILanguageStringProperty (Utils.newList (prefix,novalue))); + return false; + + } + + // See if the project already exists. + Path pf = saveDir.getFile ().resolve (Utils.sanitizeForFilename (n)); + + if (Files.exists (pf)) + { + + this.form.showError (getUILanguageStringProperty (Utils.newList (prefix,valueexists))); + return false; + + } + + if (this.encrypt.isSelected ()) + { + + // Make sure a password has been provided. + String pwd = this.passwords.getPassword1 (); + + String pwd2 = this.passwords.getPassword2 (); + + if (pwd.equals ("")) + { + + this.form.showError (getUILanguageStringProperty (Utils.newList (prefix,nopassword))); + //"Please provide a password for securing the {project}."); + return false; + + } + + if (pwd2.equals ("")) + { + + this.form.showError (getUILanguageStringProperty (Utils.newList (prefix,confirmpassword))); + //"Please confirm your password."); + return false; + + } + + if (!pwd.equals (pwd2)) + { + + this.form.showError (getUILanguageStringProperty (Utils.newList (prefix,nomatch))); + //"The passwords do not match."); + return false; + + } + + } + + return true; + + } + + public Path getSaveDirectory () + { + + return this.saveDir.getFile (); + + } + + public String getPassword () + { + + if (!this.encrypt.isSelected ()) + { + + return null; + + } + + return this.passwords.getPassword1 (); + + } + + public void setName (String n) + { + + this.name.setText (n); + + } + + public String getName () + { + + return this.name.getText (); + + } + + @Override + public void requestFocus () + { + + this.name.requestFocus (); + + } + +} diff --git a/src/main/java/com/quollwriter/ui/fx/NewUserConfigurableTypeFieldPanel.java b/src/main/java/com/quollwriter/ui/fx/NewUserConfigurableTypeFieldPanel.java new file mode 100644 index 00000000..aaf48d94 --- /dev/null +++ b/src/main/java/com/quollwriter/ui/fx/NewUserConfigurableTypeFieldPanel.java @@ -0,0 +1,286 @@ +package com.quollwriter.ui.fx; + +import java.util.*; +import java.util.function.*; + +import javafx.beans.property.*; +import javafx.util.*; +import javafx.collections.*; +import javafx.event.*; +import javafx.scene.control.*; +import javafx.scene.layout.*; + +import com.quollwriter.*; +import com.quollwriter.data.*; +import com.quollwriter.ui.fx.userobjects.*; +import com.quollwriter.ui.fx.components.*; + +import static com.quollwriter.uistrings.UILanguageStringsManager.getUILanguageStringProperty; +import static com.quollwriter.LanguageStrings.*; + +public class NewUserConfigurableTypeFieldPanel extends VBox +{ + + public static final EventType FIELD_CREATED_EVENT = new EventType<> ("newtypefield.created"); + + private QuollTextField nameField = null; + private UserConfigurableObjectTypeField field = null; + private EventHandler formHandler = null; + + public NewUserConfigurableTypeFieldPanel (UserConfigurableObjectType type) + { + + List prefix = Arrays.asList (userobjects,fields,add); + this.getStyleClass ().addAll (StyleClassNames.NEW, StyleClassNames.FIELD); +/* + Header h = Header.builder () + // TODO + .title (getUILanguageStringProperty (userobjects,fields,add,title)) + .build (); + + v.getChildren ().add (h); +*/ + ObservableList vals = FXCollections.observableList (new ArrayList<> ()); + + for (UserConfigurableObjectTypeField.Type t : UserConfigurableObjectTypeField.Type.values ()) + { + + // TODO: File removed for now due to complexity. + if (t == UserConfigurableObjectTypeField.Type.file) + { + + continue; + + } + + if (t == UserConfigurableObjectTypeField.Type.objectname) + { + + continue; + + } + + // Only allow a single object desc. + if ((t == UserConfigurableObjectTypeField.Type.objectdesc) + && + (type.getObjectDescriptionField () != null) + ) + { + + continue; + + } + + // Only allow a single object desc. + if ((t == UserConfigurableObjectTypeField.Type.objectimage) + && + (type.getObjectImageField () != null) + ) + { + + continue; + + } + + // Only allow a single documents + if ((t == UserConfigurableObjectTypeField.Type.documents) + && + (type.hasField (t)) + ) + { + + continue; + + } + + // Only allow a linked to + if ((t == UserConfigurableObjectTypeField.Type.linkedto) + && + (type.hasField (t)) + ) + { + + continue; + + } + + vals.add (t); + + } + + ChoiceBox selType = new ChoiceBox<> (vals); + + selType.setConverter (new StringConverter () + { + + @Override + public UserConfigurableObjectTypeField.Type fromString (String s) + { + + return null; + + } + + @Override + public String toString (UserConfigurableObjectTypeField.Type p) + { + + return p.getName (); + + } + + }); + + VBox fieldBox = new VBox (); + fieldBox.managedProperty ().bind (fieldBox.visibleProperty ()); + fieldBox.setVisible (false); + + this.nameField = QuollTextField.builder () + .styleClassName (StyleClassNames.NAME) + .build (); + + Form f = Form.builder () + .layoutType (Form.LayoutType.stacked) + .item (getUILanguageStringProperty (Utils.newList (prefix,labels,LanguageStrings.type)), + selType) + .item (getUILanguageStringProperty (Utils.newList (prefix,labels,LanguageStrings.name)), + this.nameField) + .build (); + this.getChildren ().addAll (f, fieldBox); + + selType.getSelectionModel ().selectedItemProperty ().addListener ((pr, oldv, newv) -> + { + + this.field = null; + + fieldBox.getChildren ().clear (); + + UserConfigurableObjectTypeField _field = UserConfigurableObjectTypeField.Type.getNewFieldForType (newv); + + UserConfigurableObjectType fakeType = new UserConfigurableObjectType (); + fakeType.setObjectTypeName (type.getObjectTypeName ()); + + _field.setUserConfigurableObjectType (fakeType); + + final UserConfigurableObjectTypeFieldConfigHandler handler = _field.getConfigHandler2 (); + + Set nitems = handler.getExtraFormItems (); + + if ((nitems != null) + && + (nitems.size () > 0) + ) + { + + fieldBox.getChildren ().add (Form.builder () + .layoutType (Form.LayoutType.stacked) + .items (nitems) + .build ()); + + fieldBox.setVisible (true); + + } + + Form bf = Form.builder () + .layoutType (Form.LayoutType.stacked) + .confirmButton (getUILanguageStringProperty (buttons,save)) + .cancelButton (getUILanguageStringProperty (buttons,cancel)) + .build (); + + if (this.formHandler != null) + { + + f.removeEventHandler (Form.FormEvent.CONFIRM_EVENT, + this.formHandler); + + } + + this.formHandler = ev -> bf.fireEvent (ev); + + f.addEventHandler (Form.FormEvent.CONFIRM_EVENT, + this.formHandler); + bf.setOnConfirm (ev -> + { + + ev.consume (); + Set errs = new LinkedHashSet<> (); + + if (nameField.getText ().trim ().equals ("")) + { + + errs.add (getUILanguageStringProperty (Utils.newList (prefix,errors,LanguageStrings.name,novalue))); + + } + + _field.setUserConfigurableObjectType (null); + + // Check for the name being the same as another field. + String formName = nameField.getText ().trim (); + String lformName = formName.toLowerCase (); + + for (UserConfigurableObjectTypeField uf : type.getConfigurableFields ()) + { + + if (uf.getFormName ().equalsIgnoreCase (lformName)) + { + + errs.add (getUILanguageStringProperty (Utils.newList (prefix,errors,LanguageStrings.name,valueexists), + uf.getFormName ())); + + } + + } + + Set errs2 = handler.getExtraFormItemErrors (type); + + if (errs2 != null) + { + + errs.addAll (errs2); + + } + + if (errs.size () > 0) + { + + f.showErrors (errs); + return; + + } + + _field.setFormName (formName); + + handler.updateFromExtraFormItems (); + + _field.setUserConfigurableObjectType (type); + _field.setOrder (type.getConfigurableFields ().size ()); + + this.field = _field; + this.fireEvent (new Event (FIELD_CREATED_EVENT)); + + }); + + fieldBox.getChildren ().add (bf); + + }); + + selType.getSelectionModel ().select (UserConfigurableObjectTypeField.Type.text); + + } + + public UserConfigurableObjectTypeField getField () + { + + return this.field; + + } + + @Override + public void requestFocus () + { + + this.nameField.requestFocus (); + + } + +} diff --git a/src/main/java/com/quollwriter/ui/fx/NoteItemFormatter.java b/src/main/java/com/quollwriter/ui/fx/NoteItemFormatter.java new file mode 100644 index 00000000..341c0713 --- /dev/null +++ b/src/main/java/com/quollwriter/ui/fx/NoteItemFormatter.java @@ -0,0 +1,111 @@ +package com.quollwriter.ui.fx; + +import javafx.beans.property.*; +import javafx.scene.Node; +import javafx.scene.control.*; +import javafx.scene.layout.*; + +import com.quollwriter.*; +import com.quollwriter.data.*; +import com.quollwriter.ui.fx.components.*; +import com.quollwriter.ui.fx.viewers.*; + +public class NoteItemFormatter extends AbstractProjectItemFormatter +{ + + public NoteItemFormatter (ProjectViewer viewer, + IPropertyBinder binder, + Note item, + Runnable onNewPopupShown) + { + + super (viewer, + binder, + item, + onNewPopupShown, + !item.isDealtWith (), + null); + + } + + @Override + public Node getContent () + { + + VBox v = new VBox (); + + if (this.item.isDealtWith ()) + { + + v.getChildren ().add (QuollLabel.builder () + //.styleClassName (StyleClassNames.DEALTWITH) + .label (new SimpleStringProperty (Environment.formatDateTime (this.item.getDealtWith ()))) + .build ()); + + } + + String summ = this.item.getSummary (); + + String desc = null; + + if ((!this.item.getType ().equals ("")) + && + (!this.item.isEditNeeded ()) + ) + { + + summ = "" + this.item.getType () + ": " + summ; + + if (this.item.getDescription () != null) + { + + summ += "
    " + this.item.getDescription ().getMarkedUpText (); + + } + + desc = summ; + + } else { + + desc = item.getDescription ().getMarkedUpText (); + + } + + QuollTextView t = QuollTextView.builder () + .text (desc) + .styleClassName (StyleClassNames.DESCRIPTION) + .build (); + /* + BasicHtmlTextFlow t = BasicHtmlTextFlow.builder () + .text (desc) + .styleClassName (StyleClassNames.DESCRIPTION) + .build (); +*/ + v.getChildren ().add (t); + + return v; + + } + + public String getStyleClassName () + { + + if (this.item.isEditNeeded ()) + { + + return StyleClassNames.EDITNEEDEDNOTE; + + } + + return StyleClassNames.NOTE; + + } + + public StringProperty getPopupTitle () + { + + return Environment.getObjectTypeName (this.item); + + } + +} diff --git a/src/main/java/com/quollwriter/ui/fx/Options.java b/src/main/java/com/quollwriter/ui/fx/Options.java new file mode 100644 index 00000000..7e3ace9c --- /dev/null +++ b/src/main/java/com/quollwriter/ui/fx/Options.java @@ -0,0 +1,4029 @@ +package com.quollwriter.ui.fx; + +import java.nio.file.*; +import java.net.*; +import java.util.*; +import java.util.function.*; +import java.util.stream.*; +import java.time.*; +import java.time.format.*; +import java.text.*; + +import javafx.collections.*; +import javafx.beans.value.*; +import javafx.beans.binding.*; +import javafx.beans.property.*; +import javafx.util.*; +import javafx.scene.*; +import javafx.scene.image.*; +import javafx.scene.paint.*; +import javafx.scene.control.*; +import javafx.scene.layout.*; +import javafx.scene.text.*; +import javafx.scene.input.*; + +import org.apache.commons.io.file.*; + +import com.quollwriter.*; +import com.quollwriter.data.*; +import com.quollwriter.data.editors.*; +import com.quollwriter.editors.*; +import com.quollwriter.text.*; +import com.quollwriter.ui.fx.popups.*; +import com.quollwriter.ui.fx.components.*; +import com.quollwriter.ui.fx.viewers.*; +import com.quollwriter.achievements.*; +import com.quollwriter.uistrings.UILanguageStringsManager; +import com.quollwriter.uistrings.UILanguageStrings; +import com.quollwriter.uistrings.UILanguageStringsInfo; +import static com.quollwriter.LanguageStrings.*; +import static com.quollwriter.uistrings.UILanguageStringsManager.getUILanguageStringProperty; + +public class Options extends VBox implements Stateful +{ + + private static final String PROJECTITEMPREVIEW_POPUP_ID = "projectitempreview"; + private static final String LAYOUT_POPUP_ID = "layoutselector"; + + private AbstractViewer viewer = null; + private IPropertyBinder propertyBinder = null; + private VBox contentWrapper = null; + private VBox sections = null; + private Section currSect = null; + private Map sects = new HashMap<> (); + private Set headerControls = null; + + public void dispose () + { + + this.propertyBinder.dispose (); + + } + + public Options (AbstractViewer viewer, + IPropertyBinder binder, + Set headerControls, + Section.Id... sects) + { + + this.propertyBinder = binder; + this.viewer = viewer; + this.headerControls = headerControls; + + HBox sp = new HBox (); + this.getChildren ().add (sp); + + VBox left = new VBox (); + left.getStyleClass ().add ("left"); + + Header h_ = Header.builder () + .title (getUILanguageStringProperty (LanguageStrings.options,title)) + .styleClassName (StyleClassNames.MAIN) + .iconClassName (StyleClassNames.OPTIONS) + //.controls (headerControls) + .build (); + + left.getChildren ().add (h_); + + this.sections = new VBox (); + this.sections.getStyleClass ().add (StyleClassNames.SECTIONS); + left.getChildren ().add (new QScrollPane (this.sections)); + VBox.setVgrow (this.sections, + Priority.ALWAYS); + + this.contentWrapper = new VBox (); + this.contentWrapper.getStyleClass ().add (StyleClassNames.ITEMS); + + sp.getChildren ().addAll (left, this.contentWrapper); + HBox.setHgrow (this.contentWrapper, + Priority.ALWAYS); + + VBox.setVgrow (sp, + Priority.ALWAYS); + + for (Section.Id id : sects) + { + + Header h = this.createSectionLabel (id, + viewer); + if (h == null) + { + + continue; + + } + + h.setUserData (id); + + h.setOnMouseClicked (ev -> + { + + this.showSection (id); + + }); + + this.sections.getChildren ().add (h); + + } + + UIUtils.setFirstLastPseudoClasses (this.sections); + + } + + public void showSection (Section.Id id) + { + + this.contentWrapper.getChildren ().clear (); + + Section s = this.sects.get (id); + + if (s == null) + { + + s = this.createSection (id, + this.viewer); + + if (s == null) + { + + return; + + } + + this.sects.put (id, + s); + + } + + if (this.currSect != null) + { + + this.currSect.getHeader ().getControls ().getItems ().clear (); + + } + + Node c = s.getContent (); + Header ch = s.getHeader (); + ch.managedProperty ().bind (ch.visibleProperty ()); + + if (headerControls != null) + { + + ch.getControls ().getItems ().addAll (headerControls); + + } + + VBox.setVgrow (c, + Priority.ALWAYS); + ScrollPane csp = new QScrollPane (c); + VBox.setVgrow (csp, + Priority.ALWAYS); + this.contentWrapper.getChildren ().addAll (ch, csp); + this.currSect = s; + UIUtils.setSelected (sections, + id); + + UIUtils.setFirstLastPseudoClasses ((Parent) c, + "." + StyleClassNames.SUBTITLE); + + } + + @Override + public State getState () + { + + State s = new State (); + + s.set ("selected", + this.currSect.getSectionId ().getType ()); + + return s; + + } + + @Override + public void init (State s) + { + + if (s == null) + { + + this.showSection ((Section.Id) this.sections.getChildren ().get (0).getUserData ()); + return; + + } + + String sel = s.getAsString ("selected"); + + if (sel == null) + { + + this.showSection ((Section.Id) this.sections.getChildren ().get (0).getUserData ()); + return; + + } + + Section.Id id = Section.Id.valueOf (sel); + + if (id != null) + { + + this.showSection (id); + + } + + } + + private Header createSectionLabel (Section.Id id, + AbstractViewer viewer) + { + + String idp = ""; + String scn = ""; + + + if (Section.Id.assets == id) + { + + idp = assets; + scn = StyleClassNames.ASSETS; + + } + + if (Section.Id.look == id) + { + + idp = lookandsound; + scn = StyleClassNames.LOOKS; + + } + +/* +TODO Remove, rolled into the looks section. + if (Section.Id.naming == id) + { + + idp = naming; + scn = StyleClassNames.NAMING; + + } +*/ + if (Section.Id.editing == id) + { + + idp = editingchapters; + scn = StyleClassNames.EDITING; + + } + + if (Section.Id.project == id) + { + + scn = StyleClassNames.PROJECT; + idp = projectandbackup; + + } + + if (Section.Id.start == id) + { + + scn = StyleClassNames.START; + idp = qwstart; + + } + +/* +TODO Remove, rolled into start section + if (Section.Id.warmups == id) + { + + scn = Warmup.OBJECT_TYPE; + idp = warmups; + + } +*/ + if (Section.Id.editors == id) + { + + scn = StyleClassNames.CONTACTS; + idp = editors; + + } + +/* + TODO Remove, rolled into edit section + if (Section.Id.itemsAndRules == id) + { + + scn = StyleClassNames.EDIT; + idp = itemsandrules; + + } +*/ + if (Section.Id.achievements == id) + { + + scn = StyleClassNames.ACHIEVEMENTS; + idp = achievements; + + } + + if (Section.Id.problems == id) + { + + scn = StyleClassNames.BUG; + idp = errors; + + } + + if (idp.equals ("")) + { + + return null; + + } + + return Header.builder () + .styleClassName (scn) + .title (options,idp,title) + //.tooltip (options,idp,text) + .build (); + + } + + private Section createSection (Section.Id id, + AbstractViewer viewer) + { + + if (Section.Id.assets == id) + { + + return this.createAssetsSection (viewer); + + } + + if (Section.Id.look == id) + { + + return this.createLookSection (viewer); + + } + + if (Section.Id.naming == id) + { + + return this.createNamingSection (viewer); + + } + + if (Section.Id.editing == id) + { + + return this.createEditingSection (viewer); + + } + + if (Section.Id.project == id) + { + + return this.createProjectSection (viewer); + + } + + if (Section.Id.start == id) + { + + return this.createStartSection (viewer); + + } + + if (Section.Id.warmups == id) + { + + return this.createWarmupsSection (viewer); + + } + + if (Section.Id.editors == id) + { + + return this.createEditorsSection (viewer); + + } + + if (Section.Id.itemsAndRules == id) + { + + return this.createItemsAndRulesSection (viewer); + + } + + if (Section.Id.achievements == id) + { + + return this.createAchievementsSection (viewer); + + } + + if (Section.Id.problems == id) + { + + return this.createProblemsSection (viewer); + + } + + return null; + + } + + private Node createLayoutSelector () + { + + final Options _this = this; + + //Label l = new Label (); + //l.setGraphic (this.getLayoutPanel (UserProperties.uiLayoutProperty ().getValue ())); + VBox l = new VBox (); + l.getChildren ().add (this.getLayoutPanel (UserProperties.uiLayoutProperty ().getValue ())); + l.maxWidthProperty ().bind (((Region) l.getChildren ().get (0)).widthProperty ()); + + this.propertyBinder.addChangeListener (UserProperties.uiLayoutProperty (), + (pr, oldv, newv) -> + { + + l.getChildren ().clear (); + l.getChildren ().add (this.getLayoutPanel (newv)); + + }); + + l.setOnMouseClicked (ev -> + { + + if (ev.getButton () != MouseButton.PRIMARY) + { + + return; + + } + + QuollPopup qp = this.viewer.getPopupById (LAYOUT_POPUP_ID); + + if (qp != null) + { + + qp.toFront (); + return; + + } + + VBox b = new VBox (); + b.getStyleClass ().add (StyleClassNames.ITEMS); + + qp = QuollPopup.builder () + .title (options,lookandsound,labels,interfacelayout,popup,title) + .styleClassName (StyleClassNames.LAYOUTSELECTOR) + .headerIconClassName (StyleClassNames.EDIT) + .popupId (LAYOUT_POPUP_ID) + .content (b) + .withClose (true) + .withViewer (_this.viewer) + .hideOnEscape (true) + .removeOnClose (true) + .show () + .build (); + + UIUtils.addStyleSheet (qp, + Constants.POPUP_STYLESHEET_TYPE, + StyleClassNames.LAYOUTSELECTOR); + + QuollPopup _qp = qp; + + List layoutTypes = new ArrayList<> (); + layoutTypes.add (Constants.LAYOUT_PS_CH); + layoutTypes.add (Constants.LAYOUT_CH_PS); + layoutTypes.add (Constants.LAYOUT_PS_CH_OS); + layoutTypes.add (Constants.LAYOUT_OS_CH_PS); + layoutTypes.add (Constants.LAYOUT_PS_OS_CH); + layoutTypes.add (Constants.LAYOUT_CH_OS_PS); + + for (String lt : layoutTypes) + { + + HBox hb = new HBox (); + hb.getStyleClass ().add (StyleClassNames.ITEM); + hb.getChildren ().add (this.getLayoutPanel (lt)); + + hb.pseudoClassStateChanged (StyleClassNames.SELECTED_PSEUDO_CLASS, UserProperties.uiLayoutProperty ().getValue ().equals (lt)); + + UIUtils.setTooltip (hb, + getUILanguageStringProperty (options,lookandsound,labels,interfacelayout,popup,tooltip)); + + //BasicHtmlTextFlow text = BasicHtmlTextFlow.builder () + QuollTextView text = QuollTextView.builder () + .styleClassName (StyleClassNames.DESCRIPTION) + .text (getUILanguageStringProperty (options,lookandsound,interfacelayouts,lt)) + .inViewer (_this.viewer) + .build (); + HBox.setHgrow (text, + Priority.ALWAYS); + + hb.getChildren ().add (text); + hb.setUserData (lt); + + hb.setOnMouseClicked (eev -> + { + + if (eev.getButton () != MouseButton.PRIMARY) + { + + return; + + } + + UIUtils.setSelected (b, + lt); + UserProperties.setUILayout (lt); + + Environment.fireUserProjectEvent (_this, + ProjectEvent.Type.layout, + ProjectEvent.Action.changed); + + _qp.close (); + + }); + + b.getChildren ().add (hb); + + } + + UIUtils.runLater (() -> + { + + _qp.toFront (); + + }); + + }); + + return l; + + } + + private Node getLayoutPanel (String type) + { + + if (type.startsWith ("layout-")) + { + + type = type.substring ("layout-".length ()); + + } + + HBox content = new HBox (); + content.getStyleClass ().add (StyleClassNames.LAYOUT); + + StringTokenizer t = new StringTokenizer (type, + "-"); + + while (t.hasMoreTokens ()) + { + + String tok = t.nextToken (); + + if (tok.equals ("os")) + { + + HBox p = new HBox (); + p.getStyleClass ().add (StyleClassNames.OTHER); + + QuollLabel l = QuollLabel.builder () + .label (options,lookandsound,labels,other) + .styleClassName (StyleClassNames.TEXT) + .build (); + + p.getChildren ().add (l); + content.getChildren ().add (p); + + } + + if (tok.equals ("ps")) + { + + HBox p = new HBox (); + p.getStyleClass ().add (StyleClassNames.PROJECT); + + QuollLabel l = QuollLabel.builder () + .label (objectnames,singular, Project.OBJECT_TYPE) + .styleClassName (StyleClassNames.TEXT) + .build (); + + p.getChildren ().add (l); + content.getChildren ().add (p); + + } + + if (tok.equals ("ch")) + { + + HBox p = new HBox (); + p.getStyleClass ().add (StyleClassNames.TABS); + HBox.setHgrow (p, Priority.ALWAYS); + + QuollLabel l = QuollLabel.builder () + // TODO Change to "content" + .label (options,lookandsound,labels,tabs) + .styleClassName (StyleClassNames.TEXT) + .build (); + + p.getChildren ().add (l); + content.getChildren ().add (p); + + } + + } + + return content; + + } + + private Section createWarmupsSection (AbstractViewer viewer) + { + + HBox hcb = new HBox (); + hcb.getStyleClass ().add (StyleClassNames.ITEM); + hcb.getChildren ().addAll (DoWarmupExercisePopup.createWordsOptions (), + QuollLabel.builder () + .label (options,warmups,labels,andor) + .build (), + DoWarmupExercisePopup.createTimeOptions (), + QuollLabel.builder () + .label (options,warmups,labels,whicheverfirst) + .build ()); + + Section s = Section.builder () + .styleClassName (Warmup.OBJECT_TYPE) + .title (options,warmups,title) + .sectionId (Section.Id.warmups) + .description (options,warmups,text) + .mainItem (DoWarmupExercisePopup.createDoWarmupOnStartupCheckbox ()) + .subItem (getUILanguageStringProperty (dowarmup,dofor,title), + hcb) + .build (); + + return s; + + } + + private Section createWebsiteSection (AbstractViewer viewer) + { + + HBox b = new HBox (); + + b.getChildren ().add (QuollButton.builder () + .label (options,website,labels,createtranslation) + .onAction (ev -> + { + + UIUtils.showAddNewWebsiteLanguageStringsPopup (this.viewer); + + }) + .build ()); + + b.getChildren ().add (QuollButton.builder () + .label (options,website,labels,edittranslation) + .onAction (ev -> + { + + UIUtils.showEditWebsiteLanguageStringsSelectorPopup (this.viewer); + + }) + .build ()); + + Section s = Section.builder () + .styleClassName (StyleClassNames.WEBSITE) + .title (options,website,title) + .description (options,website,text) + .sectionId (Section.Id.website) + .mainItem (b) + .build (); + + return s; + + } + + private Section createStartSection (AbstractViewer viewer) + { + + final Options _this = this; + + QuollCheckBox showTips = QuollCheckBox.builder () + .label (options,qwstart,labels,showtips) + .userProperty (Constants.SHOW_TIPS_PROPERTY_NAME) + .build (); + //("Show useful tips")); + + QuollCheckBox lastCB = QuollCheckBox.builder () + .label (options,qwstart,labels,showlastedited) + .userProperty (Constants.OPEN_LAST_EDITED_PROJECT_PROPERTY_NAME) + .build (); + // ("Open the last edited {project}")); + + QuollCheckBox showCB = QuollCheckBox.builder () + .label (options,qwstart,labels,showprojectswindow) + .userProperty (Constants.SHOW_LANDING_ON_START_PROPERY_NAME) + .build (); + + lastCB.selectedProperty ().addListener ((pr, oldv, newv) -> + { + + if (!newv) + { + + showCB.setSelected (true); + + } + + }); + + showCB.selectedProperty ().addListener ((pr, oldv, newv) -> + { + + if (!newv) + { + + lastCB.setSelected (true); + + } + + }); + + // ("Show the {Projects} window")); +/* + showTips.setSelected (UserProperties.getAsBoolean (Constants.SHOW_TIPS_PROPERTY_NAME)); + lastCB.setSelected (UserProperties.getAsBoolean (Constants.OPEN_LAST_EDITED_PROJECT_PROPERTY_NAME)); + showCB.setSelected (UserProperties.getAsBoolean (Constants.SHOW_LANDING_ON_START_PROPERY_NAME)); + + showTips.addItemListener (new ItemAdapter () + { + + public void itemStateChanged (ItemEvent ev) + { + + _this.updateUserProperty (Constants.SHOW_TIPS_PROPERTY_NAME, + showTips.isSelected ()); + + } + + }); + + JComponent c = this.createWrapper (showTips); + this.setAsMainItem (c); + + box.add (c); + + box.add (Box.createVerticalStrut (15)); + + lastCB.addActionListener (new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + if (!lastCB.isSelected ()) + { + + showCB.setSelected (true); + + UserProperties.set (Constants.SHOW_LANDING_ON_START_PROPERY_NAME, + showCB.isSelected ()); + + } + + UserProperties.set (Constants.OPEN_LAST_EDITED_PROJECT_PROPERTY_NAME, + lastCB.isSelected ()); + + } + + }); + + c = this.createWrapper (lastCB); + + this.setAsMainItem (c); + + box.add (c); + + box.add (Box.createVerticalStrut (15)); + + showCB.addActionListener (new ActionAdapter () + { + + public void actionPerformed (ActionEvent ev) + { + + if (!showCB.isSelected ()) + { + + lastCB.setSelected (true); + + UserProperties.set (Constants.OPEN_LAST_EDITED_PROJECT_PROPERTY_NAME, + lastCB.isSelected ()); + + } + + UserProperties.set (Constants.SHOW_LANDING_ON_START_PROPERY_NAME, + showCB.isSelected ()); + + } + + }); + + c = this.createWrapper (showCB); + + this.setAsMainItem (c); + + box.add (c); +*/ + + HBox hcb = new HBox (); + hcb.getStyleClass ().add (StyleClassNames.ITEM); + hcb.getChildren ().addAll (DoWarmupExercisePopup.createWordsOptions (), + QuollLabel.builder () + .label (options,warmups,labels,andor) + .build (), + DoWarmupExercisePopup.createTimeOptions (), + QuollLabel.builder () + .label (options,warmups,labels,whicheverfirst) + .build ()); + + Section s = Section.builder () + .sectionId (Section.Id.start) + .styleClassName (StyleClassNames.START) + .title (options,qwstart,title) + .description (options,qwstart,text) + .mainItem (showTips) + .mainItem (lastCB) + .mainItem (showCB) + .mainItem (DoWarmupExercisePopup.createDoWarmupOnStartupCheckbox ()) + .subItem (getUILanguageStringProperty (dowarmup,dofor,title), + hcb) + .build (); + + return s; + + } + + private Section createEditingSection (AbstractViewer viewer) + { + + //final Properties props = Environment.getDefaultProperties (Project.OBJECT_TYPE); + + Map timeMap = new LinkedHashMap<> (); + + timeMap.put (5, + getUILanguageStringProperty (times,mins5)); + timeMap.put (10, + getUILanguageStringProperty (times,mins10)); + timeMap.put (20, + getUILanguageStringProperty (times,mins20)); + timeMap.put (30, + getUILanguageStringProperty (times,mins30)); + timeMap.put (60, + getUILanguageStringProperty (times,hour1)); + + final ComboBox autosaveAmount = new ComboBox<> (FXCollections.observableList (new ArrayList (timeMap.keySet ()))); + + int v = UserProperties.chapterAutoSaveTimeProperty ().getValue () / Constants.MIN_IN_MILLIS; + + autosaveAmount.getSelectionModel ().select (Integer.valueOf (UserProperties.chapterAutoSaveTimeProperty ().getValue () / Constants.MIN_IN_MILLIS)); + autosaveAmount.valueProperty ().addListener ((pr, oldv, newv) -> + { + + int selVal = autosaveAmount.getSelectionModel ().getSelectedItem (); + + UserProperties.setChapterAutoSaveTime (newv * Constants.MIN_IN_MILLIS); + + }); + + Callback, ListCell> cellFactory = (lv -> + { + + return new ListCell () + { + + @Override + protected void updateItem (Integer item, + boolean empty) + { + + super.updateItem (item, + empty); + + if (empty || item == null) + { + + this.textProperty ().unbind (); + setText (""); + + } else { + + this.textProperty ().bind (timeMap.get (item)); + + } + + } + + }; + + }); + + autosaveAmount.setCellFactory (cellFactory); + autosaveAmount.setButtonCell (cellFactory.call (null)); + + // TODO Change to use user properties. + + final QuollCheckBox enableAutosave = QuollCheckBox.builder () + .label (options,editingchapters,labels,autosave) + .build (); + boolean autosaveEnabled = UserProperties.chapterAutoSaveEnabledProperty ().getValue (); + enableAutosave.setSelected (autosaveEnabled); + + enableAutosave.selectedProperty ().addListener ((pv, oldv, newv) -> + { + + UserProperties.setChapterAutoSaveEnabled (enableAutosave.isSelected ()); + autosaveAmount.setDisable (!enableAutosave.isSelected ()); + Environment.fireUserProjectEvent (this.viewer, + ProjectEvent.Type.autosave, + (enableAutosave.isSelected () ? ProjectEvent.Action.on : ProjectEvent.Action.off)); + + }); + + autosaveAmount.setDisable (!autosaveEnabled); + + ComboBox spellcheckLang = new ComboBox<> (); + spellcheckLang.setDisable (true); + + final QuollCheckBox defLang = QuollCheckBox.builder () + .label (options,editingchapters,labels,setasdefaultlanguage) + .build (); + //"Set as default language")); + + defLang.selectedProperty ().addListener ((pr, oldv, newv) -> + { + + if (defLang.isSelected ()) + { + + UserProperties.setDefaultSpellCheckLanguage (spellcheckLang.valueProperty ().getValue ()); + + } + + }); + + Consumer downloadDictFiles = lang -> + { + + DownloadPanel langDownload = DownloadPanel.builder () + .title (getUILanguageStringProperty (Arrays.asList (dictionary,download,notification), + getUILanguageStringProperty (languagenames,lang))) + .styleClassName (StyleClassNames.DOWNLOAD) + .showStop (true) + .build (); + langDownload.managedProperty ().bind (langDownload.visibleProperty ()); + + Set controls = new LinkedHashSet<> (); + controls.add (langDownload.getStopButton ()); + + Notification n = this.viewer.addNotification (langDownload, + StyleClassNames.DOWNLOAD, + -1, + controls); + + UrlDownloader dl = UIUtils.downloadDictionaryFiles (lang, + this.viewer, + // On progress + p -> + { + + langDownload.setProgress (p); + + }, + // On complete + () -> + { + + this.viewer.removeNotification (n); + + if (this.viewer instanceof AbstractProjectViewer) + { + + AbstractProjectViewer pv = (AbstractProjectViewer) this.viewer; + + try + { + + pv.setProjectSpellCheckLanguage (lang); + + } catch (Exception e) { + + Environment.logError ("Unable to set project spell check language to: " + lang, + e); + + ComponentUtils.showErrorMessage (this.viewer, + getUILanguageStringProperty (Arrays.asList (spellchecker,unabletosetlanguage), + getUILanguageStringProperty (languagenames,lang))); + + return; + + } + + pv.fireProjectEventLater (ProjectEvent.Type.spellcheck, + ProjectEvent.Action.changelanguage); + + this.viewer.addNotification (getUILanguageStringProperty (Arrays.asList (options,editingchapters,downloaddictionaryfiles,notification,text), + //"The language files for %s have been downloaded and the project language set.", + lang), + StyleClassNames.INFORMATION, + 30); + + } else { + + // Add a notification that the files have been downloaded. + this.viewer.addNotification (getUILanguageStringProperty (Arrays.asList (options,editingchapters,downloaddictionaryfiles,notification,text), + //"The language files for %s have been downloaded and the project language set.", + lang), + StyleClassNames.INFORMATION, + -1); + + } + + }, + // On error + ex -> + { + + this.viewer.removeNotification (n); + + ComponentUtils.showErrorMessage (this.viewer, + getUILanguageStringProperty (Arrays.asList (dictionary,download,actionerror), + getUILanguageStringProperty (languagenames,spellcheckLang.valueProperty ().getValue ()))); + + }); + + }; + + Node downloadFiles = QuollHyperlink.builder () + .label (options,editingchapters,labels,downloadlanguagefiles) + .styleClassName (StyleClassNames.DOWNLOAD) + .onAction (ev -> + { + + String lang = spellcheckLang.valueProperty ().getValue (); + + downloadDictFiles.accept (lang); + + }) + .build (); + downloadFiles.managedProperty ().bind (downloadFiles.visibleProperty ()); + + if (this.viewer instanceof AbstractProjectViewer) + { + + AbstractProjectViewer pv = (AbstractProjectViewer) this.viewer; + + try + { + + downloadFiles.setVisible (!DictionaryProvider.isLanguageInstalled (pv.getProjectSpellCheckLanguage ())); + + } catch (Exception e) { + + // Ignore. + + } + + } else { + + downloadFiles.setVisible (!DictionaryProvider.isLanguageInstalled (UserProperties.getDefaultSpellCheckLanguage ())); + + } + + spellcheckLang.valueProperty ().addListener ((pr, oldv, newv) -> + { + + final String lang = newv; + + String def = UserProperties.getDefaultSpellCheckLanguage (); + + if (def == null) + { + + def = Constants.ENGLISH; + + } + + final String currLang = def; + + if (UILanguageStrings.isEnglish (def)) + { + + def = Constants.ENGLISH; + + } + + //defLang.setSelected (def.equals (lang)); + + if (this.viewer instanceof AbstractProjectViewer) + { + + AbstractProjectViewer pv = (AbstractProjectViewer) this.viewer; + + def = pv.getProjectSpellCheckLanguage (); + + } + + if (!def.equals (lang)) + { + + defLang.setSelected (false); + + } else { + + defLang.setSelected (true); + + } + + if ((!UILanguageStrings.isEnglish (lang)) + && + (!def.equals (lang)) + ) + { + + QuollPopup.messageBuilder () + .message (options,editingchapters,labels,nonenglishwarning) + .withViewer (this.viewer) + .closeButton () + .build (); + + } + + downloadFiles.setVisible (false); + + // Check to see if the files are available. + try + { + + if (!DictionaryProvider.isLanguageInstalled (lang)) + { + + downloadFiles.setVisible (true); + + List prefix = Arrays.asList (options,editingchapters,downloaddictionaryfiles,popup); + + QuollPopup.questionBuilder () + .withViewer (this.viewer) + .styleClassName (StyleClassNames.DOWNLOAD) + .title (getUILanguageStringProperty (Utils.newList (prefix,title))) + .message (getUILanguageStringProperty (Utils.newList (prefix,text), + lang)) + .confirmButtonLabel (getUILanguageStringProperty (Utils.newList (prefix,buttons,confirm))) + .cancelButtonLabel (getUILanguageStringProperty (Utils.newList (prefix,buttons,cancel))) + .onConfirm (ev -> + { + + downloadDictFiles.accept (lang); + + }) + .onCancel (ev -> + { + + spellcheckLang.getSelectionModel ().select (currLang); + + }) + .build (); + + return; + + } else { + + if (this.viewer instanceof AbstractProjectViewer) + { + + AbstractProjectViewer pv = (AbstractProjectViewer) this.viewer; + + try + { + + pv.setProjectSpellCheckLanguage (lang); + + } catch (Exception e) { + + Environment.logError ("Unable to set spell check language to: " + lang, + e); + + ComponentUtils.showErrorMessage (this.viewer, + getUILanguageStringProperty (Arrays.asList (spellchecker,unabletosetlanguage), + getUILanguageStringProperty (languagenames,lang))); + + } + + pv.fireProjectEventLater (ProjectEvent.Type.spellcheck, + ProjectEvent.Action.changelanguage); + + } + + } + + } catch (Exception e) { + + Environment.logError ("Unable to get language files for: " + + lang, + e); + + ComponentUtils.showErrorMessage (this.viewer, + getUILanguageStringProperty (options,editingchapters,downloaddictionaryfiles,actionerror)); + //"Unable to check for dictionary files, please contact Quoll Writer support."); + + return; + + } + + }); + + Callback, ListCell> langCellFactory = (lv -> + { + + return new ListCell () + { + + @Override + protected void updateItem (String item, + boolean empty) + { + + super.updateItem (item, + empty); + + if (empty || item == null) + { + + this.textProperty ().unbind (); + setText (""); + + } else { + + StringProperty textProp = getUILanguageStringProperty (Arrays.asList (languagenames,item)); + + this.textProperty ().bind (textProp); + + } + + } + + }; + + }); + + spellcheckLang.setCellFactory (langCellFactory); + spellcheckLang.setButtonCell (langCellFactory.call (null)); + + // Get the languages supported by the spellchecker. + Environment.schedule (() -> + { + + String l = null; + + try + { + + l = Utils.getUrlFileAsString (new URL (Environment.getQuollWriterWebsite () + "/" + UserProperties.get (Constants.QUOLL_WRITER_SUPPORTED_LANGUAGES_URL_PROPERTY_NAME))); + + } catch (Exception e) { + + // Something gone wrong, so just add english. + l = Constants.ENGLISH; + + Environment.logError ("Unable to get language files url", + e); + + } + + StringTokenizer t = new StringTokenizer (l, + String.valueOf ('\n')); + + final List langs = new ArrayList<> (); + + while (t.hasMoreTokens ()) + { + + String lang = t.nextToken ().trim (); + + if (lang.equals ("")) + { + + continue; + + } + + langs.add (lang); + + } + + UIUtils.runLater (() -> + { + + spellcheckLang.getItems ().addAll (langs); + + String def = UserProperties.get (Constants.SPELL_CHECK_LANGUAGE_PROPERTY_NAME); + + if (this.viewer instanceof AbstractProjectViewer) + { + + AbstractProjectViewer pv = (AbstractProjectViewer) this.viewer; + + spellcheckLang.getSelectionModel ().select (pv.getProjectSpellCheckLanguage ()); + + } else { + + spellcheckLang.getSelectionModel ().select (def); + + } + + spellcheckLang.setDisable (false); + + boolean isDef = def.equals (spellcheckLang.valueProperty ().getValue ()); + + //defLang.setSelected (isDef); + + }); + + }, + 1, + -1); + + Region editPosColorSwatch = new Region (); + editPosColorSwatch.setBackground (new Background (new BackgroundFill (UserProperties.getEditMarkerColor (), null, null))); + editPosColorSwatch.getStyleClass ().add (StyleClassNames.EDITPOSITIONCOLORSWATCH); + editPosColorSwatch.getStyleClass ().add (StyleClassNames.COLORSWATCH); + + editPosColorSwatch.setOnMouseClicked (ev -> + { + + if (ev.getButton () != MouseButton.PRIMARY) + { + + return; + + } + + String pid = "edit-position-color-chooser"; + + QuollPopup qp = viewer.getPopupById (pid); + + if (qp != null) + { + + qp.toFront (); + return; + + } + + ColorChooserPopup p = new ColorChooserPopup (viewer, + UserProperties.getEditMarkerColor (), + true); + p.getPopup ().setPopupId (pid); + p.getChooser ().setOnColorSelected (eev -> + { + + UserProperties.setEditMarkerColor (p.getChooser ().colorProperty ().getValue ()); + editPosColorSwatch.setBackground (new Background (new BackgroundFill (UserProperties.getEditMarkerColor (), null, null))); + p.close (); + + }); + + p.show (); + + + }); + + QuollCheckBox compressChapterContextMenu = QuollCheckBox.builder () + .label (options,editingchapters,labels,compressrightclickmenu) + .userProperty (Constants.COMPRESS_CHAPTER_CONTEXT_MENU_PROPERTY_NAME) + .build (); + + boolean soundSel = UserProperties.getAsBoolean (Constants.PLAY_SOUND_ON_KEY_STROKE_PROPERTY_NAME); + + QuollButton playSoundB = QuollButton.builder () + .label (options,editingchapters,labels,playtypewritersound,buttons,playsound) + .onAction (ev -> + { + + UserProperties.playKeyStrokeSound (); + + }) + .build (); + + QuollCheckBox playSoundCB = QuollCheckBox.builder () + .selected (soundSel) + .label (options,editingchapters,labels,playtypewritersound,text) + .build (); + + playSoundCB.selectedProperty ().addListener ((pr, oldv, newv) -> + { + + UserProperties.setPlaySoundOnKeyStroke (playSoundCB.isSelected ()); + + }); + + Path kp = null; + + String kf = UserProperties.get (Constants.KEY_STROKE_SOUND_FILE_PROPERTY_NAME); + + if (kf != null) + { + + kp = Paths.get (kf); + + } + + QuollFileField ownSoundF = QuollFileField.builder () + .showClear (true) + .limitTo (QuollFileField.Type.file) + .styleClassName (StyleClassNames.OWNSOUND) + .withViewer (this.viewer) + .fileExtensionFilter (getUILanguageStringProperty (options,editingchapters,labels,playtypewritersound,finder,filter), + "wav") + .chooserTitle (getUILanguageStringProperty (options,editingchapters,labels,playtypewritersound,finder,title)) + .findButtonTooltip (getUILanguageStringProperty (options,editingchapters,labels,playtypewritersound,finder,tooltip)) + .initialFile (kp) + .build (); + + ownSoundF.fileProperty ().addListener ((pr, oldv, newv) -> + { + + UserProperties.setKeyStrokeSoundFilePath (newv); + + }); + + playSoundB.setDisable (!soundSel); + ownSoundF.setDisable (!soundSel); + + playSoundCB.selectedProperty ().addListener ((pr, oldv, newv) -> + { + + playSoundB.setDisable (!playSoundCB.isSelected ()); + ownSoundF.setDisable (!playSoundCB.isSelected ()); + + }); + + QuollCheckBox showPreviewCB = QuollCheckBox.builder () + .label (options,editingchapters,labels,showpreview) + .userProperty (Constants.SHOW_QUICK_OBJECT_PREVIEW_IN_PROJECT_SIDEBAR_PROPERTY_NAME) + .build (); + + QuollButton changeDisplayBut = QuollButton.builder () + .label (options,editingchapters,labels,changedisplay) + .onAction (ev -> + { + + QuollPopup qp = this.viewer.getPopupById (ChangeProjectItemPreviewDisplayPopup.POPUP_ID); + + if (qp != null) + { + + qp.toFront (); + return; + + } + + new ChangeProjectItemPreviewDisplayPopup (this.viewer).show (); + + }) + .build (); + + changeDisplayBut.setDisable (!showPreviewCB.isSelected ()); + + showPreviewCB.selectedProperty ().addListener ((pr, oldv, newv) -> + { + + changeDisplayBut.setDisable (!newv); + + }); + + Section.Builder s = Section.builder () + .styleClassName (StyleClassNames.EDITING) + .sectionId (Section.Id.editing) + .title (options,editingchapters,title) + .description (options,editingchapters,text) + .subtitle (getUILanguageStringProperty (options,editingchapters,labels,subtitles,autosave)) + .mainItem (enableAutosave) + .subItem (getUILanguageStringProperty (options,editingchapters,labels,autosavewhen), + autosaveAmount) + .subtitle (getUILanguageStringProperty (options,editingchapters,labels,subtitles,editposition)) + .mainItem (getUILanguageStringProperty (options,editingchapters,labels,showicon), + QuollCheckBox.builder () + .label (options,editingchapters,labels,haseditposition) + .userProperty (Constants.SHOW_EDIT_POSITION_ICON_IN_CHAPTER_LIST_PROPERTY_NAME) + .build (), + QuollCheckBox.builder () + .label (options,editingchapters,labels,editcomplete) + .userProperty (Constants.SHOW_EDIT_COMPLETE_ICON_IN_CHAPTER_LIST_PROPERTY_NAME) + .build (), + QuollHyperlink.builder () + .label (actions,viewexample) + .styleClassName (StyleClassNames.VIEW) + .onAction (ev -> + { + + String pid = "chapter-icons-example-popup"; + + QuollPopup qp = this.viewer.getPopupById (pid); + + if (qp != null) + { + + qp.toFront (); + return; + + } + + QuollPopup.messageBuilder () + .title (names,example) + .styleClassName (StyleClassNames.CHAPTERICONSEXAMPLE) + .message (new ImageView ()) + .withViewer (this.viewer) + .popupId (pid) + .build (); + + }) + .build ()) + .mainItem (QuollCheckBox.builder () + .label (options,editingchapters,labels,showeditposition) + .userProperty (Constants.SHOW_EDIT_MARKER_IN_CHAPTER_PROPERTY_NAME) + .build ()) + .subItem (getUILanguageStringProperty (options,editingchapters,labels,seteditpositioncolor,text), + editPosColorSwatch, + QuollHyperlink.builder () + .label (actions,viewexample) + .styleClassName (StyleClassNames.VIEW) + .onAction (ev -> + { + + String pid = "edit-position-example-popup"; + + QuollPopup qp = this.viewer.getPopupById (pid); + + if (qp != null) + { + + qp.toFront (); + return; + + } + + QuollPopup.messageBuilder () + .title (names,example) + .styleClassName (StyleClassNames.EDITPOSITIONEXAMPLE) + .message (new ImageView ()) + .withViewer (this.viewer) + .popupId (pid) + .build (); + + }) + .build ()) + .mainItem (QuollCheckBox.builder () + .label (options,editingchapters,labels,seteditcompleteatchapterend) + .userProperty (Constants.SET_CHAPTER_AS_EDIT_COMPLETE_WHEN_EDIT_POSITION_IS_AT_END_OF_CHAPTER_PROPERTY_NAME) + .build ()) + .subtitle (getUILanguageStringProperty (options,editingchapters,labels,subtitles,sidebar)) + .mainItem (showPreviewCB) + .subItem (changeDisplayBut) + .mainItem (QuollCheckBox.builder () + .label (options,editingchapters,labels,shownotes) + .userProperty (Constants.SHOW_NOTES_IN_CHAPTER_LIST_PROPERTY_NAME) + .build ()) + .mainItem (compressChapterContextMenu) + .subItem (QuollHyperlink.builder () + .label (actions,viewexample) + .styleClassName (StyleClassNames.VIEW) + .onAction (ev -> + { + + String pid = "compress-chapter-menu-example-popup-" + compressChapterContextMenu.isSelected (); + + QuollPopup qp = this.viewer.getPopupById (pid); + + if (qp != null) + { + + qp.toFront (); + return; + + } + + ImageView iv = new ImageView (); + iv.pseudoClassStateChanged (StyleClassNames.COMPRESSED_PSEUDO_CLASS, compressChapterContextMenu.isSelected ()); + + QuollPopup.messageBuilder () + .styleClassName (StyleClassNames.COMPRESSCHAPTERCONTEXTEXAMPLE) + .message (iv) + .title (names,example) + .withViewer (this.viewer) + .popupId (pid) + .build (); + + }) + .build ()); + + boolean isAPV = (viewer instanceof ProjectViewer); + + if (isAPV) + { + + s.subtitle (getUILanguageStringProperty (options,editingchapters,labels,subtitles,problemfinder)) + .mainItem (QuollButton.builder () + .label (options,editingchapters,labels,problemfinderrules) + .onAction (ev -> + { + + ((ProjectViewer) viewer).showProblemFinderRuleConfig (); + + }) + .build ()); + + } + + s.subtitle (getUILanguageStringProperty (options,editingchapters,labels,subtitles,notetypes)) + .mainItem (QuollButton.builder () + .label (options,editingchapters,labels,editnotetypes) + .onAction (ev -> + { + + viewer.showManageNoteTypes (); + + }) + .build ()); + + s.subtitle (getUILanguageStringProperty (options,editingchapters,labels,subtitles,spellcheck)) + .mainItem (getUILanguageStringProperty (options,editingchapters,labels,setspellcheckerlanguage), + spellcheckLang) + .subItem (defLang) + .mainItem (QuollButton.builder () + .label (getUILanguageStringProperty (options,editingchapters,labels,managedictionary)) + .onAction (ev -> + { + + this.viewer.showDictionaryManager (); + + }) + .build ()) + // TODO Is this still needed? .subItem (downloadFiles) + .subtitle (getUILanguageStringProperty (options,editingchapters,labels,subtitles,keypress)) + .mainItem (playSoundCB) + .subItem (getUILanguageStringProperty (options,editingchapters,labels,playtypewritersound,selectownwavfile), + ownSoundF) + .subItem (playSoundB); + + return s.build (); + + } + + private Section createNamingSection (AbstractViewer viewer) + { + + Section s = Section.builder () + .sectionId (Section.Id.naming) + .styleClassName (StyleClassNames.NAMING) + .title (options,naming,title) + .description (options,naming,text) + .mainItem (QuollButton.builder () + .label (options,naming,labels,changenames) + .onAction (ev -> + { + + QuollPopup qp = this.viewer.getPopupById (ObjectTypeNameChangePopup.POPUP_ID); + + if (qp != null) + { + + qp.toFront (); + return; + + } + + new ObjectTypeNameChangePopup (this.viewer).show (); + + }) + .build ()) + .build (); + + return s; + + } + + private Section createProjectSection (AbstractViewer viewer) + { + + if (!(this.viewer instanceof AbstractProjectViewer)) + { + + return null; + + } + + AbstractProjectViewer pv = (AbstractProjectViewer) viewer; + + final Options _this = this; + + final Project proj = pv.getProject (); + + VBox b = new VBox (); + + ErrorBox projDirErr = ErrorBox.builder () + .build (); + + QuollFileField projDirF = QuollFileField.builder () + .chooserTitle (getUILanguageStringProperty (options,projectandbackup,labels,selectprojectdir,finder,title)) + .limitTo (QuollFileField.Type.directory) + .initialFile (proj.getProjectDirectory ().getParentFile ().toPath ()) + .withViewer (viewer) + .build (); + + b.getChildren ().addAll (projDirErr, projDirF); + + QuollButton projDirChangeB = QuollButton.builder () + .label (options,projectandbackup,labels,selectprojectdir,finder,label) + .build (); + projDirChangeB.setOnAction (ev -> + { + + this.handleProjectDirChange (projDirF.getFile (), + pv, + err -> + { + + if (err != null) + { + + projDirErr.setErrors (err); + projDirErr.setVisible (true); + + } + + // Reset the project dir, something went wrong. + projDirF.setFile (proj.getProjectDirectory ().getParentFile ().toPath ()); + + }); + + projDirChangeB.setDisable (true); + + }); + projDirChangeB.setDisable (true); + + projDirF.fileProperty ().addListener ((pr, oldv, newv) -> + { + + if (newv == null) + { + + return; + + } + + projDirChangeB.setDisable (newv.equals (proj.getProjectDirectory ().getParentFile ().toPath ())); + + }); + + Set backupsA = new LinkedHashSet<> (); + backupsA.add (getUILanguageStringProperty (times,hours12)); //Constants.HOURS_12); + backupsA.add (getUILanguageStringProperty (times,hours24)); //Constants.HOURS_24); + backupsA.add (getUILanguageStringProperty (times,days2)); //Constants.DAYS_2); + backupsA.add (getUILanguageStringProperty (times,days5)); //Constants.DAYS_5); + backupsA.add (getUILanguageStringProperty (times,week1)); //Constants.WEEK_1); + + long backupsTime = proj.getAutoBackupsTime (); + //Utils.getTimeAsMillis (proj.getProperty (Constants.AUTO_SNAPSHOTS_TIME_PROPERTY_NAME)); + + int btInd = 0; // 12 hours + + if (backupsTime == (24 * Constants.HOUR_IN_MILLIS)) + { + + btInd = 1; + + } + + if (backupsTime == (2 * Constants.DAY_IN_MILLIS)) + { + + btInd = 2; + + } + + if (backupsTime == (5 * Constants.DAY_IN_MILLIS)) + { + + btInd = 3; + + } + + if (backupsTime == (7 * Constants.DAY_IN_MILLIS)) + { + + btInd = 4; + + } + + QuollChoiceBox backupTimeB = QuollChoiceBox.builder () + .items (backupsA) + .onSelected (ev -> + { + + QuollChoiceBox cb = (QuollChoiceBox) ev.getSource (); + + int selInd = cb.getSelectionModel ().getSelectedIndex (); + + long time = 0; + + if (selInd == 0) + { + + time = 12 * Constants.HOUR_IN_MILLIS; + + } + + if (selInd == 1) + { + + time = 24 * Constants.HOUR_IN_MILLIS; + + } + + if (selInd == 2) + { + + time = 2 * Constants.DAY_IN_MILLIS; + + } + + if (selInd == 3) + { + + time = 5 * Constants.DAY_IN_MILLIS; + + } + + if (selInd == 4) + { + + time = 7 * Constants.DAY_IN_MILLIS; + + } + + proj.setAutoBackupsTime (time); + UserProperties.setAutoBackupsTime (time); + + }) + .selectedIndex (btInd) + .build (); + + QuollCheckBox autoBackupEnb = QuollCheckBox.builder () + .label (options,projectandbackup,labels,autobackup) + .selected (proj.isAutoBackupsEnabled ()) + .build (); + + autoBackupEnb.selectedProperty ().addListener ((pr, oldv, newv) -> + { + + backupTimeB.setDisable (!newv); + proj.setAutoBackupsEnabled (newv); + UserProperties.setAutoBackupsEnabled (newv); + + }); + + backupTimeB.setDisable (!autoBackupEnb.isSelected ()); + + Set countA = new LinkedHashSet<> (); + countA.add (new SimpleStringProperty (Environment.formatNumber (10))); + countA.add (new SimpleStringProperty (Environment.formatNumber (20))); + countA.add (new SimpleStringProperty (Environment.formatNumber (50))); + countA.add (getUILanguageStringProperty (options,projectandbackup,labels,all)); + + int count = proj.getBackupsToKeepCount (); + + int selInd = 3; + + if (count == 10) + { + + selInd = 0; + + } + + if (count == 20) + { + + selInd = 1; + + } + + if (count == 50) + { + + selInd = 2; + + } + + QuollChoiceBox backupsCountB = QuollChoiceBox.builder () + .items (countA) + .selectedIndex (selInd) + .onSelected (ev -> + { + + QuollChoiceBox cb = (QuollChoiceBox) ev.getSource (); + + int cselInd = cb.getSelectionModel ().getSelectedIndex (); + + int ccount = 10; + + if (cselInd == 1) + { + + ccount = 20; + + } + + if (cselInd == 2) + { + + ccount = 50; + + } + + if (cselInd == 3) + { + + ccount = -1; + + } + + proj.setBackupsToKeepCount (ccount); + UserProperties.setBackupsToKeepCount (ccount); + + if (ccount > -1) + { + + int _ccount = ccount; + + Runnable prune = () -> + { + + try + { + + pv.getObjectManager ().pruneBackups (pv.getProject (), + _ccount); + + QuollPopup.messageBuilder () + .title (options,projectandbackup,prunebackups,confirmpopup,title) + .message (options,projectandbackup,prunebackups,confirmpopup,text) + .closeButton () + .styleClassName (StyleClassNames.BACKUPS) + .withViewer (viewer) + .build (); + + } catch (Exception e) { + + Environment.logError ("Unable to prune backups for project: " + + proj, + e); + + ComponentUtils.showErrorMessage (viewer, + getUILanguageStringProperty (options,projectandbackup,prunebackups,actionerror)); + + } + + }; + + int pc = -1; + + try + { + + pc = pv.getObjectManager ().getBackupFilesCount (pv.getProject ()); + + } catch (Exception e) { + + Environment.logError ("Unable to prune backups for project: " + + proj, + e); + + ComponentUtils.showErrorMessage (viewer, + getUILanguageStringProperty (options,projectandbackup,prunebackups,actionerror)); + return; + + } + + if (pc > ccount) + { + + QuollPopup.yesConfirmTextEntryBuilder () + .withViewer (viewer) + .styleClassName (StyleClassNames.BACKUPS) + .title (options,projectandbackup,prunebackups,confirmpopup,title) + .description (getUILanguageStringProperty (Arrays.asList (options,projectandbackup,prunebackups,popup,text), + Environment.formatNumber (pc - ccount))) + .confirmButtonLabel (options,projectandbackup,prunebackups,popup,buttons,confirm) + .cancelButtonLabel (options,projectandbackup,prunebackups,popup,buttons,cancel) + .onConfirm (eev -> + { + + prune.run (); + + }) + .build (); + + } + + } + + }) + .build (); + + VBox bb = new VBox (); + + ErrorBox projBackupDirErr = ErrorBox.builder () + .build (); + + Path backupDir = proj.getBackupDirectory ().toPath (); + + if (Files.notExists (backupDir)) + { + + try + { + + Files.createDirectory (backupDir); + + Utils.createQuollWriterDirFile (backupDir); + + } catch (Exception e) { + + Environment.logError ("Unable to create backup dir: " + backupDir, + e); + + } + + } + + QuollFileField projBackupDirF = QuollFileField.builder () + .chooserTitle (getUILanguageStringProperty (options,projectandbackup,labels,selectbackupdir,finder,title)) + .limitTo (QuollFileField.Type.directory) + .initialFile (backupDir) + .withViewer (viewer) + .build (); + + bb.getChildren ().addAll (projBackupDirErr, projBackupDirF); + + QuollButton projBackupDirChangeB = QuollButton.builder () + .label (options,projectandbackup,labels,selectbackupdir,finder,label) + .onAction (ev -> + { + + projBackupDirErr.setVisible (false); + + this.handleBackupsDirChange (projBackupDirF.getFile (), + pv, + err -> + { + + if (err != null) + { + + projBackupDirErr.setErrors (err); + projBackupDirErr.setVisible (true); + + } + + // Reset the project dir, something went wrong. + //projBackupDirF.setFile (proj.getBackupDirectory ().toPath ()); + + }); + + }) + .build (); + projBackupDirChangeB.setDisable (true); + + projBackupDirF.fileProperty ().addListener ((pr, oldv, newv) -> + { + + if (newv == null) + { + + return; + + } + + projBackupDirChangeB.setDisable (newv.equals (proj.getBackupDirectory ().toPath ())); + + }); + + this.propertyBinder.addChangeListener (proj.backupDirectoryProperty (), + (pr, oldv, newv) -> + { + + if (newv == null) + { + + return; + + } + + projBackupDirF.setFile (newv.toPath ()); + + projBackupDirChangeB.setDisable (newv.toPath ().equals (projBackupDirF.fileProperty ().getValue ())); + + }); + + QuollButton createBackupB = QuollButton.builder () + .label (options,projectandbackup,labels,createbackup) + .onAction (ev -> + { + + BackupsManager.showCreateBackup (proj, + proj.getFilePassword (), + this.viewer); + + }) + .build (); + + QuollButton manageBackupsB = QuollButton.builder () + .label (options,projectandbackup,labels,managebackups) + .onAction (ev -> + { + + BackupsManager.showForProject (Environment.getProjectInfo (proj), + this.viewer); + + }) + .build (); + + HBox buts = new HBox (); + buts.getStyleClass ().add (StyleClassNames.ITEM); + buts.getChildren ().addAll (createBackupB, manageBackupsB); + + Section s = Section.builder () + .sectionId (Section.Id.project) + .styleClassName (StyleClassNames.PROJECT) + .title (options,projectandbackup,title) + .description (options,projectandbackup,text) + .subtitle (getUILanguageStringProperty (options,projectandbackup,labels,subtitles,projectdir)) + .mainItem (getUILanguageStringProperty (options,projectandbackup,labels,selectprojectdir,text), + b) + .subItem (projDirChangeB) + .subtitle (getUILanguageStringProperty (options,projectandbackup,labels,subtitles,backups)) + .mainItem (autoBackupEnb) + .subItem (getUILanguageStringProperty (options,projectandbackup,labels,createbackupafter), + backupTimeB) + .mainItem (getUILanguageStringProperty (options,projectandbackup,labels,nobackupstokeep), + backupsCountB) + .mainItem (getUILanguageStringProperty (options,projectandbackup,labels,selectbackupdir,text), + bb) + .subItem (projBackupDirChangeB) + .mainItem (buts) + .build (); + + return s; + + } + + private Section createAssetsSection (AbstractViewer viewer) + { + + String addAsset = UserProperties.get (Constants.ADD_ASSETS_PROPERTY_NAME); + + if (addAsset == null) + { + + addAsset = Constants.ADD_ASSETS_POPUP; + + } + + QuollRadioButtons rbuts = QuollRadioButtons.builder () + .button (QuollRadioButton.builder () + .label (options,assets,labels,newasset,options,alwayspopup,text) + .tooltip (options,assets,labels,newasset,options,alwayspopup,tooltip) + .selected (addAsset.equals (Constants.ADD_ASSETS_POPUP)) + .onAction (ev -> + { + + UserProperties.set (Constants.ADD_ASSETS_PROPERTY_NAME, + Constants.ADD_ASSETS_POPUP); + + }) + .build ()) + .button (QuollRadioButton.builder () + .label (options,assets,labels,newasset,options,popupifpossible,text) + .tooltip (options,assets,labels,newasset,options,popupifpossible,tooltip) + .selected (addAsset.equals (Constants.ADD_ASSETS_TRY_POPUP)) + .onAction (ev -> + { + + UserProperties.set (Constants.ADD_ASSETS_PROPERTY_NAME, + Constants.ADD_ASSETS_TRY_POPUP); + + }) + .build ()) + .button (QuollRadioButton.builder () + .label (options,assets,labels,newasset,options,owntab,text) + .tooltip (options,assets,labels,newasset,options,owntab,tooltip) + .selected (addAsset.equals (Constants.ADD_ASSETS_TAB)) + .onAction (ev -> + { + + UserProperties.set (Constants.ADD_ASSETS_PROPERTY_NAME, + Constants.ADD_ASSETS_TAB); + + }) + .build ()) + .build (); + + ObservableList types = FXCollections.observableList (new ArrayList<> ()); + + this.propertyBinder.addSetChangeListener (Environment.getUserConfigurableObjectTypes (), + ch -> + { + + if (ch.wasAdded ()) + { + + if (ch.getElementAdded ().isAssetObjectType ()) + { + + types.add (ch.getElementAdded ()); + + } + + } + + if (ch.wasRemoved ()) + { + + types.remove (ch.getElementRemoved ()); + + } + + }); + + for (UserConfigurableObjectType t : Environment.getAssetUserConfigurableObjectTypes (true)) + { + + types.add (t); + + } + + ComboBox editTypes = new ComboBox<> (types); + + Callback, ListCell> cellFactory = listView -> + { + + return new ListCell () + { + + // This is dumb...just sayin... + @Override + protected void updateItem (UserConfigurableObjectType type, + boolean empty) + { + + super.updateItem (type, + empty); + + if (empty || item == null) + { + + this.textProperty ().unbind (); + setText (""); + + } else { + + ImageView iv = new ImageView (); + iv.imageProperty ().bind (type.icon16x16Property ()); + + this.textProperty ().bind (type.nameProperty ()); + this.setGraphic (iv); + + } + + } + + }; + + }; + editTypes.setCellFactory (cellFactory); + editTypes.setButtonCell (cellFactory.call (null)); + editTypes.getSelectionModel ().select (types.get (0)); + + QuollButton editType = QuollButton.builder () + .label (buttons,edit) + .onAction (ev -> + { + + this.viewer.showEditUserConfigurableType (editTypes.getSelectionModel ().getSelectedItem ()); + + }) + .build (); + + QuollButton deleteType = QuollButton.builder () + .label (buttons,delete) + .onAction (ev -> + { + + this.viewer.showDeleteUserConfigurableType (editTypes.getSelectionModel ().getSelectedItem ()); + + }) + .build (); + + HBox b = new HBox (); + b.getChildren ().addAll (editTypes, editType, deleteType); + b.getStyleClass ().add (StyleClassNames.ITEM); + + Section s = Section.builder () + .sectionId (Section.Id.assets) + .styleClassName (StyleClassNames.ASSETS) + .title (options,assets,title) + .description (options,assets,text) + .subtitle (getUILanguageStringProperty (options,assets,labels,subtitles,newasset)) + .mainItem (getUILanguageStringProperty (options,assets,labels,newasset,text), + rbuts) + .subtitle (getUILanguageStringProperty (options,assets,labels,subtitles,existing)) + .mainItem (getUILanguageStringProperty (options,assets,labels,editassetconfig), + b) + .subtitle (getUILanguageStringProperty (options,assets,labels,subtitles,newtype)) + .mainItem (QuollButton.builder () + .label (options,assets,labels,addtype) + .onAction (ev -> + { + + // TODO + this.viewer.showAddNewUserConfigurableType (); + + }) + .build ()) + .build (); + + return s; + + } + + private Section createLookSection (AbstractViewer viewer) + { + + QuollButton feedbackB = QuollButton.builder () + .label (options,lookandsound,labels,feedback) + .onAction (ev -> + { + + QuollPopup qp = this.viewer.getPopupById (ContactUILanguageStringsCreatorPopup.getPopupId ()); + + if (qp != null) + { + + qp.toFront (); + return; + + } + + new ContactUILanguageStringsCreatorPopup (this.viewer).show (); + + }) + .build (); + + boolean showFeedbackB = true; + + UILanguageStrings currUIL = UILanguageStringsManager.getCurrentUILanguageStrings (); + + if ((currUIL.isEnglish ()) + || + (currUIL.isUser ()) + ) + { + + showFeedbackB = false; + + } + + feedbackB.setVisible (showFeedbackB); + + ComboBox uilangSel = new ComboBox<> (); + uilangSel.valueProperty ().addListener ((pr, oldv, newv) -> + { + + String uid = newv.id; + + feedbackB.setVisible ((!UILanguageStrings.isEnglish (uid)) && (!uid.startsWith ("user-"))); + + if (uid.equals (UserProperties.get (Constants.USER_UI_LANGUAGE_PROPERTY_NAME))) + { + + return; + + } + + UILanguageStrings ls = null; + + try + { + + ls = UILanguageStringsManager.getUILanguageStrings (uid); + + } catch (Exception e) { + + Environment.logError ("Unable to get ui language for: " + uid, + e); + + ComponentUtils.showErrorMessage (viewer, + getUILanguageStringProperty (uilanguage,set,actionerror)); + + return; + + } + + Runnable setLang = () -> + { + + try + { + + Environment.setUILanguage (uid); + + } catch (Exception e) { + + Environment.logError ("Unable to set ui language to: " + uid, + e); + + ComponentUtils.showErrorMessage (viewer, + getUILanguageStringProperty (uilanguage,set,actionerror)); + + } + + }; + + if (ls == null) + { + + QuollPopup.messageBuilder () + .withViewer (viewer) + .title (uilanguage,set,downloading,title) + .message (uilanguage,set,downloading,text) + .closeButton () + .build (); + + UILanguageStringsManager.downloadUILanguageFile (uid, + setLang, + () -> + { + + ComponentUtils.showErrorMessage (viewer, + getUILanguageStringProperty (uilanguage,set,actionerror)); + + }); + + } else { + + UIUtils.runLater (setLang); + + } + + }); + + Callback, ListCell> cellFactory = (lv -> + { + + return new ListCell () + { + + @Override + protected void updateItem (UILanguageStringsInfo item, + boolean empty) + { + + super.updateItem (item, + empty); + + if (empty || item == null) + { + + this.textProperty ().unbind (); + setText (""); + + } else { + + StringProperty textProp = null;//item.nativeName; + + if (!UILanguageStrings.isEnglish (item.id)) + { + + textProp = getUILanguageStringProperty (Arrays.asList (uilanguage,set,LanguageStrings.item), + item.nativeName, + (item.languageName != null ? item.languageName : ""), + Environment.formatNumber (item.percentComplete), + item.user ? getUILanguageStringProperty (uilanguage,set,createdbyyou) : ""); + /* + text = String.format ("%1$s (%2$s, %3$s%% %4$s%5$s)", + item.nativeName, + item.languageName, + Environment.formatNumber (item.percentComplete), + "complete", + item.user ? ", created by you" : ""); + */ + } else { + + textProp = new SimpleStringProperty (item.nativeName); + + } + + this.textProperty ().bind (textProp); + + } + + } + + }; + + }); + + uilangSel.setCellFactory (cellFactory); + uilangSel.setButtonCell (cellFactory.call (null)); + uilangSel.setDisable (true); + + Environment.schedule (() -> + { + + Set _uilangs = Environment.getAvailableUILanguageStrings (); + + Set uilangs = _uilangs.stream () + .sorted ((o1, o2) -> + { + + if (UILanguageStrings.isEnglish (o1.id)) + { + + return -1 * Integer.MAX_VALUE; + + } + + if (UILanguageStrings.isEnglish (o2.id)) + { + + return -1 * Integer.MAX_VALUE; + + } + + if (o1.nativeName.equals (o2.nativeName)) + { + + return Integer.compare (o1.percentComplete, o2.percentComplete); + + } + + return o1.nativeName.compareTo (o2.nativeName); + + }) + .collect (Collectors.toSet ()); + + UIUtils.runLater (() -> + { + + uilangSel.getItems ().addAll (uilangs); + + uilangSel.setDisable (false); + + String sel = UserProperties.get (Constants.USER_UI_LANGUAGE_PROPERTY_NAME); + + uilangs.stream () + .forEach (in -> + { + + if (in.id.equals (sel)) + { + + uilangSel.getSelectionModel ().select (in); + + } + + }); + + }); + + }, + 0, + -1); + + HBox hb = new HBox (); + hb.getStyleClass ().add (StyleClassNames.ITEM); + hb.getChildren ().addAll (uilangSel, feedbackB); + + QuollButton createTransB = QuollButton.builder () + .label (options,lookandsound,labels,createtranslation) + .onAction (ev -> + { + + UIUtils.showAddNewUILanguageStringsPopup (this.viewer); + + }) + .build (); + + QuollButton editTransB = QuollButton.builder () + .label (options,lookandsound,labels,edittranslation) + .onAction (ev -> + { + + UIUtils.showEditUILanguageStringsSelectorPopup (this.viewer); + + }) + .build (); + + HBox bb = new HBox (); + bb.getStyleClass ().add (StyleClassNames.ITEM); + bb.getChildren ().addAll (createTransB, editTransB); + + VBox uilangb = new VBox (); + uilangb.getChildren ().addAll (hb, bb); + + Slider textSize = new Slider (5, 30, 1); + textSize.setBlockIncrement (1); + textSize.setMajorTickUnit (5); + textSize.setMinorTickCount (4); + + HBox thb = new HBox (); + thb.getStyleClass ().add (StyleClassNames.TEXTSIZE); + + Label less = QuollLabel.builder () + .label (getUILanguageStringProperty (options,lookandsound,labels,basefontsizeless)) + .styleClassName (StyleClassNames.LESS) + .build (); + Label more = QuollLabel.builder () + .label (getUILanguageStringProperty (options,lookandsound,labels,basefontsizemore)) + .styleClassName (StyleClassNames.MORE) + .build (); + thb.getChildren ().addAll (less, textSize, more); + + double f = UserProperties.getUIBaseFontSize (); + + textSize.setValue (f); + textSize.valueChangingProperty ().addListener ((pr, oldv, newv) -> + { + + if (newv) + { + + return; + + } + + UserProperties.setUIBaseFontSize (textSize.valueProperty ().floatValue ()); + + }); + + textSize.valueProperty ().addListener ((pr, oldv, newv) -> + { + + if (textSize.isValueChanging ()) + { + + return; + + } + + UserProperties.setUIBaseFontSize (textSize.valueProperty ().floatValue ()); + + }); + + this.propertyBinder.addChangeListener (UserProperties.uiBaseFontSizeProperty (), + (pr, oldv, newv) -> + { + + if (newv.floatValue () != textSize.valueProperty ().floatValue ()) + { + + textSize.setValue (newv.floatValue ()); + + } + + }); + + ComboBox uiFont = UIUtils.getFontSelector (this.viewer, + UserProperties.getUIBaseFont ()); + + uiFont.valueProperty ().addListener ((pr, oldv, newv) -> + { + + UserProperties.setUIBaseFont (uiFont.valueProperty ().getValue ()); + + }); + + QuollFileField styleSheet = QuollFileField.builder () + .initialFile (UserProperties.getUserStyleSheet ()) + .limitTo (QuollFileField.Type.file) + .withViewer (this.viewer) + .chooserTitle (options,lookandsound,stylesheet,finder,title) + .showClear (true) + .viewButtonTooltip (options,lookandsound,stylesheet,finder,view,tooltip) + .findButtonTooltip (options,lookandsound,stylesheet,finder,find,tooltip) + .clearButtonTooltip (options,lookandsound,stylesheet,finder,clear,tooltip) + .fileExtensionFilter (getUILanguageStringProperty (options,lookandsound,stylesheet,finder,extensionfilter), + "css") + .build (); + + styleSheet.fileProperty ().addListener ((pr, oldv, newv) -> + { + + UserProperties.setUserStyleSheet (newv); + + }); + + QuollTimeRangeSelector timeRange = QuollTimeRangeSelector.builder () + .now () + .from (UserProperties.getAutoNightModeFromTime ()) + .to (UserProperties.getAutoNightModeToTime ()) + .build (); + + QuollCheckBox autoNightMode = QuollCheckBox.builder () + .label (options,lookandsound,labels,autonightmode) + .selected (UserProperties.autoNightModeEnabledProperty ().getValue ()) + .build (); + + timeRange.setDisable (!autoNightMode.isSelected ()); + + autoNightMode.selectedProperty ().addListener ((pr, oldv, newv) -> + { + + timeRange.setDisable (!autoNightMode.isSelected ()); + + UserProperties.setAutoNightModeEnabled (autoNightMode.isSelected ()); + + }); + + timeRange.fromProperty ().addListener ((pr, oldv, newv) -> + { + + UserProperties.setAutoNightModeFromTime (newv); + + }); + + timeRange.toProperty ().addListener ((pr, oldv, newv) -> + { + + UserProperties.setAutoNightModeToTime (newv); + + }); + + QuollCheckBox permNightMode = QuollCheckBox.builder () + .label (options,lookandsound,labels,permanentnightmode) + .selected (UserProperties.permanentNightModeEnabledProperty ().getValue ()) + .build (); + + permNightMode.selectedProperty ().addListener ((pr, oldv, newv) -> + { + + if (!newv) + { + + timeRange.setDisable (false); + autoNightMode.setDisable (false); + + } else { + + timeRange.setDisable (true); + autoNightMode.setDisable (true); + Environment.setNightModeEnabled (true); + + } + + UserProperties.setPermanentlyEnableNightMode (newv); + + }); + + Section s = Section.builder () + .sectionId (Section.Id.look) + .styleClassName (StyleClassNames.LOOKS) + .title (options,lookandsound,title) + .description (options,lookandsound,text) + .subtitle (getUILanguageStringProperty (options,lookandsound,labels,subtitles,language)) + .mainItem (getUILanguageStringProperty (options,lookandsound,labels,uilanguage), + uilangb) + .subtitle (getUILanguageStringProperty (options,lookandsound,labels,subtitles,font)) + .mainItem (getUILanguageStringProperty (options,lookandsound,labels,basefont), + uiFont) + .mainItem (getUILanguageStringProperty (options,lookandsound,labels,basefontsize), + thb) + /* + TODO Removed for now... + .mainItem (getUILanguageStringProperty (options,lookandsound,labels,stylesheet,text), + styleSheet) + */ + .subtitle (getUILanguageStringProperty (options,lookandsound,labels,subtitles,layout)) + .mainItem (getUILanguageStringProperty (options,lookandsound,labels,interfacelayout,text), + this.createLayoutSelector ()) + .mainItem (getUILanguageStringProperty (options,lookandsound,labels,showtoolbar), + QuollComboBox.builder () + .items (getUILanguageStringProperty (options,lookandsound,labels,abovesidebar), + getUILanguageStringProperty (options,lookandsound,labels,belowsidebar)) + .selectedIndex (Constants.TOP.equals (UserProperties.get (Constants.TOOLBAR_LOCATION_PROPERTY_NAME)) ? 0 : 1) + .onSelected (ev -> + { + + ComboBox cb = (ComboBox) ev.getSource (); + + int ind = cb.getSelectionModel ().getSelectedIndex (); + + UserProperties.setToolbarLocation (ind == 0 ? Constants.TOP : Constants.BOTTOM); + + }) + .build ()) + .mainItem (getUILanguageStringProperty (options,lookandsound,labels,showtabs), + QuollComboBox.builder () + .items (getUILanguageStringProperty (options,lookandsound,labels,showtabstop), + getUILanguageStringProperty (options,lookandsound,labels,showtabsbottom)) + .selectedIndex (Constants.TOP.equals (UserProperties.get (Constants.TABS_LOCATION_PROPERTY_NAME)) ? 0 : 1) + .onSelected (ev -> + { + + ComboBox cb = (ComboBox) ev.getSource (); + + int ind = cb.getSelectionModel ().getSelectedIndex (); + + UserProperties.set (Constants.TABS_LOCATION_PROPERTY_NAME, + ind == 0 ? Constants.TOP : Constants.BOTTOM); + + }) + .build ()) + .subtitle (getUILanguageStringProperty (options,lookandsound,labels,subtitles,naming)) + .mainItem (QuollButton.builder () + .label (options,lookandsound,labels,changenames) + .onAction (ev -> + { + + viewer.runCommand (AbstractViewer.CommandId.editobjectnames); + + }) + .build ()) + .subtitle (getUILanguageStringProperty (options,lookandsound,labels,subtitles,tags)) + .mainItem (QuollButton.builder () + .label (options,lookandsound,labels,tags) + .onAction (ev -> + { + + viewer.runCommand (AbstractViewer.CommandId.edittags); + + }) + .build ()) + .subtitle (getUILanguageStringProperty (options,lookandsound,labels,subtitles,nightmode)) + .mainItem (permNightMode) + .mainItem (autoNightMode) + .subItem (timeRange) + .subtitle (getUILanguageStringProperty (options,lookandsound,labels,subtitles,projectswindow)) + .mainItem (QuollCheckBox.builder () + .label (options,lookandsound,labels,keepprojectswindowsopen) + .userProperty (Constants.KEEP_PROJECTS_WINDOW_WHEN_PROJECT_OPENED_PROPERTY_NAME) + .build ()) + .mainItem (QuollCheckBox.builder () + .label (options,lookandsound,labels,showprojectswindownoopenproject) + .userProperty (Constants.SHOW_PROJECTS_WINDOW_WHEN_NO_OPEN_PROJECTS_PROPERTY_NAME) + .build ()) + .subtitle (getUILanguageStringProperty (options,lookandsound,labels,subtitles,find)) + .mainItem (getUILanguageStringProperty (options,lookandsound,labels,whenfind), + QuollRadioButtons.builder () + .button (QuollRadioButton.builder () + .label (options,lookandsound,labels,expandall) + .onAction (ev -> + { + + UserProperties.set (Constants.SHOW_EACH_CHAPTER_FIND_RESULT_PROPERTY_NAME, + true); + + }) + .selected (UserProperties.getAsBoolean (Constants.SHOW_EACH_CHAPTER_FIND_RESULT_PROPERTY_NAME)) + .build ()) + .button (QuollRadioButton.builder () + .label (options,lookandsound,labels,justchapter) + .onAction (ev -> + { + + UserProperties.set (Constants.SHOW_EACH_CHAPTER_FIND_RESULT_PROPERTY_NAME, + false); + + }) + .selected (!UserProperties.getAsBoolean (Constants.SHOW_EACH_CHAPTER_FIND_RESULT_PROPERTY_NAME)) + .build ()) + .build ()) + .build (); + + return s; + + } + + private Section createProblemsSection (AbstractViewer viewer) + { + + QuollCheckBox sendErrorsToSupport = QuollCheckBox.builder () + .label (options,errors,labels,send) + .userProperty (Constants.AUTO_SEND_ERRORS_TO_SUPPORT_PROPERTY_NAME) + .build (); + + Section s = Section.builder () + .styleClassName (StyleClassNames.BUG) + .sectionId (Section.Id.problems) + .title (options,errors,title) + .description (options,errors,text) + .mainItem (sendErrorsToSupport) + .build (); + + return s; + + } + + private Section createAchievementsSection (AbstractViewer viewer) + { + + final AchievementsManager man = Environment.getAchievementsManager (); + + QuollCheckBox achievementsOn = QuollCheckBox.builder () + .label (options,achievements,labels,enable) + .build (); + achievementsOn.setSelected (man.isAchievementsEnabled ()); + + achievementsOn.selectedProperty ().addListener ((pr, oldv, newv) -> + { + + man.setAchievementsEnabled (achievementsOn.isSelected ()); + + }); + + QuollCheckBox achievementSounds = QuollCheckBox.builder () + .label (options,achievements,labels,playsound) + .build (); + achievementSounds.setSelected (man.isSoundEnabled ()); + + QuollCheckBox fullScreenSoundsOn = QuollCheckBox.builder () + .label (options,achievements,labels,playsoundinfullscreen) + .build (); + + fullScreenSoundsOn.setSelected (man.isSoundsInFullScreenEnabled ()); + + achievementSounds.selectedProperty ().addListener ((pr, oldv, newv) -> + { + + man.setSoundEnabled (achievementSounds.isSelected ()); + + fullScreenSoundsOn.setDisable (!achievementSounds.isSelected ()); + + }); + + fullScreenSoundsOn.setSelected (man.isSoundsInFullScreenEnabled ()); + + fullScreenSoundsOn.selectedProperty ().addListener ((pr, oldv, newv) -> + { + + man.setSoundsInFullScreenEnabled (fullScreenSoundsOn.isSelected ()); + + }); + + Section s = Section.builder () + .sectionId (Section.Id.achievements) + .styleClassName (StyleClassNames.ACHIEVEMENTS) + .title (options,achievements,title) + .description (options,achievements,text) + .mainItem (achievementsOn) + .mainItem (achievementSounds) + .subItem (fullScreenSoundsOn) + .build (); + + return s; + + } + + private Section createItemsAndRulesSection (AbstractViewer viewer) + { + + // Gaaah.... + boolean isAPV = (viewer instanceof ProjectViewer); + + HBox b = new HBox (); + b.getStyleClass ().add (StyleClassNames.ITEM); + b.getChildren ().add (QuollButton.builder () + .label (objectnames,plural, Note.NOTE_TYPE_OBJECT_TYPE) + .onAction (ev -> + { + + viewer.showManageNoteTypes (); + + }) + .build ()); + + b.getChildren ().add (QuollButton.builder () + .label (objectnames,plural, Tag.OBJECT_TYPE) + .onAction (ev -> + { + + viewer.runCommand (AbstractViewer.CommandId.edittags); + + }) + .build ()); + + if (isAPV) + { + + b.getChildren ().add (QuollButton.builder () + .label (options,itemsandrules,labels,problemfinderrules) + .onAction (ev -> + { + + ((ProjectViewer) viewer).showProblemFinderRuleConfig (); + + }) + .build ()); + + } + + Section s = Section.builder () + .sectionId (Section.Id.itemsAndRules) + .styleClassName (StyleClassNames.EDIT) + .title (options,itemsandrules,title) + .description (options,itemsandrules,text) + .mainItem (b) + .build (); + + return s; + + } + + private Section createEditorsSection (AbstractViewer viewer) + { + + QuollCheckBox autoLogin = QuollCheckBox.builder () + .label (options,editors,labels,autologin) + .build (); + //"Automatically login/go online whenever Quoll Writer starts"); + + autoLogin.setSelected (EditorsEnvironment.getEditorsPropertyAsBoolean (Constants.QW_EDITORS_SERVICE_LOGIN_AT_QW_START_PROPERTY_NAME)); + + autoLogin.selectedProperty ().addListener ((pr, oldv, newv) -> + { + + try + { + + EditorsEnvironment.setEditorsProperty (Constants.QW_EDITORS_SERVICE_LOGIN_AT_QW_START_PROPERTY_NAME, + autoLogin.isSelected ()); + + } catch (Exception e) { + + Environment.logError ("Unable to set to login at start", + e); + + } + + }); + + List statuses = Arrays.asList (EditorEditor.OnlineStatus.online, + EditorEditor.OnlineStatus.busy, + EditorEditor.OnlineStatus.away, + EditorEditor.OnlineStatus.snooze); + + final ComboBox defStatus = new ComboBox<> (FXCollections.observableList (statuses)); + + defStatus.valueProperty ().addListener ((pr, oldv, newv) -> + { + + EditorEditor.OnlineStatus selVal = defStatus.getSelectionModel ().getSelectedItem (); + + try + { + + EditorsEnvironment.setEditorsProperty (Constants.QW_EDITORS_SERVICE_DEFAULT_ONLINE_STATUS_PROPERTY_NAME, + selVal.getType ()); + + } catch (Exception e) { + + Environment.logError ("Unable to set default online status", + e); + + } + + }); + + Callback, ListCell> cellFactory = (lv -> + { + + return new ListCell () + { + + @Override + protected void updateItem (EditorEditor.OnlineStatus item, + boolean empty) + { + + super.updateItem (item, + empty); + + if (empty || item == null) + { + + this.textProperty ().unbind (); + setText (""); + + } else { + + String iconName = item.getType (); + + IconBox ib = IconBox.builder () + .iconName (iconName) + .build (); + this.setGraphic (ib); + + this.textProperty ().bind (getUILanguageStringProperty (editors,LanguageStrings.statuses,item.getType ())); + //this.getStyleClass ().add (Constants.ONLINE_STATUS_ICON_NAME_PREFIX + iconName); + + } + + } + + }; + + }); + + defStatus.setCellFactory (cellFactory); + defStatus.setButtonCell (cellFactory.call (null)); + + String defOnlineStatus = EditorsEnvironment.getEditorsProperty (Constants.QW_EDITORS_SERVICE_DEFAULT_ONLINE_STATUS_PROPERTY_NAME); + + if (defOnlineStatus != null) + { + + defStatus.getSelectionModel ().select (EditorEditor.OnlineStatus.valueOf (defOnlineStatus)); + + } + + QuollCheckBox fullScreenBusy = QuollCheckBox.builder () + .label (options,editors,labels,fullscreenbusystatus) + .build (); + //"Set my status to Busy when I enter full screen mode"); + + fullScreenBusy.setSelected (EditorsEnvironment.getEditorsPropertyAsBoolean (Constants.QW_EDITORS_SERVICE_SET_BUSY_ON_FULL_SCREEN_ENTERED_PROPERTY_NAME)); + + fullScreenBusy.selectedProperty ().addListener ((pr, oldv, newv) -> + { + + try + { + + EditorsEnvironment.setEditorsProperty (Constants.QW_EDITORS_SERVICE_SET_BUSY_ON_FULL_SCREEN_ENTERED_PROPERTY_NAME, + fullScreenBusy.isSelected ()); + + if (fullScreenBusy.isSelected ()) + { + + if (Environment.isInFullScreen ()) + { + + EditorsEnvironment.fullScreenEntered (); + + } + + } + + } catch (Exception e) { + + Environment.logError ("Unable to set to busy on full screen entered", + e); + + } + + }); + + QuollCheckBox logMessages = QuollCheckBox.builder () + .label (options,editors,labels,logmessages,text) + .build (); + //"Log messages I send/receive (debug only)"); + + logMessages.selectedProperty ().addListener ((pr, oldv, newv) -> + { + + EditorsEnvironment.logEditorMessages (logMessages.isSelected ()); + + }); + + Section s = Section.builder () + .sectionId (Section.Id.editors) + .styleClassName (StyleClassNames.CONTACTS) + .title (options,editors,title) + .description (options,editors,text) + .mainItem (autoLogin) + .mainItem (getUILanguageStringProperty (options,editors,labels,defaultstatus), + defStatus) + .mainItem (fullScreenBusy) + .mainItem (logMessages) + .subItem (getUILanguageStringProperty (options,editors,labels,logmessages,help)) + .build (); + + return s; + + } + + public static class Section extends VBox implements Stateful + { + + public enum Id + { + + warmups ("warmups"), + look ("look"), + naming ("naming"), + editing ("editing"), + editors ("editors"), + itemsAndRules ("itemsAndRules"), + achievements ("achievements"), + problems ("problems"), + betas ("betas"), + start ("start"), + assets ("assets"), + project ("project"), + website ("website"); + + private String type = null; + + Id (String type) + { + + this.type = type; + + } + + public String getType () + { + + return this.type; + + } + + } + + private AccordionItem acc = null; + private Section.Id id = null; + private VBox openContent = null; + private Header header = null; + + private Section (Builder b) + { + + if (b.sectId == null) + { + + throw new IllegalArgumentException ("Section id must be provided."); + + } + + if (b.description == null) + { + + throw new IllegalArgumentException ("Description must be provided."); + + } + + if (b.title == null) + { + + throw new IllegalArgumentException ("Title must be provided."); + + } + + if (b.items.size () == 0) + { + + throw new IllegalArgumentException ("At least 1 item must be provided."); + + } + + this.id = b.sectId; + + BasicHtmlTextFlow desc = BasicHtmlTextFlow.builder () + .text (b.description) + .build (); + desc.managedProperty ().bind (desc.visibleProperty ()); + + VBox c = new VBox (); + c.managedProperty ().bind (c.visibleProperty ()); + c.getStyleClass ().add (StyleClassNames.CONTENT); + + this.openContent = c; + + // Build the section. + for (Item it : b.items) + { + + if (it.type == Item.Type.subtitle) + { + + QuollLabel l = QuollLabel.builder () + .label (it.description) + .styleClassName (StyleClassNames.SUBTITLE) + .build (); + c.getChildren ().add (l); + continue; + + } + + String style = it.type == Item.Type.main ? StyleClassNames.MAIN : StyleClassNames.SUB; + + if (it.description != null) + { + + VBox bb = new VBox (); + + Node n = BasicHtmlTextFlow.builder () + .styleClassName (StyleClassNames.DESCRIPTION) + .text (it.description) + .build (); + + bb.getStyleClass ().add (style); + bb.getChildren ().add (n); + style = StyleClassNames.SUB; + c.getChildren ().add (bb); + + } + + String _style = style; + + it.controls.stream () + .forEach (con -> + { + + VBox bb = new VBox (); + bb.getStyleClass ().add (_style); + bb.getChildren ().add (con); + c.getChildren ().add (bb); + + }); + + } +/* + this.acc = AccordionItem.builder () + .title (b.title) + .openContent (c) + .open (true) + .closedContent (desc) + .styleClassName (b.styleName) + .build (); +*/ + VBox.setVgrow (c, + Priority.ALWAYS); + + this.header = Header.builder () + .title (b.title) + .styleClassName (b.styleName) + .build (); + + } + + public Node getContent () + { + + return this.openContent; + + } + + public Header getHeader () + { + + return this.header; + + } + + public Node getOpenContent () + { + + return this.openContent; + + } + + @Override + public void init (State state) + { + + this.acc.init (state); + + } + + @Override + public State getState () + { + + return this.acc.getState (); + + } + + public Section.Id getSectionId () + { + + return this.id; + + } + + /** + * Get a builder to create a new Section. + * + * @returns A new builder. + */ + public static Section.Builder builder () + { + + return new Builder (); + + } + + private static class Item + { + + public enum Type + { + main, + sub, + subtitle + } + + public StringProperty description = null; + public Set controls = new LinkedHashSet<> (); + public Type type = Type.main; + + public Item (StringProperty desc, + Set controls, + Type type) + { + + this.description = desc; + this.controls.addAll (controls); + this.type = type; + + } + + public Item (StringProperty desc, + Node control, + Type type) + { + + this.description = desc; + this.controls.add (control); + this.type = type; + + } + + } + + public static class Builder implements IBuilder + { + + private StringProperty description = null; + private StringProperty title = null; + private String styleName = null; + private Set items = new LinkedHashSet<> (); + private AbstractViewer viewer = null; + public Section.Id sectId = null; + + private Builder () + { + + } + + @Override + public Section build () + { + + return new Section (this); + + } + + @Override + public Builder _this () + { + + return this; + + } + + public Builder sectionId (Section.Id id) + { + + this.sectId = id; + return this; + + } + + public Builder withViewer (AbstractViewer viewer) + { + + this.viewer = viewer; + return this; + + } + + public Builder styleClassName (String name) + { + + this.styleName = name; + return this; + + } + + public Builder subtitle (StringProperty p) + { + + return this.item (p, + (Node) null, + Item.Type.subtitle); + + } + + public Builder mainItem (Node control) + { + + return this.item (null, + control, + Item.Type.main); + + } + + public Builder mainItem (Set controls) + { + + return this.item (null, + controls, + Item.Type.main); + + } + + public Builder mainItem (StringProperty desc, + Node control) + { + + return this.item (desc, + control, + Item.Type.main); + + } + + public Builder mainItem (StringProperty desc, + Node... controls) + { + + return this.item (desc, + (controls != null ? new LinkedHashSet<> (Arrays.asList (controls)) : null), + Item.Type.main); + + } + + public Builder mainItem (StringProperty desc, + Set control) + { + + return this.item (desc, + control, + Item.Type.main); + + } + + public Builder subItem (Node control) + { + + return this.item (null, + control, + Item.Type.sub); + + } + + public Builder subItem (Set controls) + { + + return this.item (null, + controls, + Item.Type.sub); + + } + + public Builder subItem (StringProperty desc, + Node... controls) + { + + return this.item (desc, + (controls != null ? new LinkedHashSet<> (Arrays.asList (controls)) : null), + Item.Type.sub); + + } + + public Builder subItem (StringProperty desc, + Node control) + { + + return this.item (desc, + control, + Item.Type.sub); + + } + + public Builder subItem (StringProperty desc, + Set controls) + { + + return this.item (desc, + controls, + Item.Type.sub); + + } + + public Builder item (StringProperty desc, + Node control, + Item.Type type) + { + + this.items.add (new Item (desc, + control, + type)); + return this; + + } + + public Builder item (StringProperty desc, + Set controls, + Item.Type type) + { + + this.items.add (new Item (desc, + controls, + type)); + return this; + + } + + public Builder title (List prefix, + String... ids) + { + + return this.title (getUILanguageStringProperty (Utils.newList (prefix, ids))); + + } + + public Builder title (String... ids) + { + + return this.title (getUILanguageStringProperty (ids)); + + } + + public Builder title (StringProperty title) + { + + this.title = title; + return this; + + } + + public Builder description (List prefix, + String... ids) + { + + return this.description (getUILanguageStringProperty (Utils.newList (prefix, ids))); + + } + + public Builder description (String... ids) + { + + return this.description (getUILanguageStringProperty (ids)); + + } + + public Builder description (StringProperty desc) + { + + this.description = desc; + return this; + + } + + } + + } + + private void handleBackupsDirChange (Path newDir, + AbstractProjectViewer viewer, + Consumer error) + { + + Project proj = viewer.getProject (); + + final Path oldDir = proj.getBackupDirectory ().toPath (); + + // See if the project directory is changing. + if (!newDir.equals (oldDir)) + { + + if (!Utils.isDirectoryEmpty (newDir)) + { + + error.accept (getUILanguageStringProperty (project,actions,changebackupdir,errors,dirnotempty)); + return; + + } + + try + { + + if (Files.exists (oldDir)) + { + + PathUtils.copyDirectory (oldDir, + newDir, + StandardCopyOption.COPY_ATTRIBUTES); + + Utils.deleteDir (oldDir); + + } + + } catch (Exception e) { + + Environment.logError ("Unable to move backup dir from: " + + oldDir + + "to: " + + newDir, + e); + + ComponentUtils.showErrorMessage (viewer, + getUILanguageStringProperty (project,actions,changebackupdir,actionerror)); + + } + + proj.setBackupDirectory (newDir.toFile ()); + + ProjectInfo pi = Environment.getProjectInfo (proj); + + if (pi != null) + { + + pi.setBackupDirPath (newDir); + + } + + String pid = "backupdirchange"; + + QuollPopup.messageBuilder () + .removeOnClose (true) + .popupId (pid) + .withViewer (viewer) + .title (project,actions,changebackupdir,confirmpopup,title) + .message (getUILanguageStringProperty (Arrays.asList (project,actions,changebackupdir,confirmpopup,text), + newDir.toString ())) + .button (QuollButton.builder () + .label (buttons,confirm) + .buttonType (ButtonBar.ButtonData.APPLY) + .onAction (eev -> + { + + this.viewer.getPopupById (pid).close (); + + }) + .build ()) + .build (); + + } + + } + + private void handleProjectDirChange (Path newParentDir, + AbstractProjectViewer viewer, + Consumer error) + { + + Project proj = viewer.getProject (); + + Path oldProjDir = proj.getProjectDirectory ().toPath (); + + Path newProjDir = newParentDir.resolve (Utils.sanitizeForFilename (proj.getName ())); + + boolean backupIsSubDir = false; + + Path _newBackupDir = null; + + if (Utils.isSubDir (proj.getProjectDirectory (), + proj.getBackupDirectory ())) + { + + backupIsSubDir = true; + _newBackupDir = newProjDir.resolve (proj.getBackupDirectory ().toPath ().toString ().substring (proj.getProjectDirectory ().toPath ().toString ().length () + 1)); + + if (!Utils.isDirectoryEmpty (_newBackupDir)) + { + + error.accept (getUILanguageStringProperty (Arrays.asList (project,actions,changeprojectdir,errors,backupdirnotempty), + _newBackupDir.toUri ().toString (), + _newBackupDir.toString ())); + + return; + + } + + } + + Path newBackupDir = _newBackupDir; + + // See if the project directory is changing. + if (!newProjDir.equals (oldProjDir)) + { + + if (Files.exists (newProjDir)) + { + + error.accept (getUILanguageStringProperty (project,actions,changeprojectdir,errors,dirnotempty)); + return; + + } + + try + { + + viewer.changeProjectDirectory (newProjDir); + + } catch (Exception e) { + + Environment.logError ("Unable to rename project directory: " + + proj.getProjectDirectory () + + " to: " + + newProjDir, + e); + + ComponentUtils.showErrorMessage (viewer, + getUILanguageStringProperty (project,actions,changeprojectdir,actionerror)); + + //Environment.showAllProjectsViewer (); + + } + + viewer.fireProjectEvent (ProjectEvent.Type.projectobject, + ProjectEvent.Action.changeddirectory, + proj.getObjectType ()); + + String pid = "projectdirchange"; + + QuollPopup.messageBuilder () + .removeOnClose (true) + .popupId (pid) + .withViewer (viewer) + .title (project,actions,changeprojectdir,confirmpopup,title) + .message (getUILanguageStringProperty (Arrays.asList (project,actions,changeprojectdir,confirmpopup,text), + newProjDir.toString ())) + .button (QuollButton.builder () + .label (buttons,confirm) + .buttonType (ButtonBar.ButtonData.APPLY) + .onAction (eev -> + { + + this.viewer.getPopupById (pid).close (); + + }) + .build ()) + .build (); + + if (true) + { + return; + } + + StringProperty extra = new SimpleStringProperty (""); + + if (backupIsSubDir) + { + + extra = getUILanguageStringProperty (project,actions,changeprojectdir,confirmpopup,backupdirchangewarning); + //"Warning! The backups directory for this {project} will also be changed.

    "; + + } + + QuollPopup.questionBuilder () + .withViewer (viewer) + .styleClassName (StyleClassNames.PROJECT) + .title (project,actions,changeprojectdir,confirmpopup,title) + .message (getUILanguageStringProperty (Arrays.asList (project,actions,changeprojectdir,confirmpopup,text), + extra)) + .confirmButtonLabel (project,actions,changeprojectdir,confirmpopup,buttons,confirm) + .cancelButtonLabel (project,actions,changeprojectdir,confirmpopup,buttons,cancel) + .onConfirm (ev -> + { + + try + { + + viewer.changeProjectDirectory (newProjDir); + + } catch (Exception e) { + + Environment.logError ("Unable to rename project directory: " + + proj.getProjectDirectory () + + " to: " + + newProjDir, + e); + + ComponentUtils.showErrorMessage (viewer, + getUILanguageStringProperty (project,actions,changeprojectdir,actionerror)); + + //Environment.showAllProjectsViewer (); + + } + + Environment.getProjectViewer (proj).fireProjectEvent (ProjectEvent.Type.projectobject, + ProjectEvent.Action.changeddirectory, + proj.getObjectType ()); + + + +/* + if (newBackupDir != null) + { + + // Need to change the backup dir first. + proj.setBackupDirectory (newBackupDir.toFile ()); + + } + + viewer.close (true, + () -> + { + + try + { + + Path _newProjDir = Files.move (proj.getProjectDirectory ().toPath (), + newProjDir); + + proj.setProjectDirectory (_newProjDir.toFile ()); + + } catch (Exception e) { + + Environment.logError ("Unable to rename project directory: " + + proj.getProjectDirectory () + + " to: " + + newProjDir, + e); + + ComponentUtils.showErrorMessage (getUILanguageStringProperty (project,actions,changeprojectdir,actionerror)); + //"Unable to change project directory, please contact Quoll Writer support for assistance."); + + } + + // Open the project again. + try + { + + Environment.openProject (proj, + () -> + { + + Environment.getProjectViewer (proj).fireProjectEvent (ProjectEvent.Type.projectobject, + ProjectEvent.Action.changeddirectory, + proj.getObjectType ()); + + }); + + } catch (Exception e) + { + + // Show the projects window. + Environment.showAllProjectsViewer (); + + Environment.logError ("Unable to reopen project: " + + proj, + e); + + ComponentUtils.showErrorMessage (null, + getUILanguageStringProperty (project,actions,changeprojectdir,errors,reopenproject)); + //"Unable to reopen project, please contact Quoll Writer support for assistance."); + + return; + + } + + }); +*/ + }) + .onCancel (ev -> + { + + error.accept (null); + + }) + .build (); + + } + + } + +} diff --git a/src/main/java/com/quollwriter/ui/fx/OutlineItemFormatter.java b/src/main/java/com/quollwriter/ui/fx/OutlineItemFormatter.java new file mode 100644 index 00000000..f55ff00a --- /dev/null +++ b/src/main/java/com/quollwriter/ui/fx/OutlineItemFormatter.java @@ -0,0 +1,81 @@ +package com.quollwriter.ui.fx; + +import javafx.beans.property.*; +import javafx.scene.Node; +import javafx.scene.control.*; +import javafx.scene.layout.*; + +import com.quollwriter.*; +import com.quollwriter.data.*; +import com.quollwriter.ui.fx.components.*; +import com.quollwriter.ui.fx.viewers.*; + +public class OutlineItemFormatter extends AbstractProjectItemFormatter +{ + + public OutlineItemFormatter (ProjectViewer viewer, + IPropertyBinder binder, + OutlineItem item, + Runnable onNewPopupShown) + { + + super (viewer, + binder, + item, + onNewPopupShown, + null); + + } + + @Override + public Node getContent () + { + + VBox v = new VBox (); + + String desc = this.item.getDescription ().getMarkedUpText (); + + // TODO Change to use a QuollTextView. + BasicHtmlTextFlow t = BasicHtmlTextFlow.builder () + .text (desc) + .styleClassName (StyleClassNames.DESCRIPTION) + .build (); + + v.getChildren ().add (t); + + if (this.item.getScene () != null) + { + + v.getChildren ().add (QuollHyperlink.builder () + .label (this.item.getScene ().getName ()) + .styleClassName (StyleClassNames.SCENE) + .onAction (ev -> + { + + this.viewer.runCommand (ProjectViewer.CommandId.viewobject, + item.getScene ()); + + }) + .build ()); + + } + + return v; + + } + + public String getStyleClassName () + { + + return StyleClassNames.OUTLINEITEM; + + } + + public StringProperty getPopupTitle () + { + + return Environment.getObjectTypeName (this.item); + + } + +} diff --git a/src/main/java/com/quollwriter/ui/fx/PopupsViewer.java b/src/main/java/com/quollwriter/ui/fx/PopupsViewer.java new file mode 100644 index 00000000..251b752f --- /dev/null +++ b/src/main/java/com/quollwriter/ui/fx/PopupsViewer.java @@ -0,0 +1,29 @@ +package com.quollwriter.ui.fx; + +import javafx.event.*; +import javafx.scene.*; +import javafx.geometry.*; + +import com.quollwriter.ui.fx.components.*; + +public interface PopupsViewer +{ + + void showPopup (QuollPopup p, + double x, + double y); + + void showPopup (QuollPopup p, + Node n, + Side s); + + QuollPopup getPopupById (String id); + + void removePopup (QuollPopup p); + + void addPopup (QuollPopup p); + + void addEventHandler (EventType type, + EventHandler handler); + +} diff --git a/src/main/java/com/quollwriter/ui/fx/ProblemFinder.java b/src/main/java/com/quollwriter/ui/fx/ProblemFinder.java new file mode 100644 index 00000000..581b7c60 --- /dev/null +++ b/src/main/java/com/quollwriter/ui/fx/ProblemFinder.java @@ -0,0 +1,1247 @@ +package com.quollwriter.ui.fx; + +import java.util.*; +import java.util.stream.*; + +import javafx.geometry.*; +import javafx.scene.Node; +import javafx.scene.input.*; +import javafx.scene.layout.*; +import javafx.scene.control.*; +import javafx.beans.property.*; +import javafx.collections.*; + +import com.quollwriter.*; +import com.quollwriter.ui.fx.viewers.*; +import com.quollwriter.ui.fx.panels.*; +import com.quollwriter.ui.fx.popups.*; +import com.quollwriter.ui.fx.components.*; +import com.quollwriter.text.*; +import com.quollwriter.text.rules.*; +import com.quollwriter.uistrings.*; +import static com.quollwriter.uistrings.UILanguageStringsManager.getUILanguageStringProperty; +import static com.quollwriter.LanguageStrings.*; + +public class ProblemFinder extends VBox +{ + + private VBox problemsBox = null; + private ObservableSet ignoredIssues = null; + private ProjectChapterEditorPanelContent panel = null; + private ProjectViewer viewer = null; + private TextEditor.Highlight lineHighlight = null; + private TextEditor.Highlight issueHighlight = null; + private Label ignoredProblemsLabel = null; + private Label noProblemsLabel = null; + private Label limitLabel = null; + + private TextBlockIterator iter = null; + + private int start = 0; + private int end = -1; + private int lastCaret = -1; + private List ignores = new ArrayList<> (); + private boolean inited = false; + + public ProblemFinder (ProjectChapterEditorPanelContent panel) + { + + this.panel = panel; + this.viewer = panel.getViewer (); + + panel.getEditor ().caretPositionProperty ().addListener ((pr, oldv, newv) -> + { + + this.lastCaret = newv; + this.init (newv, -1); + + }); + + this.ignoredIssues = panel.getObject ().getProblemFinderIgnores (); + + this.managedProperty ().bind (this.visibleProperty ()); + + List prefix = Arrays.asList (project,editorpanel,actions,problemfinder); + + UIUtils.addStyleSheet (this, + Constants.COMPONENT_STYLESHEET_TYPE, + StyleClassNames.PROBLEMFINDER); + + this.getStyleClass ().add (StyleClassNames.PROBLEMFINDER); + + Set controls = new LinkedHashSet<> (); + controls.add (QuollButton.builder () + .iconName (StyleClassNames.CONFIG) + .tooltip (getUILanguageStringProperty (Utils.newList (prefix,headercontrols,items,config,tooltip))) + .onAction (ev -> + { + + this.panel.showProblemFinderRuleConfig (); + + }) + .build ()); + + controls.add (QuollButton.builder () + .iconName (StyleClassNames.FINISH) + .tooltip (getUILanguageStringProperty (Utils.newList (prefix,headercontrols,items,cancel,tooltip))) + .onAction (ev -> + { + + this.finish (); + + }) + .build ()); + + controls.add (UIUtils.createHelpPageButton (this.panel.getViewer (), + "chapters/problem-finder", + null)); + + this.getChildren ().add (Header.builder () + .title (getUILanguageStringProperty (Utils.newList (prefix,title))) + .controls (controls) + .iconClassName (StyleClassNames.PROBLEMFINDER) + .build ()); + + this.limitLabel = QuollLabel.builder () + .label (getUILanguageStringProperty (Utils.newList (prefix,limit))) + .styleClassName (StyleClassNames.INFORMATION) + .build (); + + this.limitLabel.managedProperty ().bind (this.limitLabel.visibleProperty ()); + this.limitLabel.setVisible (false); + this.getChildren ().add (this.limitLabel); + + this.noProblemsLabel = QuollLabel.builder () + .label (getUILanguageStringProperty (Utils.newList (prefix,noproblemsfound))) + .styleClassName (StyleClassNames.NOPROBLEMS) + .build (); + + this.noProblemsLabel.managedProperty ().bind (this.noProblemsLabel.visibleProperty ()); + this.noProblemsLabel.setVisible (false); + this.getChildren ().add (this.noProblemsLabel); + + this.problemsBox = new VBox (); + this.problemsBox.getStyleClass ().add (StyleClassNames.ISSUES); + VBox.setVgrow (this.problemsBox, + Priority.ALWAYS); + + this.getChildren ().add (this.problemsBox); + + HBox buts = new HBox (); + this.getChildren ().add (buts); + + QuollButtonBar qbb = QuollButtonBar.builder () + .button (QuollButton.builder () + .tooltip (getUILanguageStringProperty (Utils.newList (prefix, buttons,previous,tooltip))) + .iconName (StyleClassNames.PREVIOUS) + .onAction (ev -> + { + + try + { + + this.previous (); + + } catch (Exception e) + { + + Environment.logError ("Unable to goto previous.", + e); + + ComponentUtils.showErrorMessage (this.panel.getViewer (), + getUILanguageStringProperty (prefix,previouserror)); + + } + + }) + .build ()) + .button (QuollButton.builder () + .label (getUILanguageStringProperty (Utils.newList (prefix, buttons,next,text))) + .tooltip (getUILanguageStringProperty (Utils.newList (prefix, buttons,next,tooltip))) + .iconName (StyleClassNames.NEXT) + .onAction (ev -> + { + + try + { + + this.next (); + + } catch (Exception e) + { + + Environment.logError ("Unable to goto next problem", + e); + + ComponentUtils.showErrorMessage (this.panel.getViewer (), + getUILanguageStringProperty (prefix,nexterror)); + //"Unable to go to next sentence."); + + } + + }) + .build ()) + .button (QuollButton.builder () + .label (getUILanguageStringProperty (Utils.newList (prefix, buttons,finish,text))) + .tooltip (getUILanguageStringProperty (Utils.newList (prefix, buttons,finish,tooltip))) + .iconName (StyleClassNames.FINISH) + .onAction (ev -> + { + + this.finish (); + + }) + .build ()) + .build (); + + buts.getChildren ().add (qbb); + HBox.setHgrow (qbb, + Priority.ALWAYS); + + this.ignoredProblemsLabel = QuollLabel.builder () + .styleClassName (StyleClassNames.WARNING) + .build (); + this.ignoredProblemsLabel.managedProperty ().bind (this.ignoredProblemsLabel.visibleProperty ()); + this.ignoredProblemsLabel.setVisible (this.ignoredIssues.size () > 0); + + buts.getChildren ().add (this.ignoredProblemsLabel); + + this.ignoredProblemsLabel.textProperty ().bind (UILanguageStringsManager.createStringBinding (() -> + { + + int s = this.ignoredIssues.size (); + + List prefix2 = Arrays.asList (project,editorpanel,actions,problemfinder,ignored); + + String t = null; + + if (s == 1) + { + + t = getUILanguageStringProperty (Utils.newList (prefix2,single)).getValue (); + + } else { + + t = getUILanguageStringProperty (Utils.newList (prefix2,plural), + s).getValue (); + + } + + return t; + + }, + this.ignoredIssues)); + + this.panel.addSetChangeListener (this.ignoredIssues, + ev -> + { + + this.ignoredProblemsLabel.setVisible (this.ignoredIssues.size () > 0); + + }); + + this.ignoredProblemsLabel.addEventHandler (MouseEvent.MOUSE_PRESSED, + ev -> + { + + String id = this.panel.getObject ().getObjectReference ().asString () + "unignoreconfirm"; + + if (this.viewer.getPopupById (id) == null) + { + + QuollPopup qp = QuollPopup.questionBuilder () + .withViewer (this.viewer) + .popupId (id) + .title (getUILanguageStringProperty (Utils.newList (prefix, unignore,confirmpopup,title))) + .styleClassName (StyleClassNames.PROBLEMFINDER) + .message (getUILanguageStringProperty (Utils.newList (prefix,unignore,confirmpopup,text), + Environment.formatNumber (this.ignoredIssues.size ()))) + .confirmButtonLabel (getUILanguageStringProperty (Utils.newList (prefix,unignore,confirmpopup,confirm))) + .onConfirm (eev -> + { + + this.removeAllIgnores (); + + this.viewer.getPopupById (id).close (); + + }) + .build (); + + this.viewer.showPopup (qp, + this.ignoredProblemsLabel, + Side.TOP); + + } + + }); + + } + + private void clearIssuesBox () + { + + this.problemsBox.getChildren ().clear (); + + } + + private void addNoProblems () + { + + this.clearIssuesBox (); + + this.noProblemsLabel.setVisible (true); + + } + + private void getIgnores () + { + + for (Node n : this.problemsBox.getChildren ()) + { + + if (!(n instanceof QuollCheckBox2)) + { + + continue; + + } + + QuollCheckBox2 b = (QuollCheckBox2) n; + + Issue iss = (Issue) b.getUserData (); + + if (b.isSelected ()) + { + + this.panel.getObject ().getProblemFinderIgnores ().add (iss); + + this.viewer.fireProjectEvent (ProjectEvent.Type.problemfinder, + ProjectEvent.Action.ignore); + + } else { + + if (this.panel.getObject ().getProblemFinderIgnores ().remove (iss)) + { + + this.viewer.fireProjectEvent (ProjectEvent.Type.problemfinder, + ProjectEvent.Action.unignore); + + } + + } + + try + { + + this.viewer.saveProblemFinderIgnores (this.panel.getObject ()); + + } catch (Exception e) { + + Environment.logError ("Unable to save problem finder ignores for chapter: " + + this.panel.getObject (), + e); + + ComponentUtils.showErrorMessage (this.viewer, + getUILanguageStringProperty (project,editorpanel,actions,problemfinder,ignore,actionerror)); + + } + + } + + this.ignores = new ArrayList<> (); + + } + + private void clearHighlights () + { + + this.panel.getEditor ().removeHighlight (this.lineHighlight); + this.panel.getEditor ().removeHighlight (this.issueHighlight); + + } + + private void removeAllIgnores () + { + + this.ignoredIssues.clear (); + + try + { + + this.viewer.saveProblemFinderIgnores (this.panel.getObject ()); + + } catch (Exception e) { + + Environment.logError ("Unable to save problem finder ignores for chapter: " + + this.panel.getObject (), + e); + + ComponentUtils.showErrorMessage (this.panel.getViewer (), + getUILanguageStringProperty (project,editorpanel,actions,problemfinder,unignoreall,actionerror)); + + return; + + } + + this.showIgnoredIssues (); + + this.viewer.fireProjectEvent (ProjectEvent.Type.problemfinder, + ProjectEvent.Action.unignore); + + } + + public void reset () + { + + this.start = -1; + this.end = -1; + this.lastCaret = -1; + this.getIgnores (); + + this.clearHighlights (); + + } + + public void close () + { + + this.finish (); + + } + + private void finish () + { + + this.setVisible (false); + + this.inited = false; + + this.reset (); + + this.panel.getEditor ().removeHighlight (this.lineHighlight); + this.panel.getEditor ().removeHighlight (this.issueHighlight); + + this.panel.getEditor ().setHighlightWritingLine (this.panel.viewer.isHighlightWritingLine ()); + + this.panel.getEditor ().requestFocus (); + + this.panel.requestLayout (); + + } + + private int processTextBlock (TextBlock b) + // throws Exception + { + + if (b == null) + { + + return 0; + + } + + if (b instanceof Paragraph) + { + + return this.handleParagraph ((Paragraph) b); + + } + + if (b instanceof Sentence) + { + + return this.handleSentence ((Sentence) b); + + } + + throw new IllegalArgumentException ("Type: " + + b.getClass ().getName () + + " not supported."); + + } + + private int handleParagraph (Paragraph p) + // throws Exception + { + + List issues = RuleFactory.getParagraphIssues (p, + this.viewer.getProject ().getProperties ()); + + this.setPositions (issues); + + return this.handleIssues (issues, + p); + + } + + private int handleSentence (Sentence s) + //throws Exception + { + + List issues = RuleFactory.getSentenceIssues (s, + this.viewer.getProject ().getProperties ()); + + this.setPositions (issues); + return this.handleIssues (issues, + s); + + } + + public void start () + { + + this.next (); + + } + + /* + Returns the number of issues actually displayed. + */ + private int handleIssues (final List issues, + final TextBlock textBlock) + //throws Exception + { + + Collections.sort (issues, + new IssueSorter ()); + this.clearIssuesBox (); + + int ignoredCount = 0; + int issueCount = 0; + + for (Issue iss : issues) + { + + QuollCheckBox2 n = this.createIssueItem (iss); + this.problemsBox.getChildren ().add (n); + n.managedProperty ().bind (n.visibleProperty ()); + + if (this.ignoredIssues.contains (iss)) + { + + n.setVisible (false); + n.setSelected (true); + + ignoredCount++; + continue; + + } + + issueCount++; + + } + + if (issueCount > 0) + { + + this.lastCaret = this.panel.getEditor ().getSelection ().getStart (); + + this.panel.scrollToTextPosition (textBlock.getAllTextStartOffset (), + () -> + { + + int end = textBlock.getAllTextEndOffset () + 1; + + if (textBlock instanceof Sentence) + { + + end = ((Sentence) textBlock).getLastWord ().getAllTextEndOffset (); + + } + + this.lineHighlight = this.panel.getEditor ().addHighlight (new IndexRange (textBlock.getAllTextStartOffset (), + end), + UserProperties.getProblemFinderBlockHighlightColor ()); + + }); + + } + + if (ignoredCount > 0) + { + + int _ignoredCount = ignoredCount; + + QuollLabel l = QuollLabel.builder () + .styleClassName (StyleClassNames.WARNING) + .label (UILanguageStringsManager.createStringPropertyWithBinding (() -> + { + + List prefix = Arrays.asList (project,editorpanel,actions,problemfinder,unignoreissues); + + StringProperty t = null; + + if (_ignoredCount == 1) + { + + t = getUILanguageStringProperty (Utils.newList (prefix,single)); + + } else { + + t = getUILanguageStringProperty (Utils.newList (prefix,plural), + _ignoredCount); + + } + + return t.getValue (); + + })) + .build (); + + l.managedProperty ().bind (l.visibleProperty ()); + + this.problemsBox.getChildren ().add (l); + l.addEventHandler (MouseEvent.MOUSE_PRESSED, + ev -> + { + + this.showIgnoredIssues (); + + }); + + } + + return issueCount; + + } + + private void showIgnoredIssues () + { + + this.problemsBox.getChildren ().stream () + .forEach (n -> + { + + if (n instanceof QuollCheckBox2) + { + + n.setVisible (true); + + } else { + + n.setVisible (false); + + } + + this.viewer.fireProjectEvent (ProjectEvent.Type.problemfinder, + ProjectEvent.Action.unignore); + + }); + + } + + private QuollCheckBox2 createIssueItem (Issue iss) + { + + StringProperty tt = new SimpleStringProperty (); + tt.bind (UILanguageStringsManager.createStringBinding (() -> + { + + String d = iss.getRule ().getDescription (); + + if ((d != null) + && + (d.length () > 0) + ) + { + + d = d + "

    "; + + } + + if (d == null) + { + + d = ""; + + } + + d = d + getUILanguageStringProperty (problemfinder,ignore,checkbox).getValue (); + + return d; + + })); + + QuollCheckBox2 cb = QuollCheckBox2.builder () + .tooltip (tt) + .label (new SimpleStringProperty (iss.getDescription ())) + .build (); + + cb.setUserData (iss); + + cb.addEventHandler (MouseEvent.MOUSE_ENTERED, + ev -> + { + + this.issueHighlight = this.panel.getEditor ().addHighlight (new IndexRange (iss.getStartIssuePosition (), + iss.getEndIssuePosition ()), + UserProperties.getProblemFinderIssueHighlightColor ()); + + }); + + cb.addEventHandler (MouseEvent.MOUSE_EXITED, + ev -> + { + + this.panel.getEditor ().removeHighlight (this.issueHighlight); + + }); + + ProblemFinder _this = this; + + ContextMenu cm = new ContextMenu (); + + List prefix = Arrays.asList (problemfinder,ignore,popupmenu,items); + + cm.getItems ().add (QuollMenuItem.builder () + .iconName (StyleClassNames.FIND) + .label (getUILanguageStringProperty (Utils.newList (prefix,find))) + .onAction (ev -> + { + + this.finish (); + + this.viewer.showProblemFinderRuleSideBar (iss.getRule ()); + + }) + .build ()); + + cm.getItems ().add (QuollMenuItem.builder () + .iconName (StyleClassNames.IGNORE) + .label (getUILanguageStringProperty (Utils.newList (prefix,ignore))) + .onAction (ev -> + { + + ProblemFinderRuleConfigPopup.confirmRuleRemoval (iss.getRule (), + this.viewer, + () -> + { + + _this.removeCheckboxesForRule (iss.getRule ()); + _this.next (); + + }); + + }) + .build ()); + + cm.getItems ().add (QuollMenuItem.builder () + .iconName (StyleClassNames.EDIT) + .label (getUILanguageStringProperty (Utils.newList (prefix,edit))) + .onAction (ev -> + { + + this.viewer.showProblemFinderRuleConfig (config -> + { + + config.editRule (iss.getRule ()); + + }); + + }) + .build ()); + + cb.setContextMenu (cm); + + this.ignores.add (cb); + + return cb; + + } + + private void setPositions (List issues) + { + + issues.stream () + .forEach (i -> + { + + i.setStartPosition2 (this.panel.getEditor ().createTextPosition (i.getStartIssuePosition ())); + + // Set the end position of the sentence. + i.setEndPosition2 (this.panel.getEditor ().createTextPosition (i.getEndIssuePosition ())); + + }); + + } + + public void removeCheckboxesForRule (Rule r) + { + + for (QuollCheckBox2 b : this.ignores) + { + + Issue iss = (Issue) b.getUserData (); + + if (r.getId ().equals (iss.getRule ().getId ())) + { + + this.getChildren ().remove (b); + + } + + } + + } + + private void init (IndexRange range) + { + + this.init (range.getStart (), + range.getEnd ()); + + } + + private void init (int start, + int end) + { + + this.start = start; + this.end = end; + + this.getIgnores (); + this.clearHighlights (); + + if (this.end < this.start) + { + + this.end = -1; + + } + + if (this.start == this.end) + { + + this.end = -1; + + } + + this.noProblemsLabel.setVisible (false); + this.clearIssuesBox (); + + this.limitLabel.setVisible (this.end > -1); + + this.iter = new TextBlockIterator (this.panel.getEditor ().getText (), + this.start, + this.end); + + this.inited = true; + + } + + public void previous () + throws Exception + { + + if (!this.inited) + { + + this.init (this.panel.getEditor ().getSelection ()); + + } + + this.noProblemsLabel.setVisible (false); + + final ProblemFinder _this = this; + + this.getIgnores (); + + this.clearHighlights (); + + TextBlock b = null; + + while ((b = this.iter.previous ()) != null) + { + + Environment.logDebugMessage ("Looking for problems in: " + b); + + int c = this.processTextBlock (b); + + if (c > 0) + { + + Environment.logDebugMessage ("Got: " + c + " problems for text: " + b); + + return; + + } + + } + + this.addNoProblems (); + + if (this.end > -1) + { + + String id = this.panel.getObject ().getObjectReference ().asString () + "problemfinderprevend"; + + QuollPopup qp = this.viewer.getPopupById (id); + + if (qp == null) + { + + List prefix = Arrays.asList (project,editorpanel,actions,problemfinder,nomoreproblems,selected,LanguageStrings.end); + + qp = QuollPopup.messageBuilder () + .withViewer (this.viewer) + .popupId (id) + .title (getUILanguageStringProperty (Utils.newList (prefix,title))) + .message (getUILanguageStringProperty (Utils.newList (prefix,text))) + .build (); + + } + + this.viewer.showPopup (qp); + + return; + + } + + String id = this.panel.getObject ().getObjectReference ().asString () + "problemfinderprevstart"; + + QuollPopup qp = this.viewer.getPopupById (id); + + if (qp == null) + { + + List prefix = Arrays.asList (project,editorpanel,actions,problemfinder,nomoreproblems,LanguageStrings.start); + + qp = QuollPopup.messageBuilder () + .withViewer (this.viewer) + .popupId (id) + .title (getUILanguageStringProperty (Utils.newList (prefix,title))) + .message (getUILanguageStringProperty (Utils.newList (prefix,text))) + .build (); + + } + + this.viewer.showPopup (qp); + + return; + + } + + public void next () + { + + if (!this.inited) + { + + this.init (this.panel.getEditor ().getSelection ()); + + } + + this.noProblemsLabel.setVisible (false); + + final ProblemFinder _this = this; + + this.getIgnores (); + + this.clearHighlights (); + + TextBlock b = null; + + while ((b = this.iter.next ()) != null) + { + + Environment.logDebugMessage ("Looking for problems in: " + b); + + int c = this.processTextBlock (b); + + if (c > 0) + { + + Environment.logDebugMessage ("Got: " + c + " problems for text: " + b); + + return; + + } + + } + + this.addNoProblems (); + + if (this.end > -1) + { + + String id = this.panel.getObject ().getObjectReference ().asString () + "problemfindernextselectedend"; + + QuollPopup qp = this.viewer.getPopupById (id); + + if (qp == null) + { + + java.util.List prefix = Arrays.asList (project,editorpanel,actions,problemfinder,nomoreproblems,selected,LanguageStrings.end); + + qp = QuollPopup.messageBuilder () + .withViewer (this.panel.getViewer ()) + .popupId (id) + .title (getUILanguageStringProperty (Utils.newList (prefix,title))) + .message (getUILanguageStringProperty (Utils.newList (prefix,text))) + .button (QuollButton.builder () + .label (buttons,finish) + .onAction (ev -> + { + + _this.panel.getEditor ().selectRange (_this.start, + _this.end); + + this.viewer.getPopupById (id).close (); + + }) + .build ()) + .build (); + + } + + this.viewer.showPopup (qp); + + return; + + } + + String id = this.panel.getObject ().getObjectReference ().asString () + "problemfindernextend"; + + QuollPopup qp = this.viewer.getPopupById (id); + + if (qp == null) + { + + List prefix = Arrays.asList (LanguageStrings.project,editorpanel,actions,problemfinder,nomoreproblems,LanguageStrings.end); + + qp = QuollPopup.questionBuilder () + .styleClassName (StyleClassNames.PROBLEMFINDER) + .withViewer (this.panel.getViewer ()) + .popupId (id) + .title (getUILanguageStringProperty (Utils.newList (prefix,title))) + .message (getUILanguageStringProperty (Utils.newList (prefix,text))) + .confirmButtonLabel (getUILanguageStringProperty (Utils.newList (prefix,buttons,confirm))) + .cancelButtonLabel (getUILanguageStringProperty (Utils.newList (prefix,buttons,cancel))) + .onConfirm (ev -> + { + + try + { + + _this.init (0, -1); + + _this.next (); + + this.viewer.getPopupById (id).close (); + + } catch (Exception e) { + + Environment.logError ("Unable to move back to start", + e); + + ComponentUtils.showErrorMessage (_this.panel.getViewer (), + getUILanguageStringProperty (Utils.newList (prefix,actionerror))); + //"Unable to move back to start of {chapter}"); + + } + + }) + .onCancel (ev -> + { + + _this.reset (); + + }) + .build (); + + } + + this.viewer.showPopup (qp); + + } + + private class TextBlockIterator + { + + private TextIterator iter = null; + private Paragraph para = null; + private Sentence sent = null; + private int endAt = -1; + private int startAt = -1; + private TextBlock current = null; + + public TextBlockIterator (String text, + int startAt, + int endAt) + { + + this.iter = new TextIterator (text); + this.startAt = startAt; + + this.endAt = endAt; + + } + + public TextBlock next () + { + + if (this.para == null) + { + + this.para = this.iter.getNextClosestParagraphTo (this.startAt); + + if (this.para == null) + { + + // At the end. + return null; + + } + + if (this.startAt > this.para.getStart ()) + { + + this.sent = this.para.getNextClosestSentenceTo (this.startAt - this.para.getStart ()); + + return this.sent; + + } + + } else { + + if (this.sent == null) + { + + this.sent = this.para.getFirstSentence (); + + } else { + + this.sent = this.sent.getNext (); + + } + + if (this.sent == null) + { + + // Get the next paragraph. + this.para = this.para.getNext (); + + } else { + + if ((this.sent.getAllTextStartOffset () > this.endAt) + && + (this.endAt > -1) + ) + { + + return null; + + } + + return this.sent; + + } + + if (this.para == null) + { + + // Reached the end; + return null; + + } + + } + + if ((this.para.getAllTextStartOffset () > this.endAt) + && + (this.endAt > -1) + ) + { + + return null; + + } + + return this.para; + + } + + public TextBlock previous () + { + + if (this.para == null) + { + + this.para = this.iter.getPreviousClosestParagraphTo (this.startAt); + + if (this.para == null) + { + + return null; + + } + + if (this.startAt > this.para.getEnd ()) + { + + this.sent = this.para.getLastSentence (); + + } else { + + this.sent = this.para.getPreviousClosestSentenceTo (this.startAt - this.para.getStart ()); + + } + + } else { + + if (this.sent == null) + { + + this.para = this.para.getPrevious (); + + if (this.para == null) + { + + return null; + + } + + this.sent = this.para.getLastSentence (); + + } else { + + this.sent = this.sent.getPrevious (); + + } + + if (this.sent == null) + { + + if ((this.startAt > this.para.getAllTextStartOffset ()) + && + (this.endAt > -1) + ) + { + + return null; + + } + + return this.para; + + } + + } + + if ((this.startAt > this.sent.getAllTextStartOffset ()) + && + (this.endAt > 1) + ) + { + + return null; + + } + + return this.sent; + + } + + } + +} diff --git a/src/main/java/com/quollwriter/ui/fx/ProjectEvent.java b/src/main/java/com/quollwriter/ui/fx/ProjectEvent.java new file mode 100644 index 00000000..570b764e --- /dev/null +++ b/src/main/java/com/quollwriter/ui/fx/ProjectEvent.java @@ -0,0 +1,236 @@ +package com.quollwriter.ui.fx; + +import java.util.*; + +import com.quollwriter.data.*; + +public class ProjectEvent extends EventObject +{ + + // Don't you just love compilers... + public enum Type + { + any ("any"), + fullscreen ("fullScreen"), + distractionfree ("distractionfree"), + typewritersound ("typewritersound"), + wordcounts ("wordcounts"), + autosave ("autosave"), + spellcheck ("spellcheck"), + toolbar ("toolbar"), + layout ("layout"), + sidebar ("sidebar"), + find ("find"), + synonym ("synonym"), + readability ("readabilty"), + about ("about"), + personaldictionary ("personaldictionary"), + help ("help"), + bugreport ("bugreport"), + contact ("contact"), + _export ("export"), + _import ("import"), + problemfinder ("problemfinder"), + problemfinderruleconfig ("problemfinderruleconfig"), + itemtypes ("itemtypes"), + notetypes ("notetypes"), + ideaboard ("ideaboard"), + idea ("idea"), + ideatype ("ideatype"), + achievements ("achievements"), + tips ("tips"), + tabs ("tabs"), + whatsnew ("whatsnew"), + statistics ("statistics"), + backups ("backups"), + textproperties ("textproperties"), + userobjecttype ("userobjecttype"), + userobjecttypefield ("userobjecttypefield"), + tags ("tags"), + // TODO Change achievements to handle this... + projectobject ("projectobject"), + scene ("scene"), + note ("note"), + outlineitem ("outlineitem"), + chapter ("chapter"), + warmup ("warmup"), + asset ("asset"), + project ("project"), + tag ("tag"); + + final String type; + + Type (String t) + { + + this.type = t; + + } + + public String getType () + { + + return this.type; + + } + + } + + public enum Action + { + changebackground ("changebackground"), + changelanguage ("changelanguage"), + open ("open"), + show ("show"), + close ("close"), + any ("*"), + _new ("new"), + edit ("edit"), + rename ("rename"), + restore ("restore"), + delete ("delete"), + on ("on"), + off ("off"), + move ("move"), + rate ("rate"), + submit ("submit"), + changed ("changed"), + enter ("enter"), + exit ("exit"), + replace ("replace"), + changeddirectory ("changeddirectory"), + addword ("addword"), + removeword ("removeword"), + ignore ("ignore"), + unignore ("unignore"), + newrule ("newrule"), + editrule ("editrule"), + removerule ("removerule"), + sort ("sort"), + timereached ("timereached"), + showchart ("showchart"), + wordcountreached ("wordcountreached"), + converttoproject ("converttoproject"), + warmuponstartup ("warmuponstartup"), + timerrestart ("timerrestart"), + timerstarted ("timerstarted"), + createownprompt ("createownprompt"), + changebordersize ("changebordersize"), + changerbgcolor ("changebgcolor"), + changelinespacing ("changelinespacing"), + changealignment ("changealignment"), + changefontcolor ("changefontcolor"), + changefontsize ("changefontsize"), + changefont ("changefont"), + changebgimage ("changebgimage"), + changebgopacity ("changebgopacity"), + changelineindent ("changelineindent"), + changehighlightwritingline ("changehighlightwritingline"), + changetextborder ("changetextborder"); + + final String action; + + Action (String a) + { + + this.action = a; + + } + + public String getAction () + { + + return this.action; + + } + + } + + private Type type = null; + private Action action = null; + private Object contextObject = null; + + public ProjectEvent (Object source, + Type type, + Action action) + { + + super (source); + + this.type = type; + this.action = action; + + } + + public ProjectEvent (Object source, + Type type, + Action action, + Object contextObject) + { + + this (source, + type, + action); + + this.contextObject = contextObject; + + } + + public ProjectEvent (Object source, + Type type) + { + + this (source, + type, + Action.any); + + } + + public ProjectEvent (Object source, + Type type, + Object contextObject) + { + + this (source, + type, + Action.any, + contextObject); + + } + + public Object getContextObject () + { + + return this.contextObject; + + } + + public Action getAction () + { + + return this.action; + + } + + public Type getType () + { + + return this.type; + + } + + public String toString () + { + + return this.getEventId (); + + } + + public String getEventId () + { + + return this.type.getType () + (this.action != null ? "." + this.action.getAction () : ""); + + } + +} diff --git a/src/main/java/com/quollwriter/ui/fx/ProjectEventListener.java b/src/main/java/com/quollwriter/ui/fx/ProjectEventListener.java new file mode 100644 index 00000000..afcef737 --- /dev/null +++ b/src/main/java/com/quollwriter/ui/fx/ProjectEventListener.java @@ -0,0 +1,11 @@ +package com.quollwriter.ui.fx; + +import java.util.*; + +@FunctionalInterface +public interface ProjectEventListener extends EventListener +{ + + public void eventOccurred (ProjectEvent ev); + +} diff --git a/src/main/java/com/quollwriter/ui/fx/ProjectTextProperties.java b/src/main/java/com/quollwriter/ui/fx/ProjectTextProperties.java new file mode 100644 index 00000000..b9ae97c1 --- /dev/null +++ b/src/main/java/com/quollwriter/ui/fx/ProjectTextProperties.java @@ -0,0 +1,244 @@ +package com.quollwriter.ui.fx; + +import javafx.scene.paint.*; + +import com.gentlyweb.properties.*; + +import com.quollwriter.*; + +public class ProjectTextProperties extends TextProperties implements UserPropertySetter +{ + + private boolean allowSet = true; + + public ProjectTextProperties () + { + + super (); + + boolean v = Environment.isNightModeEnabled (); + + this.initInternal (UserProperties.get (Constants.EDITOR_FONT_PROPERTY_NAME), + UserProperties.getAsInt (Constants.EDITOR_FONT_SIZE_PROPERTY_NAME), + UserProperties.get (Constants.EDITOR_ALIGNMENT_PROPERTY_NAME), + UserProperties.getAsBoolean (Constants.EDITOR_INDENT_FIRST_LINE_PROPERTY_NAME), + UserProperties.getAsFloat (Constants.EDITOR_LINE_SPACING_PROPERTY_NAME), + UserProperties.getAsFloat (Constants.EDITOR_PARAGRAPH_SPACING_PROPERTY_NAME), + UIUtils.hexToColor (UserProperties.get (v ? Constants.EDITOR_FONT_COLOR_NIGHT_MODE_PROPERTY_NAME : Constants.EDITOR_FONT_COLOR_PROPERTY_NAME)), + UIUtils.hexToColor (UserProperties.get (v ? Constants.EDITOR_BGCOLOR_NIGHT_MODE_PROPERTY_NAME : Constants.EDITOR_BGCOLOR_PROPERTY_NAME)), + UIUtils.hexToColor (UserProperties.get (v ? Constants.EDITOR_WRITING_LINE_COLOR_NIGHT_MODE_PROPERTY_NAME : Constants.EDITOR_WRITING_LINE_COLOR_PROPERTY_NAME)), + UserProperties.getAsBoolean (Constants.EDITOR_HIGHLIGHT_WRITING_LINE_PROPERTY_NAME), + UserProperties.getAsInt (Constants.EDITOR_TEXT_BORDER_PROPERTY_NAME)); + + Environment.nightModeProperty ().addListener ((pr, oldv, newv) -> + { + + this.setTextColor (UIUtils.hexToColor (UserProperties.get (newv ? Constants.EDITOR_FONT_COLOR_NIGHT_MODE_PROPERTY_NAME : Constants.EDITOR_FONT_COLOR_PROPERTY_NAME))); + this.setBackgroundColor (UIUtils.hexToColor (UserProperties.get (newv ? Constants.EDITOR_BGCOLOR_NIGHT_MODE_PROPERTY_NAME : Constants.EDITOR_BGCOLOR_PROPERTY_NAME))); + this.setWritingLineColor (UIUtils.hexToColor (UserProperties.get (newv ? Constants.EDITOR_WRITING_LINE_COLOR_NIGHT_MODE_PROPERTY_NAME : Constants.EDITOR_WRITING_LINE_COLOR_PROPERTY_NAME))); + + }); + + } + + public ProjectTextProperties (TextProperties props) + { + + this.initInternal (props); + + } + + @Override + public void stopSetting () + { + + this.allowSet = false; + + } + + @Override + public void startSetting () + { + + this.allowSet = true; + + } + + public void setBackgroundColor (Color c) + { + + super.setBackgroundColor (c); + + this.setProperty (new StringProperty (Environment.isNightModeEnabled () ? Constants.EDITOR_BGCOLOR_NIGHT_MODE_PROPERTY_NAME : Constants.EDITOR_BGCOLOR_PROPERTY_NAME, + UIUtils.colorToHex (this.getBackgroundColor ()))); + +/* + * + * + if (this.sideBar != null) + { + + this.sideBar.backgroundChanged (); + + } + + if (c.equals (this.getTextColor ())) + { + + if (c.equals (Color.black)) + { + + // Set the background to white. + this.setTextColor (Color.white); + + } + + if (c.equals (Color.white)) + { + + // Set the background to black. + this.setTextColor (Color.black); + + } + + } + */ +/* + this.setProperty (new StringProperty (Constants.EDITOR_FONT_BGCOLOR_PROPERTY_NAME, + UIUtils.colorToHex (this.getBackgroundColor ()))); + */ + } + + public void setHighlightWritingLine (boolean v) + { + + super.setHighlightWritingLine (v); + + this.setProperty (new BooleanProperty (Constants.EDITOR_HIGHLIGHT_WRITING_LINE_PROPERTY_NAME, + v)); + + } + + public void setWritingLineColor (Color c) + { + + super.setWritingLineColor (c); + + this.setProperty (new StringProperty (Environment.isNightModeEnabled () ? Constants.EDITOR_WRITING_LINE_COLOR_NIGHT_MODE_PROPERTY_NAME : Constants.EDITOR_WRITING_LINE_COLOR_PROPERTY_NAME, + UIUtils.colorToHex (this.getWritingLineColor ()))); + + } + + public void setTextColor (Color c) + { + + super.setTextColor (c); + + this.setProperty (new StringProperty (Environment.isNightModeEnabled () ? Constants.EDITOR_FONT_COLOR_NIGHT_MODE_PROPERTY_NAME : Constants.EDITOR_FONT_COLOR_PROPERTY_NAME, + UIUtils.colorToHex (this.getTextColor ()))); + + } + + public void setLineSpacing (float v) + { + + super.setLineSpacing (v); + + this.setProperty (new FloatProperty (Constants.EDITOR_LINE_SPACING_PROPERTY_NAME, + this.getLineSpacing ())); + + } + + public void setParagraphSpacing (float v) + { + + super.setParagraphSpacing (v); + + this.setProperty (new FloatProperty (Constants.EDITOR_PARAGRAPH_SPACING_PROPERTY_NAME, + this.getParagraphSpacing ())); + + } + + public void setFirstLineIndent (boolean v) + { + + super.setFirstLineIndent (v); + + this.setProperty (new BooleanProperty (Constants.EDITOR_INDENT_FIRST_LINE_PROPERTY_NAME, + this.getFirstLineIndent ())); + + } + + public void setAlignment (String v) + { + + super.setAlignment (v); + + this.setProperty (new StringProperty (Constants.EDITOR_ALIGNMENT_PROPERTY_NAME, + this.getAlignment ())); + + } + + public void setFontSize (int v) + { + + super.setFontSize (v); + + this.setProperty (new IntegerProperty (Constants.EDITOR_FONT_SIZE_PROPERTY_NAME, + this.getFontSize ())); + + } + + public void setFontFamily (String f) + { + + super.setFontFamily (f); + + this.setProperty (new StringProperty (Constants.EDITOR_FONT_PROPERTY_NAME, + this.getFontFamily ())); + + } + + public void setTextBorder (int v) + { + + super.setTextBorder (v); + + this.setProperty (new IntegerProperty (Constants.EDITOR_TEXT_BORDER_PROPERTY_NAME, + this.getTextBorder ())); + + } + + private void setProperty (AbstractProperty prop) + { + + if (!this.allowSet) + { + + return; + + } + + UserProperties.set (prop.getID (), + prop); + + } +/* + public void resetToDefaults () + { + + this.setBackgroundColor (UIUtils.hexToColor (UserProperties.get (Constants.DEFAULT_EDITOR_BGCOLOR_PROPERTY_NAME))); + this.setTextColor (UIUtils.hexToColor (UserProperties.get (Constants.DEFAULT_EDITOR_FONT_COLOR_PROPERTY_NAME))); + this.setTextBorder (UserProperties.getAsInt (Constants.DEFAULT_EDITOR_TEXT_BORDER_PROPERTY_NAME)); + this.setFontFamily (UserProperties.get (Constants.DEFAULT_EDITOR_FONT_PROPERTY_NAME)); + this.setFontSize (UserProperties.getAsInt (Constants.DEFAULT_EDITOR_FONT_SIZE_PROPERTY_NAME)); + this.setAlignment (Environment.getDefaultTextAlignment ()); + this.setFirstLineIndent (UserProperties.getAsBoolean (Constants.DEFAULT_EDITOR_INDENT_FIRST_LINE_PROPERTY_NAME)); + this.setLineSpacing (UserProperties.getAsFloat (Constants.DEFAULT_EDITOR_LINE_SPACING_PROPERTY_NAME)); + this.setParagraphSpacing (UserProperties.getAsFloat (Constants.DEFAULT_EDITOR_PARAGRAPH_SPACING_PROPERTY_NAME)); + this.setWritingLineColor (UIUtils.hexToColor (UserProperties.get (Constants.DEFAULT_EDITOR_WRITING_LINE_COLOR_PROPERTY_NAME))); + this.setHighlightWritingLine (UserProperties.getAsBoolean (Constants.DEFAULT_EDITOR_HIGHLIGHT_WRITING_LINE_PROPERTY_NAME)); + + } +*/ +} diff --git a/src/main/java/com/quollwriter/ui/fx/SceneItemFormatter.java b/src/main/java/com/quollwriter/ui/fx/SceneItemFormatter.java new file mode 100644 index 00000000..635e6142 --- /dev/null +++ b/src/main/java/com/quollwriter/ui/fx/SceneItemFormatter.java @@ -0,0 +1,60 @@ +package com.quollwriter.ui.fx; + +import javafx.beans.property.*; +import javafx.scene.Node; +import javafx.scene.control.*; +import javafx.scene.layout.*; + +import com.quollwriter.*; +import com.quollwriter.ui.fx.components.*; +import com.quollwriter.data.IPropertyBinder; +import com.quollwriter.data.Scene; +import com.quollwriter.ui.fx.viewers.*; + +public class SceneItemFormatter extends AbstractProjectItemFormatter +{ + + public SceneItemFormatter (ProjectViewer viewer, + IPropertyBinder binder, + com.quollwriter.data.Scene scene, + Runnable onNewPopupShown) + { + + super (viewer, + binder, + scene, + onNewPopupShown, + null); + + } + + @Override + public Node getContent () + { + + String desc = item.getDescription ().getMarkedUpText (); + + BasicHtmlTextFlow t = BasicHtmlTextFlow.builder () + .text (desc) + .styleClassName (StyleClassNames.DESCRIPTION) + .build (); + + return t; + + } + + public String getStyleClassName () + { + + return StyleClassNames.SCENE; + + } + + public StringProperty getPopupTitle () + { + + return Environment.getObjectTypeName (this.item); + + } + +} diff --git a/src/main/java/com/quollwriter/ui/fx/SpellCheckSupported.java b/src/main/java/com/quollwriter/ui/fx/SpellCheckSupported.java new file mode 100644 index 00000000..0d7b0255 --- /dev/null +++ b/src/main/java/com/quollwriter/ui/fx/SpellCheckSupported.java @@ -0,0 +1,15 @@ +package com.quollwriter.ui.fx; + +import com.quollwriter.*; + + +public interface SpellCheckSupported +{ + + public void setSpellCheckingEnabled (boolean v); + + public void setDictionaryProvider (DictionaryProvider2 dp); + + public void checkSpelling (); + +} diff --git a/src/main/java/com/quollwriter/ui/fx/SpellChecker.java b/src/main/java/com/quollwriter/ui/fx/SpellChecker.java new file mode 100644 index 00000000..6126aff4 --- /dev/null +++ b/src/main/java/com/quollwriter/ui/fx/SpellChecker.java @@ -0,0 +1,16 @@ +package com.quollwriter.ui.fx; + +import java.util.*; + +import com.quollwriter.text.*; + +public interface SpellChecker +{ + + public boolean isCorrect (Word word); + + public boolean isIgnored (Word word); + + public List getSuggestions (Word word); + +} diff --git a/src/main/java/com/quollwriter/ui/fx/State.java b/src/main/java/com/quollwriter/ui/fx/State.java new file mode 100644 index 00000000..8d4408ef --- /dev/null +++ b/src/main/java/com/quollwriter/ui/fx/State.java @@ -0,0 +1,462 @@ +package com.quollwriter.ui.fx; + +import java.util.*; + +import com.quollwriter.*; + +public class State +{ + + public static final String DEF_SEP = "|"; + + public enum Key + { + + scrollpanev, + content, + open; + + } + + private Map state = new LinkedHashMap<> (); + + public State () + { + + } + + public State (String s) + { + + if (s == null) + { + + return; + + } + + // Try json first. + try + { + + Map v = (Map) JSONDecoder.decode (s); + + Iterator it = v.keySet ().iterator (); + + while (it.hasNext ()) + { + + String k = it.next ().toString (); + Object val = v.get (k); + + this.state.put (k, val); + + } + + } catch (Exception e) { + + // Try the legacy method. + StringTokenizer t = new StringTokenizer (s, + String.valueOf ('\n')); + + while (t.hasMoreTokens ()) + { + + String tok = t.nextToken ().trim (); + + StringTokenizer tt = new StringTokenizer (tok, + "="); + + while (tt.hasMoreTokens ()) + { + + if (tt.countTokens () == 2) + { + + String name = tt.nextToken ().trim (); + String value = tt.nextToken ().trim (); + + this.state.put (name, + value); + + } else { + + break; + + } + + } + + } + + } + + } + + public Integer getAsInt (String name) + { + + return this.getAsInt (name, + null); + + } + + public Integer getAsInt (Key name, + Integer def) + { + + return this.getAsInt (name.name (), + def); + + } + + public Integer getAsInt (Key name) + { + + return this.getAsInt (name, + null); + + } + + public Integer getAsInt (String name, + Integer def) + { + + Number n = this.getAsNumber (name, + def); + + if (n != null) + { + + return n.intValue (); + + } + + return def; + + } + + public Float getAsFloat (Key name, + Float def) + { + + return this.getAsFloat (name.name (), + def); + + } + + public Float getAsFloat (String name, + Float def) + { + + Number n = this.getAsNumber (name, + def); + + if (n != null) + { + + return n.floatValue (); + + } + + return def; + + } + + public Double getAsDouble (String name, + Double def) + { + + Number n = this.getAsNumber (name, + def); + + if (n != null) + { + + return n.doubleValue (); + + } + + return def; + + } + + public Number getAsNumber (Key name, + Number def) + { + + try + { + + Number n = this.getAs (name.name (), + Number.class); + + if (n == null) + { + + return def; + + } + + return n; + + } catch (Exception e) { + + return def; + + } + + } + + public Number getAsNumber (String name, + Number def) + { + + return this.getAs (name, + Number.class); + + } + + public Boolean getAsBoolean (Key name) + { + + return this.getAsBoolean (name.name ()); + + } + + public Boolean getAsBoolean (Key name, + boolean def) + { + + return this.getAsBoolean (name.toString (), + def); + + } + + public Boolean getAsBoolean (String name) + { + + return this.getAsBoolean (name, + false); + + } + + public Boolean getAsBoolean (String name, + boolean def) + { + + try + { + + Boolean b = this.getAs (name, + Boolean.class); + + if (b == null) + { + + return def; + + } + + return b; + + } catch (IllegalStateException e) { + + return def; + + } + + } + + public T getAs (Key name, + Class expect) + { + + return this.getAs (name.name (), + expect); + + } + + public T getAs (String name, + Class expect) + { + + return this.checkGet (name, + expect); + + } + + public String getAsString (String name) + { + + return this.getAs (name, + String.class); + + } + + public State getAsState (Key name) + { + + return this.getAs (name, + State.class); + + } + + public State getAsState (String name) + { + + return this.getAs (name, + State.class); + + } + + public Set getAsSet (String name, + Class itemExpect) + { + + Object v = this.get (name); + + if (v == null) + { + + return null; + + } + + if (!Collection.class.isAssignableFrom (v.getClass ())) + { + + throw new IllegalArgumentException ("Unable to convert item data for: " + name + " to set of type: " + itemExpect.getName ()); + + } + + Collection c = (Collection) v; + + Set items = new LinkedHashSet<> (); + + for (Object o : c) + { + + if (!itemExpect.isAssignableFrom (o.getClass ())) + { + + throw new IllegalArgumentException ("Unable to convert collection item: " + o.getClass ().getName () + " to type: " + itemExpect.getName ()); + + } + + items.add ((T) o); + + } + + return items; + + } + + public List getAsList (String name, + Class itemExpect) + { + + Object v = this.get (name); + + if (v == null) + { + + return null; + + } + + if (!Collection.class.isAssignableFrom (v.getClass ())) + { + + throw new IllegalArgumentException ("Unable to convert item data for: " + name + " to set of type: " + itemExpect.getName ()); + + } + + Collection c = (Collection) v; + + List items = new ArrayList<> (); + + for (Object o : c) + { + + if (!itemExpect.isAssignableFrom (o.getClass ())) + { + + throw new IllegalArgumentException ("Unable to convert collection item: " + o.getClass ().getName () + " to type: " + itemExpect.getName ()); + + } + + items.add ((T) o); + + } + + return items; + + } + + private T checkGet (String name, + Class expect) + { + + Object v = this.get (name); + + if (v == null) + { + + return null; + + } + + if (!(expect.isAssignableFrom (v.getClass ()))) + { + + //throw new IllegalStateException ("Value for name: " + name + ", is type: " + v.getClass ().getName ()); + return null; + + } + + return expect.cast (v); + + } + + public Object get (String name) + { + + return this.state.get (name); + + } + + public void set (Key name, + Object value) + { + + this.set (name.toString (), + value); + + } + + public void set (String name, + Object value) + { + + this.state.put (name, + value); + + } + + public String toString () + { + + return this.getClass ().getName () + "(" + this.state + ")"; + + } + + public String asString () + throws GeneralException + { + + return JSONEncoder.encode (this.state); + + } + +} diff --git a/src/main/java/com/quollwriter/ui/fx/Stateful.java b/src/main/java/com/quollwriter/ui/fx/Stateful.java new file mode 100644 index 00000000..22efd833 --- /dev/null +++ b/src/main/java/com/quollwriter/ui/fx/Stateful.java @@ -0,0 +1,15 @@ +package com.quollwriter.ui.fx; + +import java.util.*; + +import com.quollwriter.*; + +public interface Stateful +{ + + public void init (State state) + throws GeneralException; + + public State getState (); + +} diff --git a/src/main/java/com/quollwriter/ui/fx/StyleClassNames.java b/src/main/java/com/quollwriter/ui/fx/StyleClassNames.java new file mode 100644 index 00000000..06297338 --- /dev/null +++ b/src/main/java/com/quollwriter/ui/fx/StyleClassNames.java @@ -0,0 +1,514 @@ +package com.quollwriter.ui.fx; + +import javafx.css.*; + +public final class StyleClassNames +{ + + public static final PseudoClass DEALTWITH_PSEUDO_CLASS = PseudoClass.getPseudoClass (StyleClassNames.DEALTWITH); + public static final PseudoClass TYPEWRITER_SCROLLING_PSEUDO_CLASS = PseudoClass.getPseudoClass (StyleClassNames.TYPEWRITER_SCROLLING); + public static final PseudoClass HASPARENT_PSEUDO_CLASS = PseudoClass.getPseudoClass (StyleClassNames.HASPARENT); + public static final PseudoClass FOCUSED_PSEUDO_CLASS = PseudoClass.getPseudoClass (StyleClassNames.FOCUSED); + public static final PseudoClass NEEDS_SAVE_PSEUDO_CLASS = PseudoClass.getPseudoClass (StyleClassNames.NEEDSSAVE); + public static final PseudoClass HASSTYLES_PSEUDO_CLASS = PseudoClass.getPseudoClass (StyleClassNames.HASSTYLES); + public static final PseudoClass NOSTYLES_PSEUDO_CLASS = PseudoClass.getPseudoClass (StyleClassNames.NOSTYLES); + public static final PseudoClass COLUMN_PSEUDO_CLASS = PseudoClass.getPseudoClass (StyleClassNames.COLUMN); + public static final PseudoClass STACKED_PSEUDO_CLASS = PseudoClass.getPseudoClass (StyleClassNames.STACKED); + public static final PseudoClass NOAVATAR_PSEUDO_CLASS = PseudoClass.getPseudoClass (StyleClassNames.NOAVATAR); + public static final PseudoClass OK_PSEUDO_CLASS = PseudoClass.getPseudoClass (StyleClassNames.OK); + public static final PseudoClass ERROR_PSEUDO_CLASS = PseudoClass.getPseudoClass (StyleClassNames.ERROR); + public static final PseudoClass SELECTED_PSEUDO_CLASS = PseudoClass.getPseudoClass (StyleClassNames.SELECTED); + public static final PseudoClass TEMP_SELECTED_PSEUDO_CLASS = PseudoClass.getPseudoClass (StyleClassNames.TEMPSELECTED); + public static final PseudoClass BGIMAGE_PSEUDO_CLASS = PseudoClass.getPseudoClass (StyleClassNames.BGIMAGE); + public static final PseudoClass BGCOLOR_PSEUDO_CLASS = PseudoClass.getPseudoClass (StyleClassNames.BGCOLOR); + public static final PseudoClass NIGHT_MODE_PSEUDO_CLASS = PseudoClass.getPseudoClass (StyleClassNames.NIGHT); + public static final PseudoClass USERIMAGE_PSEUDO_CLASS = PseudoClass.getPseudoClass (StyleClassNames.USERIMAGE); + public static final PseudoClass ACHIEVED_PSEUDO_CLASS = PseudoClass.getPseudoClass (StyleClassNames.ACHIEVED); + public static final PseudoClass EXPANDED_PSEUDO_CLASS = PseudoClass.getPseudoClass (StyleClassNames.EXPANDED); + public static final PseudoClass LEAF_PSEUDO_CLASS = PseudoClass.getPseudoClass (StyleClassNames.LEAF); + public static final PseudoClass BRANCH_PSEUDO_CLASS = PseudoClass.getPseudoClass (StyleClassNames.BRANCH); + public static final PseudoClass OPEN_PSEUDO_CLASS = PseudoClass.getPseudoClass (StyleClassNames.OPEN); + public static final PseudoClass CLOSED_PSEUDO_CLASS = PseudoClass.getPseudoClass (StyleClassNames.CLOSED); + public static final PseudoClass SCROLLING_PSEUDO_CLASS = PseudoClass.getPseudoClass (StyleClassNames.SCROLLING); + public static final PseudoClass COMPRESSED_PSEUDO_CLASS = PseudoClass.getPseudoClass (StyleClassNames.COMPRESSED); + public static final PseudoClass DRAGGING_PSEUDO_CLASS = PseudoClass.getPseudoClass (StyleClassNames.DRAGGING); + public static final PseudoClass DRAGOVER_PSEUDO_CLASS = PseudoClass.getPseudoClass (StyleClassNames.DRAGOVER); + public static final PseudoClass EDITPOSITION_PSEUDO_CLASS = PseudoClass.getPseudoClass (StyleClassNames.EDITPOSITION); + public static final PseudoClass EDITCOMPLETE_PSEUDO_CLASS = PseudoClass.getPseudoClass (StyleClassNames.EDITCOMPLETE); + public static final PseudoClass ENABLED_PSEUDO_CLASS = PseudoClass.getPseudoClass (StyleClassNames.ENABLED); + public static final PseudoClass DISABLED_PSEUDO_CLASS = PseudoClass.getPseudoClass (StyleClassNames.DISABLED); + public static final PseudoClass LEFT_PSEUDO_CLASS = PseudoClass.getPseudoClass (StyleClassNames.LEFT); + public static final PseudoClass FIRST_PSEUDO_CLASS = PseudoClass.getPseudoClass (StyleClassNames.FIRST); + public static final PseudoClass LAST_PSEUDO_CLASS = PseudoClass.getPseudoClass (StyleClassNames.LAST); + public static final PseudoClass EDITED_PSEUDO_CLASS = PseudoClass.getPseudoClass (StyleClassNames.EDITED); + public static final PseudoClass HASCHANGES_PSEUDO_CLASS = PseudoClass.getPseudoClass (StyleClassNames.HASCHANGES); + public static final PseudoClass NOIMAGE_PSEUDO_CLASS = PseudoClass.getPseudoClass (StyleClassNames.NOIMAGE); + public static final PseudoClass HIDELABELS_PSUEDO_CLASS = PseudoClass.getPseudoClass (StyleClassNames.HIDELABELS); + public static final PseudoClass INVALID_PSUEDO_CLASS = PseudoClass.getPseudoClass (StyleClassNames.INVALID); + public static final PseudoClass NORMAL_PSUEDO_CLASS = PseudoClass.getPseudoClass (StyleClassNames.NORMAL); + public static final PseudoClass UNDEALTWITH_PSEUDO_CLASS = PseudoClass.getPseudoClass (StyleClassNames.UNDEALTWITH); + public static final PseudoClass ATTENTIONREQUIRED_PSEUDO_CLASS = PseudoClass.getPseudoClass (StyleClassNames.ATTENTIONREQUIRED); + + public static final String FILTER = "filter"; + public static final String FOCUSED = "focused"; + public static final String TYPEWRITER_SCROLLING = "typewriterscrolling"; + public static final String NEEDSSAVE = "needssave"; + public static final String NOSECTIONS = "nosections"; + public static final String TIMESELECT = "timeselect"; + public static final String STRING = "string"; + public static final String FORWARD = "forward"; + public static final String NODE = "node"; + public static final String SECTION = "section"; + public static final String LANGUAGESTRINGS = "languagestrings"; + public static final String SUBMIT = "submit"; + public static final String TRYOUT = "tryout"; + public static final String AVERAGEFK = "averagefk"; + public static final String AVERAGEGF = "averagegf"; + public static final String TARGETFK = "targetfk"; + public static final String TARGETGF = "targetgf"; + public static final String SELECT = "select"; + public static final String TARGET = "target"; + public static final String AVERAGE = "average"; + public static final String PROMPT = "prompt"; + public static final String QTOOLBAR = "qtoolbar"; + public static final String EDITORREMOVED = "editorremoved"; + public static final String NEWPROJECTRESPONSE = "newprojectresponse"; + public static final String PROJECTCOMMENTS = "projectcomments"; + public static final String STYLESHEETS = "stylesheets"; + public static final String PROPERTIES = "properties"; + public static final String HASSTYLES = "hasstyles"; + public static final String NOSTYLES = "nostyles"; + public static final String CSS = "css"; + public static final String CSSNODE = "cssnode"; + public static final String PROJECTMESSAGES = "projectmessages"; + public static final String EDITORPROJECT = "editorproject"; + public static final String PROJECTVERSIONINFO = "projectversioninfo"; + public static final String VIEWPROJECT = "viewproject"; + public static final String EDITORMESSAGES = "editormessages"; + public static final String USER = "user"; + public static final String CHATBOX = "chatbox"; + public static final String NOAVATAR = "noavatar"; + public static final String SETUNDEALTWITH = "setundealtwith"; + public static final String SETDEALTWITH = "setdealtwith"; + public static final String EDITORREGISTER = "editorregister"; + public static final String OK = "ok"; + public static final String SECTIONTITLE = "sectiontitle"; + public static final String MARGINBG = "margin-bg"; + public static final String SHOWPASSWORD = "showpassword"; + public static final String RESETPASSWORD = "resetpassword"; + public static final String RESENDCONFIRMEMAIL = "resendconfirmemail"; + public static final String UPDATEINFO = "updateinfo"; + public static final String LOGOUT = "logout"; + public static final String LOGIN = "login"; + public static final String PENDINGINVITES = "pendinginvites"; + public static final String OTHERCOMMENTS = "othercomments"; + public static final String WHEN = "when"; + public static final String VERSION = "version"; + public static final String FIRSTLOGIN = "firstlogin"; + public static final String NOEDITORS = "noeditors"; + public static final String INVITESFORME = "invitesforme"; + public static final String ALLCONTACTS = "allcontacts"; + public static final String EDITORS = "editors"; + public static final String SENDINVITE = "sendinvite"; + public static final String CHATMESSAGES = "chatmessages"; + public static final String TYPING = "typing"; + public static final String SENDING = "sending"; + public static final String PREVIOUSCONTACTS = "previouscontacts"; + public static final String DELETEACCOUNT = "deleteaccount"; + public static final String PREVIOUSEDITORS = "previouseditors"; + public static final String CHATMESSAGE = "chatmessage"; + public static final String STATUSBAR = "statusbar"; + public static final String ATTENTIONREQUIRED = "attentionrequired"; + public static final String ONLINESTATUS = "onlinestatus"; + public static final String UNDEALTWITH = "undealtwith"; + public static final String DEALTWITH = "dealtwith"; + public static final String COMMENT = "comment"; + public static final String NOTIFY = "notify"; + public static final String MESSAGE = "message"; + public static final String AVATAR = "avatar"; + public static final String CONTACT = "contact"; + public static final String INVITEEDITOR = "inviteeditor"; + public static final String CHANGEPASSWORD = "changepassword"; + public static final String SEND = "send"; + public static final String INVITEMESSAGE = "invitemessage"; + public static final String ACCEPT = "accept"; + public static final String NEWPROJECTMESSAGE = "newprojectmessage"; + public static final String STOPPED = "stopped"; + public static final String ACCEPTED = "accepted"; + public static final String REJECTED = "rejected"; + public static final String EDITORINFO = "editorinfo"; + public static final String EDITORLOGIN = "editorlogin"; + public static final String MESSAGEDETAILS = "messagedetails"; + public static final String RESPONSE = "response"; + public static final String UPDATEPROJECTMESSAGE = "updateprojectmessage"; + public static final String REPORTMESSAGE = "reportmessage"; + public static final String IMPORTANT = "important"; + public static final String COMMENTS = "comments"; + public static final String MOVE = "move"; + public static final String MOVEVERT = "movevert"; + public static final String MOVETOP = "movetop"; + public static final String MOVEBOTTOM = "movebottom"; + public static final String MOVEUP = "moveup"; + public static final String MOVEDOWN = "movedown"; + public static final String QW = "qw"; + public static final String NEWASSET = "newasset"; + public static final String SPLITCHAPTER = "splitchapter"; + public static final String SUN = "sun"; + public static final String MOON = "moon"; + public static final String DICTIONARY = "dictionary"; + public static final String ICONBOX = "iconbox"; + public static final String PLAY = "play"; + public static final String PAUSE = "pause"; + public static final String TIMER = "timer"; + public static final String WINDOWED = "windowed"; + public static final String TAGSMANAGER = "tagsmanager"; + public static final String NEWPROJECT = "newproject"; + public static final String PROGRESS = "progress"; + public static final String LOADING = "loading"; + public static final String FIRSTUSEWIZARD = "firstusewizard"; + public static final String INNER = "inner"; + public static final String BACKGROUNDSIZEBOX = "backgroundsizebox"; + public static final String DOCUMENTS = "documents"; + public static final String FILES = "files"; + public static final String FILE = "file"; + public static final String INVALID = "invalid"; + public static final String VIEWERCONTENT = "viewercontent"; + public static final String DIVIDER = "divider"; + public static final String BIGICON = "bigicon"; + public static final String SMALLICON = "smallicon"; + public static final String WEBSITELANGSTRINGSSELECT = "websitelangstringsselect"; + public static final String ADDNEWWEBSITELANGSTRINGS = "addnewwebsitelangstrings"; + public static final String START = "start"; + public static final String WEBSITE = "website"; + public static final String POPUPVIEWER = "popupviewer"; + public static final String PASSWORDENTRY = "passwordentry"; + public static final String NOTETYPESMANAGER = "notetypesmanager"; + public static final String CREATEASSET = "createasset"; + public static final String ASSETS = "assets"; + public static final String FIELDS = "fields"; + public static final String HIDELABELS = "hidelabels"; + public static final String OVERLAY = "overlay"; + public static final String ERRORS = "errors"; + public static final String FIELD = "field"; + public static final String APPEARSINCHAPTERS = "appearsinchapters"; + public static final String FULL = "full"; + public static final String SINGLE = "single"; + public static final String BULLET = "bullet"; + public static final String OBJECTSELECT = "objectselect"; + public static final String TOP = "top"; + public static final String BOTTOM = "bottom"; + public static final String ASSETLAYOUT0 = "assetlayout0"; + public static final String ASSETLAYOUT1 = "assetlayout1"; + public static final String ASSETLAYOUT2 = "assetlayout2"; + public static final String ASSETLAYOUT3 = "assetlayout3"; + public static final String ASSETLAYOUT4 = "assetlayout4"; + public static final String ASSETLAYOUT5 = "assetlayout5"; + public static final String ASSETLAYOUT6 = "assetlayout6"; + public static final String ASSETLAYOUT7 = "assetlayout7"; + public static final String ASSETLAYOUT8 = "assetlayout8"; + public static final String OBJECTDESCRIPTION = "objectdescription"; + public static final String OBJECTIMAGE = "objectimage"; + public static final String HYPERLINK = "hyperlink"; + public static final String FOLDER = "folder"; + public static final String BULLETS = "bullets"; + public static final String OBJECTNAME = "objectname"; + public static final String NEWIDEA = "newidea"; + public static final String IDEAS = "ideas"; + public static final String STARBAR = "starbar"; + public static final String SHORTTEXT = "shorttext"; + public static final String FULLTEXT = "fulltext"; + public static final String UP = "up"; + public static final String CONVERT = "convert"; + public static final String IDEA = "idea"; + public static final String IDEATYPE = "ideatype"; + public static final String DATE = "date"; + public static final String STAR = "star"; + public static final String ALPHA = "alpha"; + public static final String CATEGORIES = "categories"; + public static final String FINDBOX = "findbox"; + public static final String SNIPPET = "snippet"; + public static final String RESULTS = "results"; + public static final String ISSUES = "issues"; + public static final String ISSUE = "issue"; + public static final String RULE = "rule"; + public static final String DETAILS = "details"; + public static final String SEARCHING = "searching"; + public static final String IGNORED = "ignored"; + public static final String NOMATCHES = "nomatches"; + public static final String REFRESH = "refresh"; + public static final String NOPROBLEMS = "noproblems"; + public static final String FINISH = "finish"; + public static final String IGNORE = "ignore"; + public static final String EDITMARKER = "editmarker"; + public static final String WORDS = "words"; + public static final String PARAGRAPHS = "paragraphs"; + public static final String SENTENCES = "sentences"; + public static final String SYNONYMS = "synonyms"; + public static final String SEPARATOR = "separator"; + public static final String EDITED = "edited"; + public static final String CHAPTERITEM = "chapteritem"; + public static final String LINK = "link"; + public static final String FIRST = "first"; + public static final String LAST = "last"; + public static final String MARGIN = "margin"; + public static final String TEXTEDITOR = "texteditor"; + public static final String LEFT = "left"; + public static final String LINESPACING = "linespacing"; + public static final String PARAGRAPHSPACING = "paragraphspacing"; + public static final String TEXTBORDER = "textborder"; + public static final String FONTSIZE = "fontsize"; + public static final String FONTFAMILY = "fontfamily"; + public static final String SHOWINGINFULLSCREEN = "showinginfullscreen"; + public static final String FULLSCREEN = "fullscreen"; + public static final String DISTRACTIONFREEEXIT = "distractionfreeexit"; + public static final String DISTRACTIONFREEENTER = "distractionfreeenter"; + public static final String FULLSCREENEXIT = "fullscreenexit"; + public static final String CLOCK = "clock"; + public static final String EDITCHAPTER = "editchapter"; + public static final String CUT = "cut"; + public static final String COPY = "copy"; + public static final String PASTE = "paste"; + public static final String UNDO = "undo"; + public static final String REDO = "redo"; + public static final String BOLD = "bold"; + public static final String ITALIC = "italic"; + public static final String UNDERLINE = "underline"; + public static final String COMPRESSEDMENUTITLE = "compressedmenutitle"; + public static final String SETEDITPOSITION = "seteditposition"; + public static final String SPLIT = "split"; + public static final String ADDWORD = "addword"; + public static final String NOSYNONYMS = "nosynonyms"; + public static final String NOSUGGESTIONS = "nosuggestions"; + public static final String OUTLINEITEM = "outlineitem"; + public static final String SCENE = "scene"; + public static final String ALLCHAPTERS = "allchapters"; + public static final String SUBTITLE = "subtitle"; + public static final String SESSION = "session"; + public static final String VALUE = "value"; + public static final String VALUELABEL = "valuelabel"; + public static final String LINKEDTO = "linkedto"; + public static final String DELETECHAPTER = "deletechapter"; + public static final String CREATECHAPTER = "createchapter"; + public static final String OVER = "over"; + public static final String EXPORT = "export"; + public static final String PROBLEMFINDER = "problemfinder"; + public static final String PROBLEMFINDERCONFIG = "problemfinderconfig"; + public static final String RULES = "rules"; + public static final String PRINT = "print"; + public static final String EDITPROPERTIES = "editproperties"; + public static final String EDITNEEDEDNOTE = "editneedednote"; + public static final String SPELLCHECK = "spellcheck"; + public static final String SPELLCHECKON = "spellcheckon"; + public static final String SPELLCHECKOFF = "spellcheckoff"; + public static final String TOOLS = "tools"; + public static final String ENABLED = "enabled"; + public static final String DISABLED = "disabled"; + public static final String FULLSCREENENTER = "fullscreenenter"; + public static final String EDITPOSITION = "editposition"; + public static final String RENAME = "rename"; + public static final String EDITNEEDED = "editneeded"; + public static final String GOTOEDITPOSITION = "gotoeditposition"; + public static final String REMOVEEDITPOSITION = "removeeditposition"; + public static final String EDITCOMPLETE = "editcomplete"; + public static final String NOTES = "notes"; + public static final String NOTE = "note"; + public static final String SORT = "sort"; + public static final String TAG = "tag"; + public static final String DRAGOVER = "dragover"; + public static final String DRAGGING = "dragging"; + public static final String DETAIL = "detail"; + public static final String PREVIEW = "preview"; + public static final String STACKED = "stacked"; + public static final String COLUMN = "column"; + public static final String LESS = "less"; + public static final String MORE = "more"; + public static final String TEXTSIZE = "textsize"; + public static final String SWATCHES = "swatches"; + public static final String EDITPOSITIONCOLORSWATCH = "editpositioncolorswatch"; + public static final String COLORSWATCH = "colorswatch"; + public static final String CHAPTERICONSEXAMPLE = "chaptericonsexample"; + public static final String DICTIONARYMANAGER = "dictionarymanager"; + public static final String COMPRESSED = "compressed"; + public static final String COMPRESSCHAPTERCONTEXTEXAMPLE = "compresschaptercontextexample"; + public static final String EDITPOSITIONEXAMPLE = "editpositionexample"; + public static final String EDITING = "editing"; + public static final String SCROLLING = "scrolling"; + public static final String OBJECTTYPENAMECHANGE = "objecttypenamechange"; + public static final String NAMING = "naming"; + public static final String OWNSOUND = "ownsound"; + public static final String CLEAR = "clear"; + public static final String ADDNEWUILANGSTRINGS = "addnewuilangstrings"; + public static final String UILANGSTRINGSSELECT = "uilangstringsselect"; + public static final String CONTACTUILANGCREATOR = "contactuilangcreator"; + public static final String PROJECTITEMPREVIEW = "projectitempreview"; + public static final String LAYOUTSELECTOR = "layoutselector"; + public static final String LAYOUT = "layout"; + public static final String TABS = "tabs"; + public static final String SECTIONS = "sections"; + public static final String LOOKS = "looks"; + public static final String CLOSED = "closed"; + public static final String MAIN = "main"; + public static final String SUB = "sub"; + public static final String USERIMAGE = "userimage"; + public static final String NIGHT = "night"; + public static final String IMAGE = "image"; + public static final String SPLASHSCREEN = "splashscreen"; + public static final String BACKGROUND = "background"; + public static final String BGIMAGE = "bgimage"; + public static final String BGCOLOR = "bgcolor"; + public static final String SELECTED = "selected"; + public static final String TEMPSELECTED = "tempselected"; + public static final String CONTENT = "content"; + public static final String CLOSE = "close"; + public static final String DEBUG = "debug"; + public static final String VIEWER = "viewer"; + public static final String SIDEBARS = "sidebars"; + public static final String SIDEBAR = "sidebar"; + public static final String PANELS = "panels"; + public static final String HEADER = "header"; + public static final String ERROR = "error"; + public static final String PANEL = "panel"; + public static final String TIPS = "tips"; + public static final String NEXT = "next"; + public static final String STOP = "stop"; + public static final String QUESTION = "question"; + public static final String CONTACTS = "contacts"; + public static final String CONTEXTMENU = "contextmenu"; + public static final String BUG = "bug"; + public static final String WARMUP = "warmup"; + public static final String OPTIONS = "options"; + public static final String ACHIEVEMENTS = "achievements"; + public static final String WHATSNEW = "whatsnew"; + public static final String HELP = "help"; + public static final String REPORTBUG = "reportbug"; + public static final String CONTACTSUPPORT = "contactsupport"; + public static final String VIEWUSERGUIDE = "viewuserguide"; + public static final String KEYBOARDSHORTCUTS = "keyboardshortcuts"; + public static final String ABOUT = "about"; + public static final String DEBUGCONSOLE = "debugconsole"; + public static final String IDEABOARD = "ideaboard"; + public static final String ALLPROJECTS = "allprojects"; + public static final String OTHERSIDEBARS = "othersidebars"; + public static final String OTHER = "other"; + public static final String HASCHANGES = "haschanges"; + public static final String SAVE = "save"; + public static final String TOOLBAR = "toolbar"; + public static final String NOPROJECTS = "noprojects"; + public static final String FORM = "form"; + public static final String SUMMARY = "summary"; + public static final String DESCRIPTION = "description"; + public static final String BUTTONS = "buttons"; + public static final String CONTROL = "control"; + public static final String LABEL = "label"; + public static final String ITEMS = "items"; + public static final String CONFIRM = "confirm"; + public static final String CANCEL = "cancel"; + public static final String ACCORDION = "accordion"; + public static final String CHAPTERINFO = "chapterinfo"; + public static final String PLAN = "plan"; + public static final String GOALS = "goals"; + public static final String EDIT = "edit"; + public static final String ASSET = "asset"; + public static final String PLACEHOLDER = "placeholder"; + public static final String VIEW = "view"; + public static final String CHAPTER = "chapter"; + public static final String WORDCOUNTS = "wordcounts"; + public static final String READABILITY = "readability"; + public static final String INFORMATION = "information"; + public static final String DOWNLOAD = "download"; + public static final String EDITOR = "editor"; + public static final String PROJECT = "project"; + public static final String NOTIFICATIONS = "notifications"; + public static final String VIEWERMENU = "viewermenu"; + public static final String PROJECTSLIST = "projectslist"; + public static final String TITLE = "title"; + public static final String CONTROLS = "controls"; + public static final String ICON = "icon"; + public static final String ICON_SUFFIX = "-" + ICON; + public static final String ENCRYPTED = "encrypted"; + public static final String ADD = "add"; + public static final String IMPORT = "import"; + public static final String IMPORTFILE = "importfile"; + public static final String NORMAL = "normal"; + public static final String CHANGEDISPLAY = "changedisplay"; + public static final String MANAGESTATUSES = "managestatuses"; + public static final String WORDCOUNT = "wordcount"; + public static final String STATUS = "status"; + public static final String NAME = "name"; + public static final String LASTEDITED = "lastedited"; + public static final String SORTMENU = "sortmenu"; + public static final String FIND = "find"; + public static final String SELECTBG = "selectbg"; + public static final String NOVALUE = "novalue"; + public static final String DELETE = "delete"; + public static final String SHOWFOLDER = "showfolder"; + public static final String MANAGEBACKUPS = "managebackups"; + public static final String CREATEBACKUP = "createbackup"; + public static final String NEWSTATUS = "newstatus"; + public static final String SETSTATUS = "setstatus"; + public static final String OPEN = "open"; + public static final String REMOVE = "remove"; + public static final String NOTIFICATION = "notification"; + public static final String TARGETS = "targets"; + public static final String NEW = "new"; + public static final String STATISTICS = "statistics"; + public static final String QPOPUP = "qpopup"; + public static final String INFO = "info"; + public static final String MAX = "max"; + public static final String QTEXTVIEW = "qtextview"; + public static final String QTEXTAREA = "qtextarea"; + public static final String EMAIL = "email"; + public static final String CREATEPROJECT = "createproject"; + public static final String PASSWORDS = "passwords"; + public static final String FILEFIND = "filefind"; + public static final String FINDPROJECTS = "findprojects"; + public static final String RESET = "reset"; + public static final String ITEM = "item"; + public static final String COLORS = "colors"; + public static final String IMAGES = "images"; + public static final String COLORCHOOSER = "colorchooser"; + public static final String TYPE = "type"; + public static final String PROJECTSTATUSES = "projectstatuses"; + public static final String ITEMMANAGER = "itemmanager"; + public static final String CURRENT = "current"; + public static final String NOIMAGE = "noimage"; + public static final String NOBACKUPS = "nobackups"; + public static final String RESTORE = "restore"; + public static final String BACKUPS = "backups"; + public static final String PASSWORD = "password"; + public static final String BACKUPCREATED = "backupcreated"; + public static final String A = "a"; + public static final String FORMAT = "format"; + public static final String EXAMPLE = "example"; + public static final String CHANGEPROJECTDISPLAY = "changeprojectdisplay"; + public static final String TEXTENTRY = "textentry"; + public static final String WARNING = "warning"; + public static final String WIZARD = "wizard"; + public static final String WEBLINKS = "weblinks"; + public static final String PREVIOUS = "previous"; + public static final String DOWARMUP = "dowarmup"; + public static final String CHOOSEPROMPT = "chooseprompt"; + public static final String OWNPROMPT = "ownprompt"; + public static final String TEXT = "text"; + public static final String CONFIG = "config"; + public static final String CHART = "chart"; + public static final String MYWRITING = "mywriting"; + public static final String CHAPTERS = "chapters"; + public static final String OVER25PERC = "over25perc"; + public static final String COUNT = "count"; + public static final String GENERAL = "general"; + public static final String ACHIEVED = "achieved"; + public static final String ACHIEVEMENT = "achievement"; + public static final String HIDE = "hide"; + public static final String SHOW = "show"; + public static final String POPUPPANE = "popuppane"; + public static final String RADIOBUTTONS = "radiobuttons"; + public static final String PROJECTS = "projects"; + public static final String EXPANDED = "expanded"; + public static final String TREE = "tree"; + public static final String CELL = "cell"; + public static final String LEAF = "leaf"; + public static final String BRANCH = "branch"; + public static final String HASPARENT = "hasparent"; + +} diff --git a/src/main/java/com/quollwriter/ui/fx/TextProperties.java b/src/main/java/com/quollwriter/ui/fx/TextProperties.java new file mode 100644 index 00000000..340dc857 --- /dev/null +++ b/src/main/java/com/quollwriter/ui/fx/TextProperties.java @@ -0,0 +1,708 @@ +package com.quollwriter.ui.fx; + +import javafx.beans.property.*; +import javafx.scene.paint.*; + +public class TextProperties implements TextStylable +{ + + private TextStylable setOn = null; + private String fontFamily = null; + private StringProperty fontFamilyProp = null; + private int fontSize = -1; + private IntegerProperty fontSizeProp = null; + private String alignment = null; + private StringProperty alignmentProp = null; + private boolean firstLineIndent = false; + private BooleanProperty firstLineIndentProp = null; + private float lineSpacing = 0; + private FloatProperty lineSpacingProp = null; + private Color textColor = null; + private ObjectProperty textColorProp = null; + private Color bgColor = null; + private ObjectProperty bgColorProp = null; + private Color writingLineColor = null; + private ObjectProperty writingLineColorProp = null; + private boolean highlightWritingLine = false; + private BooleanProperty highlightWritingLineProp = null; + private int textBorder = 0; + private IntegerProperty textBorderProp = null; + + private FloatProperty paragraphSpacingProp = null; + + public TextProperties () + { + + this.fontFamilyProp = new SimpleStringProperty (); + this.fontSizeProp = new SimpleIntegerProperty (); + this.alignmentProp = new SimpleStringProperty (); + this.firstLineIndentProp = new SimpleBooleanProperty (); + this.lineSpacingProp = new SimpleFloatProperty (); + this.textColorProp = new SimpleObjectProperty<> (); + this.bgColorProp = new SimpleObjectProperty<> (); + this.writingLineColorProp = new SimpleObjectProperty<> (); + this.highlightWritingLineProp = new SimpleBooleanProperty (); + this.textBorderProp = new SimpleIntegerProperty (); + this.paragraphSpacingProp = new SimpleFloatProperty (1f); + + } +/* + public TextProperties (TextStylable setOn) + { + + this.setOn = setOn; + + } +*/ + public TextProperties (TextProperties props) + { + + this (props.setOn, + props.fontFamily, + props.fontSize, + props.alignment, + props.firstLineIndent, + props.lineSpacing, + props.paragraphSpacingProp.getValue (), + props.textColor, + props.bgColor, + props.writingLineColor, + props.highlightWritingLine, + props.textBorder); + + } + + public TextProperties (TextStylable setOn, + String fontFamily, + int fontSize, + String alignment, + boolean firstLineIndent, + float lineSpacing, + float paraSpacing, + Color writingLineColor, + boolean highlightWritingLine, + int textBorder) + { + + this (setOn, + fontFamily, + fontSize, + alignment, + firstLineIndent, + lineSpacing, + paraSpacing, + null, + null, + writingLineColor, + highlightWritingLine, + textBorder); + + } + + public TextProperties (TextStylable setOn, + String fontFamily, + int fontSize, + String alignment, + boolean firstLineIndent, + float lineSpacing, + float paraSpacing, + Color textColor, + Color bgColor, + Color writingLineColor, + boolean highlightWritingLine, + int textBorder) + { + + //this (setOn); + + this (); + + this.initInternal (fontFamily, + fontSize, + alignment, + firstLineIndent, + lineSpacing, + paraSpacing, + textColor, + bgColor, + writingLineColor, + highlightWritingLine, + textBorder); + + } + + protected void initInternal (TextProperties props) + { + + //this.setOn = props.setOn; + + this.initInternal (props.fontFamily, + props.fontSize, + props.alignment, + props.firstLineIndent, + props.lineSpacing, + props.paragraphSpacingProp.getValue (), + props.textColor, + props.bgColor, + props.writingLineColor, + props.highlightWritingLine, + props.textBorder); + + } + + protected void initInternal (String fontFamily, + int fontSize, + String alignment, + boolean firstLineIndent, + float lineSpacing, + float paraSpacing, + Color textColor, + Color bgColor, + Color writingLineColor, + boolean highlightWritingLine, + int textBorder) + { + + this.setFontFamily (fontFamily); + //this.fontFamily = fontFamily; + this.setFontSize (fontSize); + this.setAlignment (alignment); + this.setFirstLineIndent (firstLineIndent); + this.setLineSpacing (lineSpacing); + this.setParagraphSpacing (paraSpacing); + this.setTextColor (textColor); + this.setBackgroundColor (bgColor); + this.setWritingLineColor (writingLineColor); + this.setHighlightWritingLine (highlightWritingLine); + this.setTextBorder (textBorder); + + } + + public void setOn (TextStylable s, + boolean init) + { + + this.setOn = s; + + if (init) + { + + this.setFontFamily (this.fontFamily); + this.setFontSize (this.fontSize); + this.setAlignment (this.alignment); + this.setFirstLineIndent (this.firstLineIndent); + this.setLineSpacing (this.lineSpacing); + this.setParagraphSpacing (this.paragraphSpacingProp.getValue ()); + this.setTextColor (this.textColor); + this.setBackgroundColor (this.bgColor); + this.setWritingLineColor (this.writingLineColor); + this.setHighlightWritingLine (this.highlightWritingLine); + this.setTextBorder (this.textBorder); + + } + + } + + public boolean isHighlightWritingLine () + { + + return this.highlightWritingLine; + + } + + public BooleanProperty highlightWritingLineProperty () + { + + return this.highlightWritingLineProp; + + } + + public void setHighlightWritingLine (boolean v) + { + + this.highlightWritingLine = v; + this.highlightWritingLineProp.setValue (v); + +/* +TODO Remove? + if (this.setOn != null) + { + + this.setOn.setHighlightWritingLine (v); + + } +*/ + } + + public int getTextBorder () + { + + return this.textBorder; + + } + + public IntegerProperty textBorderProperty () + { + + return this.textBorderProp; + + } + + public void setTextBorder (int v) + { + + this.textBorder = v; + this.textBorderProp.setValue (v); + +/* +TODO Remove? + if (this.setOn != null) + { + + this.setOn.setTextBorder (v); + + } +*/ + } + + public ObjectProperty writingLineColorProperty () + { + + return this.writingLineColorProp; + + } + + public void setWritingLineColor (Color c) + { + + this.writingLineColor = c; + this.writingLineColorProp.setValue (c); + +/* +TODO Remove? + if ((this.setOn != null) + && + (this.writingLineColor != null) + ) + { + + this.setOn.setWritingLineColor (c); + + } +*/ + } + + public Color getWritingLineColor () + { + + return this.writingLineColor; + + } + + public String getFontFamily () + { + + return this.fontFamily; + + } + + public StringProperty fontFamilyProperty () + { + + return this.fontFamilyProp; + + } + + public void setFontFamily (String f) + { + + this.fontFamily = f; + this.fontFamilyProp.setValue (f); + +/* +TODO REmove? + if ((this.setOn != null) + && + (this.fontFamily != null) + ) + { + + this.setOn.setFontFamily (f); + + } +*/ + } + + public int getFontSize () + { + + return this.fontSize; + + } + + public IntegerProperty fontSizeProperty () + { + + return this.fontSizeProp; + + } + + public void setFontSize (int v) + { + + this.fontSize = v; + this.fontSizeProp.setValue (v); + +/* +TODO Remove + if ((this.setOn != null) + && + (this.fontSize > 0) + ) + { + + this.setOn.setFontSize (v); + + } +*/ + } + + public String getAlignment () + { + + return this.alignment; + + } + + public StringProperty alignmentProperty () + { + + return this.alignmentProp; + + } + + public void setAlignment (String v) + { + + this.alignment = v; + this.alignmentProp.setValue (v); +/* +TODO Remove + if ((this.setOn != null) + && + (this.alignment != null) + ) + { + + this.setOn.setAlignment (v); + + } +*/ + } + + public boolean getFirstLineIndent () + { + + return this.firstLineIndent; + + } + + public BooleanProperty firstLineIndentProperty () + { + + return this.firstLineIndentProp; + + } + + public void setFirstLineIndent (boolean v) + { + + this.firstLineIndent = v; + this.firstLineIndentProp.setValue (v); + +/* +TODO Remove + if (this.setOn != null) + { + + this.setOn.setFirstLineIndent (v); + + } +*/ + } + + public float getLineSpacing () + { + + return this.lineSpacing; + + } + + public FloatProperty lineSpacingProperty () + { + + return this.lineSpacingProp; + + } + + public void setLineSpacing (float v) + { + + this.lineSpacing = v; + this.lineSpacingProp.setValue (v); +/* +TODO Remove + if ((this.setOn != null) + && + (this.lineSpacing > 0) + ) + { + + this.setOn.setLineSpacing (v); + + } +*/ + } + + public float getParagraphSpacing () + { + + return this.paragraphSpacingProp.getValue (); + + } + + public FloatProperty paragraphSpacingProperty () + { + + return this.paragraphSpacingProp; + + } + + public void setParagraphSpacing (float v) + { + + this.paragraphSpacingProp.setValue (v); + + } + + public Color getTextColor () + { + + return this.textColor; + + } + + public ObjectProperty textColorProperty () + { + + return this.textColorProp; + + } + + public void setTextColor (Color c) + { + + this.textColor = c; + this.textColorProp.setValue (c); +/* +TODO REmove + if ((this.setOn != null) + && + (this.textColor != null) + ) + { + + this.setOn.setTextColor (c); + + } +*/ + } + + public Color getBackgroundColor () + { + + return this.bgColor; + + } + + public ObjectProperty backgroundColorProperty () + { + + return this.bgColorProp; + + } + + public void setBackgroundColor (Color c) + { + + this.bgColor = c; + this.bgColorProp.setValue (c); + +/* +TODO Remove + if ((this.setOn != null) + && + (this.bgColor != null) + ) + { + + this.setOn.setBackgroundColor (c); + + } +*/ + } +/* + public void resetToDefaults () + { + + if (this.setOn != null) + { + + //this.setOn.resetToDefaults (); + + } + + } +*/ + public void unbindAll () + { + + this.fontFamilyProp.unbind (); + this.fontSizeProp.unbind (); + this.alignmentProp.unbind (); + this.firstLineIndentProp.unbind (); + this.lineSpacingProp.unbind (); + this.textColorProp.unbind (); + this.bgColorProp.unbind (); + this.writingLineColorProp.unbind (); + this.highlightWritingLineProp.unbind (); + this.textBorderProp.unbind (); + this.paragraphSpacingProp.unbind (); + + } + + /** + * Binds the properties in these properties to the properties in the passed in value. The bind is one way, "this" properties do not + * update the the passed in properties. + * + * So: this.lineSpacing gets its value from props.lineSpacing. + */ + public void bindTo (TextProperties props) + { + + this.unbindAll (); + this.fontFamilyProp.bind (props.fontFamilyProperty ()); + + this.fontFamilyProp.addListener ((pr, oldv, newv) -> + { + + this.fontFamily = newv; + + }); + + this.fontFamily = props.getFontFamily (); + + this.fontSizeProp.bind (props.fontSizeProperty ()); + + this.fontSizeProp.addListener ((pr, oldv, newv) -> + { + + this.fontSize = newv.intValue (); + + }); + + this.fontSize = props.getFontSize (); + + this.alignmentProp.bind (props.alignmentProperty ()); + + this.alignmentProp.addListener ((pr, oldv, newv) -> + { + + this.alignment = newv; + + }); + this.alignment = props.getAlignment (); + + this.firstLineIndentProp.bind (props.firstLineIndentProperty ()); + + this.firstLineIndentProp.addListener ((pr, oldv, newv) -> + { + + this.firstLineIndent = newv; + + }); + this.firstLineIndent = props.getFirstLineIndent (); + + this.lineSpacingProp.bind (props.lineSpacingProperty ()); + + this.lineSpacingProp.addListener ((pr, oldv, newv) -> + { + + this.lineSpacing = newv.floatValue (); + + }); + this.lineSpacing = props.getLineSpacing (); + + this.paragraphSpacingProp.bind (props.paragraphSpacingProperty ()); +/* + this.pargraphSpacingProp.addListener ((pr, oldv, newv) -> + { + + this.lineSpacing = newv.floatValue (); + + }); + this.lineSpacing = props.getLineSpacing (); +*/ + this.textColorProp.bind (props.textColorProperty ()); + + this.textColorProp.addListener ((pr, oldv, newv) -> + { + + this.textColor = newv; + + }); + this.textColor = props.getTextColor (); + + this.bgColorProp.bind (props.backgroundColorProperty ()); + + this.bgColorProp.addListener ((pr, oldv, newv) -> + { + + this.bgColor = newv; + + }); + this.bgColor = props.getBackgroundColor (); + + this.writingLineColorProp.bind (props.writingLineColorProperty ()); + + this.writingLineColorProp.addListener ((pr, oldv, newv) -> + { + + this.writingLineColor = newv; + + }); + this.writingLineColor = props.getWritingLineColor (); + + this.highlightWritingLineProp.bind (props.highlightWritingLineProperty ()); + + this.highlightWritingLineProp.addListener ((pr, oldv, newv) -> + { + + this.highlightWritingLine = newv; + + }); + this.highlightWritingLine = props.isHighlightWritingLine (); + + this.textBorderProp.bind (props.textBorderProperty ()); + + this.textBorderProp.addListener ((pr, oldv, newv) -> + { + + this.textBorder = newv.intValue (); + + }); + this.textBorder = props.getTextBorder (); + + } + +} diff --git a/src/main/java/com/quollwriter/ui/fx/TextPropertiesPanel.java b/src/main/java/com/quollwriter/ui/fx/TextPropertiesPanel.java new file mode 100644 index 00000000..1ca48548 --- /dev/null +++ b/src/main/java/com/quollwriter/ui/fx/TextPropertiesPanel.java @@ -0,0 +1,492 @@ +package com.quollwriter.ui.fx; + +import java.util.*; +import java.util.stream.*; + +import javafx.beans.value.*; +import javafx.scene.*; +import javafx.geometry.*; +import javafx.scene.layout.*; +import javafx.beans.property.*; +import javafx.scene.control.*; +import javafx.scene.text.*; +import javafx.util.*; +import javafx.collections.*; + +import com.quollwriter.*; +import com.quollwriter.data.IPropertyBinder; +import com.quollwriter.ui.fx.viewers.*; +import com.quollwriter.ui.fx.components.*; + +import static com.quollwriter.uistrings.UILanguageStringsManager.getUILanguageStringProperty; +import static com.quollwriter.LanguageStrings.*; + +public class TextPropertiesPanel extends VBox +{ + + private ComboBox font = null; + private Spinner fontSize = null; + private Slider fontSizeSlider = null; + private ChoiceBox alignment = null; + private Spinner lineSpacing = null; + private Slider lineSpacingSlider = null; + private Spinner paragraphSpacing = null; + private Slider paragraphSpacingSlider = null; + private Slider textBorderSlider = null; + private Spinner textBorder = null; + private CheckBox indentFirstLine = null; + private CheckBox highlightWritingLine = null; + + public TextPropertiesPanel (AbstractProjectViewer viewer, + TextProperties props, + StringProperty desc, + IPropertyBinder binder) + { + + this.managedProperty ().bind (this.visibleProperty ()); + + Form.Builder fb = Form.builder (); + + if (desc != null) + { + + fb.description (desc); + + } + + this.font = new ComboBox<> (); + this.font.getStyleClass ().add (StyleClassNames.FONTFAMILY); + this.font.setEditable (false); + Callback, ListCell> fact = lv -> + { + + return new ListCell () + { + + @Override + protected void updateItem (Font f, boolean empty) + { + + super.updateItem (f, empty); + + if (f == null) + { + + return; + + } + + this.setText (f.getName ()); + this.setFont (f); + + } + + }; + + }; + + viewer.schedule (() -> + { + + ObservableList fs = FXCollections.observableList (Font.getFamilies ().stream () + .map (n -> + { + + try + { + + Font f = Font.font (n); + + if (f == null) + { + + return null; + + } + + return f; + + } catch (Exception e) { + + return null; + + } + + }) + .filter (n -> n != null) + .collect (Collectors.toList ())); + + UIUtils.runLater (() -> + { + + this.font.setItems (fs); + + this.font.getSelectionModel ().select (Font.font (props.getFontFamily ())); + + this.font.getSelectionModel ().selectedItemProperty ().addListener ((pr, oldv, newv) -> + { + + props.setFontFamily (newv.getFamily ()); + + }); + + }); + + }, + -1, + -1); + + this.font.setButtonCell (fact.call (null)); + this.font.setCellFactory (fact); + + // Add the font item. + fb.item (getUILanguageStringProperty (project,LanguageStrings.sidebar,textproperties,LanguageStrings.font,text), + this.font); + + // Font size + HBox b = new HBox (); + b.getStyleClass ().add (StyleClassNames.FONTSIZE); + + int minFontSize = 8; + int maxFontSize = 50; + + this.fontSizeSlider = new Slider (minFontSize, maxFontSize, props.getFontSize ()); + this.fontSizeSlider.setBlockIncrement (1); + this.fontSizeSlider.setMajorTickUnit (1); + HBox.setHgrow (this.fontSizeSlider, + Priority.ALWAYS); + this.fontSize = new Spinner<> (new SpinnerValueFactory.IntegerSpinnerValueFactory (minFontSize, maxFontSize, props.getFontSize ())); + this.fontSize.setEditable (true); + this.fontSize.getStyleClass ().add ("arrows-on-right-vertical");//Spinner.STYLE_CLASS_ARROWS_ON_RIGHT_HORIZONTAL); + HBox.setHgrow (this.fontSize, + Priority.NEVER); + + this.fontSize.valueProperty ().addListener ((pr, oldv, newv) -> + { + + this.fontSizeSlider.setValue (newv.intValue ()); + props.setFontSize (newv.intValue ()); + + }); + + this.fontSizeSlider.valueProperty ().addListener ((pr, oldv, newv) -> + { + + this.fontSize.getValueFactory ().setValue (newv.intValue ()); + + }); + + b.getChildren ().addAll (this.fontSizeSlider, this.fontSize); + + // Add the font size. + fb.item (getUILanguageStringProperty (project,LanguageStrings.sidebar,textproperties,fontsize,text), + b); + + Set aitems = new LinkedHashSet<> (); + + aitems.add (getUILanguageStringProperty (textalignments,left)); + //QTextEditor.ALIGN_LEFT); + aitems.add (getUILanguageStringProperty (textalignments,justified)); + //QTextEditor.ALIGN_JUSTIFIED); + aitems.add (getUILanguageStringProperty (textalignments,right)); + + String al = props.getAlignment (); + + int selInd = 0; + + if (al.equals (TextEditor.ALIGN_JUSTIFIED)) + { + + selInd = 1; + + } + + if (al.equals (TextEditor.ALIGN_RIGHT)) + { + + selInd = 2; + + } + + this.alignment = QuollChoiceBox.builder () + .items (aitems) + .styleClassName ("alignment") + .selectedIndex (selInd) + .onSelected (ev -> + { + + QuollChoiceBox cb = (QuollChoiceBox) ev.getSource (); + + int v = cb.getSelectionModel ().getSelectedIndex (); + + if (v == 0) + { + + props.setAlignment (TextEditor.ALIGN_LEFT); + + } + + if (v == 1) + { + + props.setAlignment (TextEditor.ALIGN_JUSTIFIED); + + } + + if (v == 2) + { + + props.setAlignment (TextEditor.ALIGN_RIGHT); + + } + + }) + .build (); + + // Alignment. + fb.item (getUILanguageStringProperty (project,LanguageStrings.sidebar,textproperties,LanguageStrings.alignment,text), + this.alignment); + + // Line spacing. + b = new HBox (); + b.getStyleClass ().add (StyleClassNames.LINESPACING); + + double minLS = 0.5; + double maxLS = 2.5; + double stepBy = 0.1; + + this.lineSpacingSlider = new Slider (minLS, maxLS, props.getLineSpacing ()); + this.lineSpacingSlider.setBlockIncrement (1); + this.lineSpacingSlider.setMajorTickUnit (0.1f); + this.lineSpacingSlider.setMinorTickCount (0); + this.lineSpacingSlider.setSnapToTicks (true); + HBox.setHgrow (this.lineSpacingSlider, + Priority.ALWAYS); + this.lineSpacing = new Spinner<> (new SpinnerValueFactory.DoubleSpinnerValueFactory (minLS, maxLS, props.getLineSpacing (), stepBy)); + this.lineSpacing.setEditable (true); + this.lineSpacing.getStyleClass ().add (Spinner.STYLE_CLASS_ARROWS_ON_RIGHT_HORIZONTAL); + HBox.setHgrow (this.lineSpacing, + Priority.NEVER); + + this.lineSpacing.valueProperty ().addListener ((pr, oldv, newv) -> + { + + this.lineSpacingSlider.setValue (newv.doubleValue ()); + props.setLineSpacing (newv.floatValue ()); + + }); + + this.lineSpacingSlider.valueProperty ().addListener ((pr, oldv, newv) -> + { + + this.lineSpacing.getValueFactory ().setValue ((double) Math.round ((newv.doubleValue () * 10f)) / 10f); + + }); + + b.getChildren ().addAll (this.lineSpacingSlider, this.lineSpacing); + + // Add the line spacing. + fb.item (getUILanguageStringProperty (project,LanguageStrings.sidebar,textproperties,linespacing,text), + b); + + double minPS = 0; + double maxPS = 3.5; + double psStepBy = 0.1; + + // Paragraph spacing + this.paragraphSpacingSlider = new Slider (minPS, maxPS, props.getParagraphSpacing ()); + this.paragraphSpacingSlider.setBlockIncrement (1); + this.paragraphSpacingSlider.setMajorTickUnit (0.1f); + this.paragraphSpacingSlider.setMinorTickCount (0); + this.paragraphSpacingSlider.setSnapToTicks (true); + HBox.setHgrow (this.paragraphSpacingSlider, + Priority.ALWAYS); + this.paragraphSpacing = new Spinner<> (new SpinnerValueFactory.DoubleSpinnerValueFactory (minPS, maxPS, props.getParagraphSpacing (), psStepBy)); + this.paragraphSpacing.setEditable (true); + this.paragraphSpacing.getStyleClass ().add (Spinner.STYLE_CLASS_ARROWS_ON_RIGHT_HORIZONTAL); + HBox.setHgrow (this.paragraphSpacing, + Priority.NEVER); + + this.paragraphSpacing.valueProperty ().addListener ((pr, oldv, newv) -> + { + + this.paragraphSpacingSlider.setValue (newv.doubleValue ()); + props.setParagraphSpacing (newv.floatValue ()); + + }); + + this.paragraphSpacingSlider.valueProperty ().addListener ((pr, oldv, newv) -> + { + + this.paragraphSpacing.getValueFactory ().setValue ((double) Math.round ((newv.doubleValue () * 10f)) / 10f); + + }); + + b = new HBox (); + b.getStyleClass ().add (StyleClassNames.PARAGRAPHSPACING); + b.getChildren ().addAll (this.paragraphSpacingSlider, this.paragraphSpacing); + + // Add the line spacing. + fb.item (getUILanguageStringProperty (project,LanguageStrings.sidebar,textproperties,paragraphspacing,text), + b); + + // Text border. + b = new HBox (); + b.getStyleClass ().add (StyleClassNames.TEXTBORDER); + + int min = 0; + int max = 150; + int stepByW = 1; + + this.textBorderSlider = new Slider (min, max, props.getTextBorder ()); + this.textBorderSlider.setBlockIncrement (1); + this.textBorderSlider.setMajorTickUnit (1); + this.textBorderSlider.setMinorTickCount (0); + this.textBorderSlider.setSnapToTicks (true); + HBox.setHgrow (this.textBorderSlider, + Priority.ALWAYS); + + this.textBorder = new Spinner<> (new SpinnerValueFactory.IntegerSpinnerValueFactory (min, max, props.getTextBorder (), stepByW)); + this.textBorder.setEditable (true); + this.textBorder.getStyleClass ().add (Spinner.STYLE_CLASS_ARROWS_ON_RIGHT_HORIZONTAL); + HBox.setHgrow (this.textBorder, + Priority.NEVER); + + this.textBorder.valueProperty ().addListener ((pr, oldv, newv) -> + { + + this.textBorderSlider.setValue (newv.intValue ()); + props.setTextBorder (newv.intValue ()); + + }); + + this.textBorderSlider.valueProperty ().addListener ((pr, oldv, newv) -> + { + + this.textBorder.getValueFactory ().setValue (newv.intValue ()); + + }); + + b.getChildren ().addAll (this.textBorderSlider, this.textBorder); + + // Add the text border width. + fb.item (getUILanguageStringProperty (project,LanguageStrings.sidebar,textproperties,textborder,text), + b); + + this.indentFirstLine = QuollCheckBox.builder () + .label (getUILanguageStringProperty (project,LanguageStrings.sidebar,textproperties,indentfirstline,text)) + .selected (props.getFirstLineIndent ()) + .build (); + + this.indentFirstLine.selectedProperty ().addListener ((pr, oldv, newv) -> + { + + props.setFirstLineIndent (newv); + + }); + + // TODO fb.item (this.indentFirstLine); + + this.highlightWritingLine = QuollCheckBox.builder () + .label (getUILanguageStringProperty (project,LanguageStrings.sidebar,textproperties,highlightwritingline,text)) + .selected (props.isHighlightWritingLine ()) + .build (); + + this.highlightWritingLine.selectedProperty ().addListener ((pr, oldv, newv) -> + { + + props.setHighlightWritingLine (newv); + + }); + + ColorSelectorSwatch writingLineC = ColorSelectorSwatch.builder () + .inViewer (viewer) + .styleClassName ("writing-line-color-chooser") + .popupTitle (getUILanguageStringProperty (project,LanguageStrings.sidebar,textproperties,highlightlinecolor,popup,title)) + .initialColor (props.getWritingLineColor ()) + .onColorSelected (col -> + { + + props.setWritingLineColor (col); + + }) + .build (); + + binder.addChangeListener (writingLineC.colorProperty (), + (pr, oldv, newv) -> + { + + props.setWritingLineColor (newv); + + }); + + ColorSelectorSwatch textColorC = ColorSelectorSwatch.builder () + .inViewer (viewer) + .styleClassName ("text-color-chooser") + .popupTitle (getUILanguageStringProperty (project,LanguageStrings.sidebar,textproperties,textcolor,popup,title)) + .initialColor (props.getTextColor ()) + .onColorSelected (col -> + { + + props.setTextColor (col); + + }) + .build (); + + binder.addChangeListener (textColorC.colorProperty (), + (pr, oldv, newv) -> + { + + props.setTextColor (newv); + + }); + + ColorSelectorSwatch bgColorC = ColorSelectorSwatch.builder () + .inViewer (viewer) + .styleClassName ("bg-color-chooser") + .popupTitle (getUILanguageStringProperty (project,LanguageStrings.sidebar,textproperties,bgcolor,popup,title)) + .initialColor (props.getBackgroundColor ()) + .onColorSelected (col -> + { + + props.setBackgroundColor (col); + + }) + .build (); + + binder.addChangeListener (bgColorC.colorProperty (), + (pr, oldv, newv) -> + { + + props.setBackgroundColor (newv); + + }); + + binder.addChangeListener (Environment.nightModeProperty (), + (pr, oldv, newv) -> + { + + writingLineC.setColor (props.getWritingLineColor ()); + textColorC.setColor (props.getTextColor ()); + bgColorC.setColor (props.getBackgroundColor ()); + + }); + + fb.item (getUILanguageStringProperty (project,LanguageStrings.sidebar,textproperties,highlightlinecolor,text), + writingLineC); + + fb.item (this.highlightWritingLine); + + fb.item (getUILanguageStringProperty (project,LanguageStrings.sidebar,textproperties,textcolor,text), + textColorC); + + fb.item (getUILanguageStringProperty (project,LanguageStrings.sidebar,textproperties,bgcolor,text), + bgColorC); + + Form ff = fb.build (); + + this.getChildren ().add (ff); + + } + +} diff --git a/src/main/java/com/quollwriter/ui/fx/TextStylable.java b/src/main/java/com/quollwriter/ui/fx/TextStylable.java new file mode 100644 index 00000000..c0c88356 --- /dev/null +++ b/src/main/java/com/quollwriter/ui/fx/TextStylable.java @@ -0,0 +1,30 @@ +package com.quollwriter.ui.fx; + +import javafx.scene.paint.*; + +public interface TextStylable +{ + + public void setFontFamily (String f); + + public void setFontSize (int v); + + public void setAlignment (String v); + + public void setFirstLineIndent (boolean v); + + public void setLineSpacing (float v); + + public void setTextColor (Color c); + + public void setBackgroundColor (Color c); + + public void setWritingLineColor (Color c); + + public void setHighlightWritingLine (boolean v); + + public void setTextBorder (int v); + + //public void resetToDefaults (); + +} diff --git a/src/main/java/com/quollwriter/ui/fx/ToolBarSupported.java b/src/main/java/com/quollwriter/ui/fx/ToolBarSupported.java new file mode 100644 index 00000000..158e76e9 --- /dev/null +++ b/src/main/java/com/quollwriter/ui/fx/ToolBarSupported.java @@ -0,0 +1,32 @@ +package com.quollwriter.ui.fx; + +import java.util.*; +import javafx.scene.*; + +import com.quollwriter.ui.fx.components.*; + +public interface ToolBarSupported +{ + + default QuollToolBar getToolBar () + { + + return null; + + } + + default Set getToolBarItems () + { + + return new HashSet<> (); + + } + + default boolean isToolBarConfigurable () + { + + return false; + + } + +} diff --git a/src/main/java/com/quollwriter/ui/fx/TreeParentNode.java b/src/main/java/com/quollwriter/ui/fx/TreeParentNode.java new file mode 100644 index 00000000..93f8e91a --- /dev/null +++ b/src/main/java/com/quollwriter/ui/fx/TreeParentNode.java @@ -0,0 +1,125 @@ +package com.quollwriter.ui.fx; + +import java.util.*; + +import com.quollwriter.data.*; + +import org.dom4j.*; + +public class TreeParentNode extends NamedObject +{ + + public static final String OBJECT_TYPE = "treeparentnode"; + + private String forObjectType = null; + private int count = -1; + + public TreeParentNode (String objType, + String name) + { + + this (objType, + name, + -1); + + } + + public TreeParentNode(String objType, + String name, + int count) + { + + super (TreeParentNode.OBJECT_TYPE + "_" + objType); + + this.forObjectType = objType; + + this.setKey ((long) name.toLowerCase ().hashCode ()); + + this.setName (name); + + this.count = count; + + } + + public void setCount (int c) + { + + this.count = c; + + } + + public int getCount () + { + + return this.count; + + } + + @Override + public void getChanges (NamedObject old, + Element root) + { + + } + + public int hashCode () + { + + int hash = 7; + hash = (31 * hash) + this.forObjectType.hashCode (); + hash = (31 * hash) + this.getName ().toLowerCase ().hashCode (); + + return hash; + + } + + public String getForObjectType () + { + + return this.forObjectType; + + } + + @Override + public boolean equals (Object o) + { + + if ((o == null) || (!(o instanceof TreeParentNode))) + { + + + return false; + + } + + TreeParentNode n = (TreeParentNode) o; + + if ((n.getName ().equalsIgnoreCase (this.getName ())) && + (n.forObjectType.equals (this.forObjectType))) + { + + return true; + + } + + return false; + + } + + @Override + public String toString () + { + + return TreeParentNode.OBJECT_TYPE + "(for: " + this.forObjectType + ", type: " + this.getName () + ")"; + + } + + @Override + public Set getAllNamedChildObjects () + { + + return new HashSet (); + + } + +} diff --git a/src/main/java/com/quollwriter/ui/fx/UIUtils.java b/src/main/java/com/quollwriter/ui/fx/UIUtils.java new file mode 100644 index 00000000..f4375f24 --- /dev/null +++ b/src/main/java/com/quollwriter/ui/fx/UIUtils.java @@ -0,0 +1,5557 @@ +package com.quollwriter.ui.fx; + +import java.net.*; +import java.util.*; +import java.util.function.*; +import java.util.stream.*; +import java.io.*; +import java.nio.file.*; + +import java.awt.image.*; +//import java.awt.Desktop; + +import javafx.application.*; +import javafx.beans.property.*; +import javafx.beans.binding.*; +import javafx.scene.control.*; +import javafx.scene.image.*; +import javafx.scene.input.*; +import javafx.scene.*; +import javafx.scene.text.*; +import javafx.scene.layout.*; +import javafx.stage.*; +import javafx.geometry.*; +import javafx.scene.paint.*; +import javafx.embed.swing.*; +import javafx.scene.text.*; +import javafx.event.*; +import javafx.util.*; +import javafx.collections.*; +import javafx.css.*; + +import javax.imageio.*; + +import org.imgscalr.Scalr; + +import com.quollwriter.*; +import com.quollwriter.db.*; +import com.quollwriter.text.*; +import com.quollwriter.data.comparators.*; +import com.quollwriter.data.ChapterCounts; +import com.quollwriter.data.ReadabilityIndices; +import com.quollwriter.data.Prompt; +import com.quollwriter.data.ObjectReference; +import com.quollwriter.data.Project; +import com.quollwriter.data.ProjectInfo; +import com.quollwriter.data.Chapter; +import com.quollwriter.data.UserConfigurableObject; +import com.quollwriter.data.IPropertyBinder; +import com.quollwriter.data.Tag; +import com.quollwriter.data.NamedObject; +import com.quollwriter.data.UserConfigurableObjectType; +import com.quollwriter.data.Note; +import com.quollwriter.data.BlankNamedObject; +import com.quollwriter.data.Book; +import com.quollwriter.data.ChapterItem; +import com.quollwriter.data.Asset; +import com.quollwriter.data.NamedObjectNameWrapper; +import com.quollwriter.ui.fx.viewers.*; +import com.quollwriter.ui.fx.sidebars.*; +import com.quollwriter.ui.fx.components.*; +import com.quollwriter.ui.fx.popups.*; +import com.quollwriter.editors.*; +import com.quollwriter.editors.messages.*; +import com.quollwriter.uistrings.UILanguageStrings; +import com.quollwriter.uistrings.UILanguageStringsManager; +import com.quollwriter.uistrings.WebsiteLanguageStrings; +import com.quollwriter.uistrings.WebsiteLanguageStringsManager; + +import static com.quollwriter.uistrings.UILanguageStringsManager.getUILanguageStringProperty; +import static com.quollwriter.uistrings.UILanguageStringsManager.getUIString; +import static com.quollwriter.LanguageStrings.*; + +public class UIUtils +{ + + public static final String PROJECT_INFO_STATUS_TAG = "{s}"; + public static final String PROJECT_INFO_WORDS_TAG = "{wc}"; + public static final String PROJECT_INFO_CHAPTERS_TAG = "{ch}"; + public static final String PROJECT_INFO_LAST_EDITED_TAG = "{le}"; + public static final String PROJECT_INFO_EDIT_COMPLETE_TAG = "{ec}"; + public static final String PROJECT_INFO_READABILITY_TAG = "{r}"; + public static final String PROJECT_INFO_EDITOR_TAG = "{ed}"; + + public static final FileChooser.ExtensionFilter imageFileFilter = new FileChooser.ExtensionFilter ("Image files: jpg, png, gif", + "*.jpg", + "*.jpeg", + "*.gif", + "*.png"); + + public static Color hexToColor (String h) + { + + if (h == null) + { + + return null; + + } + + try + { + + return Color.web (h); + + } catch (Exception e) { + + return null; + + } + + } + + public static String colorToHex (Color c) + { + + return String.format( "#%02X%02X%02X", + (int)( c.getRed () * 255 ), + (int)( c.getGreen () * 255 ), + (int)( c.getBlue () * 255 ) ); + + } + + public static int getA4PageCountForChapter (Chapter chapter, + String text) + { + + // TODO + return -1; + + } + + /** + * Creates a wrapper around the passed in Runnable to ensure that it always runs on the event thread. + * + * @param r The runnable to run on the event thread. + * @return The runnable wrapper. + */ + public static Runnable createRunLater (Runnable r) + { + + Runnable _r = new Runnable () + { + + @Override + public void run () + { + + UIUtils.runLater (r); + + } + + }; + + return _r; + + } + + /** + * Force the runnable to run later on the fx thread. + */ + public static void forceRunLater (Runnable r) + { + + if (r == null) + { + + return; + + } + + Platform.runLater (() -> + { + + try + { + + r.run (); + + } catch (Exception e) { + + Environment.logError ("Unable to run: " + r, + e); + + } + + }); + + } + + /** + * Run the passed in Runnable on the event thread, if already on the event thread then run immediately. + * + * @param r The runnable to run. + */ + public static void runLater (Runnable r) + { + + if (r == null) + { + + return; + + } + + if (Platform.isFxApplicationThread ()) + { + + try + { + + r.run (); + + } catch (Exception e) { + + Environment.logError ("Unable to run: " + r, + e); + + } + + return; + + } + + UIUtils.forceRunLater (r); + + } + + public static TextFlow createTextFlowForHtml (StringProperty text) + { + + return BasicHtmlTextFlow.builder () + .text (text) + .build (); + + } + + public static Tooltip createTooltip (StringProperty text) + { + + Tooltip t = new Tooltip (); + + t.setContentDisplay (ContentDisplay.GRAPHIC_ONLY); + + t.setOnShowing (ev -> + { + + QuollTextView tf = QuollTextView.builder () + .text (text) + .build (); + t.setGraphic (tf); + + }); + + t.minWidthProperty ().bind (t.prefWidthProperty ()); + + return t; + + } + + public static Tooltip getTooltip (Node node) + { + + Object o = node.getProperties ().get ("tooltip"); + + if ((o != null) + && + (o instanceof Tooltip) + ) + { + + return (Tooltip) o; + + } + + if (node instanceof Control) + { + + return ((Control) node).getTooltip (); + + } + + return null; + + } + + /** + * Set a bound tooltip on the control using the uistring ids. + * + * @param control The control to set the tooltip on. + * @param ids The property to use as the source of the tooltip text. + * @return The tooltip, it will be set on the control. + */ + public static Tooltip setTooltip (Node node, + StringProperty prop) + { + + if (prop == null) + { + + Tooltip.uninstall (node, + (Tooltip) node.getProperties ().get ("tooltip")); + return null; + + } + + Tooltip t = new Tooltip (); + + t.setContentDisplay (ContentDisplay.GRAPHIC_ONLY); + + t.setOnShowing (ev -> + { + + QuollTextView tf = QuollTextView.builder () + .text (prop) + .build (); + /* + tf.setPrefWidth (300); + tf.setMinWidth (300); + tf.setMaxWidth (300); + */ + t.setGraphic (tf); + + }); + + node.getProperties ().put ("tooltip", t); + t.minWidthProperty ().bind (t.prefWidthProperty ()); + + Tooltip.install (node, + t); + + return t; + + } + + /** + * Create a button with bound text for the uistring ids. + * + * @param ids + * @return The button. + */ + public static Button createButton (String... ids) + { + + Button b = new Button (); + b.textProperty ().bind (Bindings.createStringBinding (() -> getUIString (ids), Environment.uilangProperty ())); + return b; + + } + + public static void openURL (AbstractViewer viewer, + String url) + { + + URL u = null; + + try + { + + u = new URL (url); + + UIUtils.openURL (viewer, + u, + null); + + } catch (Exception e) + { + + Environment.logError ("Unable to browse to: " + + url, + e); + + ComponentUtils.showErrorMessage (viewer, + getUILanguageStringProperty (Arrays.asList (general,unabletoopenwebpage), + url)); + //"Unable to open web page: " + url); + + return; + + } + + } + + public static void openURL (AbstractViewer viewer, + String url, + MouseEvent ev) + { + + if ("#".equals (url)) + { + + return; + + } + + URL u = null; + + try + { + + u = new URL (url); + + UIUtils.openURL (viewer, + u, + ev); + + } catch (Exception e) + { + + Environment.logError ("Unable to browse to: " + + url, + e); + + ComponentUtils.showErrorMessage (viewer, + getUILanguageStringProperty (Arrays.asList (general,unabletoopenwebpage), + url)); + //"Unable to open web page: " + url); + + return; + + } + + } + + public static void openURL (AbstractViewer viewer, + URL url, + MouseEvent ev) + throws Exception + { + + if ((viewer != null) + && + (viewer instanceof AbstractProjectViewer) + ) + { + + AbstractProjectViewer pv = (AbstractProjectViewer) viewer; + + if (url.getProtocol ().equals (Constants.OBJECTNAME_PROTOCOL)) + { + + String n = url.getHost (); + + try + { + + n = URLDecoder.decode (url.getHost (), "utf-8"); + + } catch (Exception e) { + + // Ignore. + + } + + Set objs = pv.getProject ().getAllNamedObjectsByName (n); + + if ((objs == null) + || + (objs.size () == 0) + ) + { + + return; + + } + + if (objs.size () == 1) + { + + pv.viewObject (objs.iterator ().next ()); + + return; + + } else { +// TODO Check this. + + Point2D p = viewer.screenToPopupLocal (ev.getScreenX (), + ev.getScreenY ()); + + ShowObjectSelectPopup.builder () + .withViewer (viewer) + .title (getUILanguageStringProperty (selectitem,popup,title)) + .styleClassName (StyleClassNames.OBJECTSELECT) + .headerIconClassName (StyleClassNames.VIEW) + .popupId ("showobject") + .objects (FXCollections.observableList (new ArrayList<> (objs))) + .cellProvider ((obj, popupContent) -> + { + + QuollLabel l = QuollLabel.builder () + .label (obj.nameProperty ()) + .styleClassName (obj.getObjectType ()) + .build (); + + UIUtils.setTooltip (l, + getUILanguageStringProperty (LanguageStrings.actions,clicktoview)); + + if (obj instanceof UserConfigurableObject) + { + + UserConfigurableObject uobj = (UserConfigurableObject) obj; + + ImageView iv = new ImageView (); + iv.imageProperty ().bind (uobj.getUserConfigurableObjectType ().icon16x16Property ()); + + l.setGraphic (iv); + + } + + l.setOnMouseClicked (eev -> + { + + if (eev.getButton () != MouseButton.PRIMARY) + { + + return; + + } + + pv.viewObject (obj); + + popupContent.close (); + + }); + + return l; + + }) + .build () + .show (p.getX (), + p.getY ()); + + } + + return; + + } + + if (url.getProtocol ().equals (Constants.OBJECTREF_PROTOCOL)) + { + + pv.viewObject (pv.getProject ().getObjectForReference (ObjectReference.parseObjectReference (url.getHost ()))); + + return; + + } + + } + + UIUtils.openURL ((URLActionHandler) viewer, + url); + + } + + public static void openURL (URLActionHandler handler, + URL url) + throws Exception + { + + if (url == null) + { + + return; + + } + + if (url.getProtocol ().equals (Constants.QUOLLWRITER_PROTOCOL)) + { + + String u = Environment.getQuollWriterWebsite (); + + String p = url.getPath (); + + if ((!p.endsWith (".html")) + && + // Only add if the url isn't of the form [name].html?parms + (p.indexOf (".html?") < 1) + && + // Only add if the url isn't of the form [name].html#id + (p.indexOf (".html#") < 1) + ) + { + + p += ".html"; + + } + + u = u + "/" + p; + + if (url.getQuery () != null) + { + + u += "?" + url.getQuery (); + + } + + if (url.getRef () != null) + { + + u += "#" + url.getRef (); + + } + + try + { + + url = new URL (u); + + } catch (Exception e) + { + + throw new GeneralException ("Unable to open url: " + + u, + e); + + } + + } + + if (url.getProtocol ().equals (Constants.HELP_PROTOCOL)) + { + + // Prefix it with the website. + String u = Environment.getQuollWriterWebsite (); + + String p = url.getPath (); + + if (p.indexOf (".html") < 0) + { + + p += ".html"; + + } + + u = u + "/user-guide/" + url.getHost () + p; + + if (url.getRef () != null) + { + + u += "#" + url.getRef (); + + } + + try + { + + url = new URL (u); + + } catch (Exception e) + { + + throw new GeneralException ("Unable to open url: " + + u, + e); + + } + + if (Environment.getFocusedViewer () != null) + { + + Environment.fireUserProjectEvent (new ProjectEvent (Environment.getFocusedViewer (), + ProjectEvent.Type.help, + ProjectEvent.Action.show)); + + } + + } + + if (url.getProtocol ().equals (Constants.OPENPROJECT_PROTOCOL)) + { + + String projId = url.getPath (); + + Project proj = null; + + try + { + + Environment.openProject (projId, + null, + null); + + } catch (Exception e) { + + throw new GeneralException ("Unable to get project for id: " + projId, + e); + + } + + return; + + } + + if (url.getProtocol ().equals (Constants.OPENEDITORMESSAGE_PROTOCOL)) + { + + int key = 0; + + try + { + + key = Integer.parseInt (url.getPath ()); + + } catch (Exception e) { + + // Ignore? + + } + + // Get the message. + EditorMessage mess = null; + + try + { + + mess = EditorsEnvironment.getMessageByKey (key); + + } catch (Exception e) { + + throw new GeneralException ("Unable to get message for key: " + key, + e); + + } + + if (mess != null) + { + + // Need to work out what to do. + // TODO? + //EditorsEnvironment.openEditorMessage (mess); + + } + + return; + + } + + if (url.getProtocol ().equals (Constants.ACTION_PROTOCOL)) + { + + String action = url.getPath (); + + if (handler != null) + { + + StringTokenizer t = new StringTokenizer (action, + ",;"); + + while (t.hasMoreTokens ()) + { + + handler.handleURLAction (t.nextToken ().trim (), + null); + + } + + return; + + } + + } + + if (url.getProtocol ().equals ("mailto")) + { + + return; + + } + + if (url.getProtocol ().equals ("file")) + { + + Environment.openURL (url); + + //Desktop.getDesktop ().browse (url.toURI ()); + + return; + + } + + try { + //URI uri = new URI(url.getProtocol(), url.getHost(), url.getPath(), url.getQuery(), url.getRef ()); + + Environment.openURL (url); + //Desktop.getDesktop ().browse (uri); + + } catch (Exception e) { + + // Handle? + } + + } + + public static AbstractViewer getViewer (Node parent) + { + + if (parent == null) + { + + return null; + + } + + if (parent instanceof AbstractViewer) + { + + return (AbstractViewer) parent; + + } + + return UIUtils.getViewer (parent.getParent ()); + + } + + public static Button createHelpPageButton (AbstractViewer viewer, + String helpPage, + StringProperty tooltip) + { + + QuollButton b = QuollButton.builder () + .iconName (StyleClassNames.HELP) + .tooltip (tooltip != null ? tooltip : getUILanguageStringProperty (help,button,LanguageStrings.tooltip)) + .onAction (ev -> + { + + UIUtils.openURL (viewer, + "help://" + helpPage); + + }) + .build (); + + return b; + + } + + public static String getQuollWriterHelpLink (String url, + String linkText) + { + + if (linkText == null) + { + + return String.format ("%s:%s", + Constants.HELP_PROTOCOL, + url); + + } + + return String.format ("%s", + Constants.HELP_PROTOCOL, + url, + linkText); + + } + + public static void showFile (AbstractViewer parent, + Path f) + { + + if ((f == null) + || + (Files.notExists (f)) + ) + { + + return; + + } + + try + { + + Desktop.open (f.toFile ()); + + } catch (Exception e) + { + + Environment.logError ("Unable to open: " + + f, + e); + + ComponentUtils.showErrorMessage (parent, + getUILanguageStringProperty (Arrays.asList (general,unabletoopenfile), + f.toString ())); + //"Unable to open: " + f); + + return; + + } + + } + + public static Image getImage (Path p) + throws IOException + { + + if (p == null) + { + + return null; + + } + + return new Image (Files.newInputStream (p)); + + } + + public static Image getImage (byte[] bytes) + throws GeneralException + { + + if (bytes == null) + { + + return null; + + } + + try + { + + return SwingFXUtils.toFXImage (ImageIO.read (new ByteArrayInputStream (bytes)), + null); + + } catch (Exception e) { + + throw new GeneralException ("Unable to convert bytes to an image", + e); + + } + + } + + public static byte[] getImageBytes (Image im) + throws GeneralException + { + + if (im == null) + { + + return null; + + } + + try + { + + BufferedImage bim = new BufferedImage ((int) im.getWidth (), + (int) im.getHeight (), + BufferedImage.TYPE_INT_ARGB_PRE); + + SwingFXUtils.fromFXImage (im, + bim); + + ByteArrayOutputStream bout = new ByteArrayOutputStream (); + + // Shouldn't use png here, it is too slow. + if (!ImageIO.write (bim, + "png", + bout)) + { + + throw new GeneralException ("Unable to write image using png"); + + } + + bout.flush (); + bout.close (); + return bout.toByteArray (); + + } catch (Exception e) { + + throw new GeneralException ("Unable to get bytes for image", + e); + + } + + } + + public static BufferedImage getScaledImage (BufferedImage img, + int targetWidth) + { + + if (img == null) + { + + return null; + + } + + img = Scalr.resize (img, + Scalr.Method.QUALITY, + Scalr.Mode.FIT_TO_WIDTH, + targetWidth, + Scalr.OP_ANTIALIAS); + + return img; + + } + + public static Image getScaledImage (Image img, + int targetWidth) + { + + if (img == null) + { + + return null; + + } + + // TODO Redo to stop using BufferedImage. + BufferedImage bim = new BufferedImage ((int) img.getWidth (), + (int) img.getHeight (), + BufferedImage.TYPE_INT_ARGB_PRE); + + BufferedImage bi = SwingFXUtils.fromFXImage (img, + bim); + + bi = Scalr.resize (bi, + Scalr.Method.QUALITY, + Scalr.Mode.FIT_TO_WIDTH, + targetWidth, + Scalr.OP_ANTIALIAS); + + return SwingFXUtils.toFXImage (bi, null); + + } + + public static WritableImage getImageOfNode (Node n) + { + + SnapshotParameters parms = new SnapshotParameters (); +/* + double w = n.getWidth (); + + if (w < 0) + { + + w = n.prefWidth (-1); + + } + + double h = n.getHeight (); + + if (h < 0) + { + + h = n.prefHeight (w); + + } +*/ + WritableImage im = new WritableImage ((int) n.boundsInParentProperty ().getValue ().getWidth (), (int) n.boundsInParentProperty ().getValue ().getHeight ()); + + return n.snapshot (parms, + im); + + } + + public static void addDoOnReturnPressed (TextField f, + Runnable r) + { + + f.addEventHandler (KeyEvent.KEY_PRESSED, + ev -> + { + + if (ev.getCode () == KeyCode.ENTER) + { + + r.run (); + + } + + }); + + } + + public static void addDoOnReturnPressed (TextArea f, + Runnable r) + { + + f.addEventHandler (KeyEvent.KEY_PRESSED, + ev -> + { + + if ((ev.getCode () == KeyCode.ENTER) + && + (ev.isShortcutDown ()) + ) + { + + r.run (); + + } + + }); + + } + + public static void addDoOnReturnPressed (QuollTextArea f, + Runnable r) + { + + f.getTextEditor ().addEventHandler (KeyEvent.KEY_PRESSED, + ev -> + { + + if ((ev.getCode () == KeyCode.ENTER) + && + (ev.isShortcutDown ()) + ) + { + + r.run (); + + } + + }); + + } + + public static void scrollIntoView (Node node, + VPos pos) + { + + if (node == null) + { + + return; + + } + + Parent p = node.getParent (); + + while (p != null) + { + + if (p instanceof ScrollPane) + { + + break; + + } + + p = p.getParent (); + + } + + if (p == null) + { + + return; + + } + + UIUtils.scrollIntoView ((ScrollPane) p, + node, + pos); + + } + + public static Bounds getBoundsInParent (Node parent, + Node node, + Bounds b) + { + + Node p = node.getParent (); + + b = node.localToParent (b); + + while (p != parent) + { + + if (p == null) + { + + return b; + + } + + b = p.localToParent (b); + p = p.getParent (); + + } + + return b; + + } + + public static Bounds getBoundsInParent (Node parent, + Node node) + { + + Node p = node.getParent (); + Bounds b = node.getBoundsInParent (); + + while (p != parent) + { + + if (p == null) + { + + return b; + + } + + b = p.localToParent (b); + p = p.getParent (); + + } + + return b; + + } + + public static void scrollIntoView (ScrollPane pane, + Node node, + VPos pos) + { + + ScrollPane scrollPane = pane; + + Bounds nb = UIUtils.getBoundsInParent (pane.getContent (), + node); + + Bounds vb = scrollPane.getBoundsInLocal (); + Bounds _nb = UIUtils.getBoundsInParent (pane, + node); + + if (vb.contains (_nb)) + { + + return; + + } + + if (pos == null) + { + + pos = VPos.CENTER; + + } + + double heightViewPort = scrollPane.getViewportBounds().getHeight(); + double heightScrollPane = scrollPane.getContent().getBoundsInLocal().getHeight(); + + // Node is below or partially below the viewport bounds. + if (_nb.getMaxY () > vb.getMaxY ()) + { + + // Move it up to be visible. + double diff = _nb.getMaxY () - vb.getMaxY (); + double vh = 0; + + if (pos == VPos.TOP) + { + + vh = heightViewPort; + diff = vh - (_nb.getHeight () - diff); + + } + + if (pos == VPos.CENTER) + { + + vh = heightViewPort / 2; + diff = vh + ((_nb.getHeight () / 2) - (_nb.getHeight () - diff)); + + } + + if (pos == VPos.BOTTOM) + { + + //diff = + + } + + //diff = vh + diff; + //diff -= vh; + + scrollPane.setVvalue (scrollPane.getVvalue () + ((diff / (heightScrollPane - heightViewPort)))); + return; + } + + if (_nb.getMinY () < vb.getMinY ()) + { + + // Move it up to be visible. + double diff = _nb.getMinY () - vb.getMinY (); + scrollPane.setVvalue (scrollPane.getVvalue () + (diff / (heightScrollPane - heightViewPort))); + return; + } + + if (pos == VPos.TOP) + { + + } + + + //scrollPane.setVvalue (scrollPane.getVvalue () + ((diff / (heightScrollPane - heightViewPort)))); + + + double y = UIUtils.getBoundsInParent (pane.getContent (), + node).getMaxY (); + +/* + if (pos == VPos.TOP) + { + + scrollPane.setVvalue ((y - heightViewPort) / (heightScrollPane-heightViewPort)); + System.out.println ("SV: " + scrollPane.getVvalue ()); + scrollPane.setVvalue (y / heightScrollPane); + return; + } +*/ + if (y<(heightViewPort/2)) { + scrollPane.setVvalue(0); + // below 0 of scrollpane + + }else if ((y>=(heightViewPort/2))&(y<=(heightScrollPane-heightViewPort/2))) { + // between 0 and 1 of scrollpane + scrollPane.setVvalue((y-(heightViewPort/2))/(heightScrollPane-heightViewPort)); + } + else if(y>= (heightScrollPane-(heightViewPort/2))){ + // above 1 of scrollpane + scrollPane.setVvalue(1); + + } +/* + double contentHeight = pane.getContent ().localToScene (pane.getContent ().getBoundsInLocal ()).getHeight (); + double nodeMinY = node.localToScene (node.getBoundsInLocal ()).getMinY (); + double nodeMaxY = node.localToScene (node.getBoundsInLocal ()).getMaxY (); + + pane.setVvalue (nodeMaxY / contentHeight); +*/ + } + + public static void toggleSelected (Parent parent, + Node node) + { + + if (node == null) + { + + return; + + } + + boolean v = UIUtils.isSelected (node); + + UIUtils.unselectChildren (parent); + + node.pseudoClassStateChanged (StyleClassNames.SELECTED_PSEUDO_CLASS, !v); + + } + + public static void unselectChildren (Parent parent) + { + + parent.getChildrenUnmodifiable ().stream () + // Switch off the selected class for all elements. + .forEach (c -> c.pseudoClassStateChanged (StyleClassNames.SELECTED_PSEUDO_CLASS, false)); + + } + + public static boolean isSelected (Node node) + { + + return node.getPseudoClassStates ().contains (StyleClassNames.SELECTED_PSEUDO_CLASS); + + } + + public static void setSelected (Parent parent, + Object userData) + { + + parent.getChildrenUnmodifiable ().stream () + .forEach (c -> + { + + c.pseudoClassStateChanged (StyleClassNames.SELECTED_PSEUDO_CLASS, false); + + if (c.getUserData ().equals (userData)) + { + + c.pseudoClassStateChanged (StyleClassNames.SELECTED_PSEUDO_CLASS, true); + + } + + }); + + } + + public static List getSelected (Parent parent) + { + + return parent.getChildrenUnmodifiable ().stream () + .filter (c -> c.getPseudoClassStates ().contains (StyleClassNames.SELECTED_PSEUDO_CLASS)) + .collect (Collectors.toList ()); + + } + + public static HBox createButtonBar (Set